GPX(GPS eXchange Format咕幻,GPS交換格式)是一個XML格式,為應(yīng)用軟件設(shè)計的通用GPS數(shù)據(jù)格式翰绊,專門用來存儲地理信息箭养。
一個GPX文件當(dāng)中可能包含一些路點(waypoint)及一些軌跡點(trackpoint)。 以全球定位系統(tǒng)(GPS設(shè)備)所產(chǎn)生的GPX檔為例偶宫, 路點可能是各自獨立互不相干的重要標(biāo)記點非迹, 例如照相的地點或用戶手動標(biāo)記的休息站或路口等等;至于GPS設(shè)備自動定時記錄的則是軌跡點纯趋。 有順序的一串軌跡點構(gòu)成一個軌跡(track)或者路程(route)憎兽。軌跡是一個人曾經(jīng)走過的記錄,可能包含走錯的路等等吵冒;路程則經(jīng)常是建議未來用路人可以走的路徑纯命。所以,一般來講痹栖,軌跡里的點扎附,包含時間信息,路程里的點结耀,則沒有時間信息留夜。點擊查看GPX文件內(nèi)容示例
1、在iOS開發(fā)當(dāng)中图甜,可以通過Xcode創(chuàng)建一個GPX文件碍粥,如圖:
2嚼摩、可以從其他地方下載GPX文件放進項目工程使用。
這種方法可以用來給模擬器虛擬定位測試使用矿瘦。Xcode模擬器可以指定當(dāng)前Location來機進行地理位置測試枕面。
然后就可以在模擬器選項里面選擇所需要的GPX文件信息。
這里有一篇釘釘模擬器模擬打卡定位的文章
3易结、下面來說說代碼創(chuàng)建GPX文件的做法枕荞。
既然GPX就是一個XML的話,那創(chuàng)建GPX就是創(chuàng)建XML搞动,說道代碼創(chuàng)建XML文件的話躏精,iOS上可以搜出幾個常用的庫,具體就不詳細說了鹦肿,這里只結(jié)合項目需求來說說自己功能需求對應(yīng)的GPX文件生成與讀取矗烛。
iOS SDK 提供了兩個xml框架。
NSXMLParser
:它是基于objective-c語言的sax解析框架箩溃,是iOS SDK默認(rèn)的xml解析框架瞭吃,不支持dom模式碌识。
libxml2
: 它是基于c語言的xml解析器,被蘋果整合在iOS SDK中虱而,支持sax和dom模式筏餐。
第三方xml解析框架
tbxml
:它是輕量級的dom模式解析庫,不支持xml文檔驗證和xpath,只能讀取xml文檔牡拇,不能寫xml文檔魁瞪。
touchxml
:它是基于dom模式的解析庫,與 tbxml類似惠呼,只能讀取xml文檔导俘,不能寫xml文檔。
KissXML
:它是基于dom模式的解析庫剔蹋,基于touchxml,主要的不同是可以寫入xml文檔旅薄。
Gdataxml
:它是基于dom模式的解析庫,由google開發(fā)泣崩,可以讀寫xml文檔少梁,支持xpath查詢。
項目里面我使用的是KissXML來進行數(shù)據(jù)的生成與解析矫付。
項目需求是記錄一段運動軌跡凯沪,記錄下每個定位點的數(shù)據(jù)信息,包括“經(jīng)緯度”买优、“海拔”妨马、“距離”、“速度”杀赢、“時間”等相關(guān)軌跡信息烘跺,用來在地圖控件上繪制一條運動軌跡線條。所以在獲取定位點信息之后脂崔,必須把數(shù)據(jù)寫入GPX文件滤淳,上傳到服務(wù)器保存起來⊥迅荩看下最終生成的GPX定位信息文件:
這個XML根節(jié)點為gpx娇钱,wpt為gpx的子節(jié)點,在wpt子節(jié)點的下面就是包含location的定位信息伤柄,n個wpt子節(jié)點定位信息組成了一個完整的GPX文件绊困。(gpx、wpt等是自己的命名)
所以采用
KissXML
來生成的話适刀,就如下面代碼示例:
- (NSString *)writeXmlDocumentCallbackPath:(YTTrackRoute *)trackRoute
{
//gpx(root根)
DDXMLElement *gpxElement = [[DDXMLElement alloc]initWithName:@"gpx"];
DDXMLNode *gpxUserID = [DDXMLNode attributeWithName:@"userid" stringValue:[[DataManagerObject shareDataManagerObject] getWildtoID]];
[gpxElement addAttribute:gpxUserID];
DDXMLNode *gpxUserName = [DDXMLNode attributeWithName:@"nickname" stringValue:[[DataManagerObject shareDataManagerObject] getUserNickName]];
[gpxElement addAttribute:gpxUserName];
DDXMLNode *gpxDevice = [DDXMLNode attributeWithName:@"device" stringValue:[UIDevice machineModelName]];
[gpxElement addAttribute:gpxDevice];
DDXMLNode *gpxVersion = [DDXMLNode attributeWithName:@"appversion" stringValue:YTAPPVersion];
[gpxElement addAttribute:gpxVersion];
DDXMLNode *gpxChannel = [DDXMLNode attributeWithName:@"channel" stringValue:@"wildto"];
[gpxElement addAttribute:gpxChannel];
DDXMLNode *gpxClient = [DDXMLNode attributeWithName:@"client" stringValue:YT_IOS_DEVICE];
[gpxElement addAttribute:gpxClient];
NSArray *points = trackRoute.route_points;
for (NSInteger i = 0; i < points.count; i ++) {
@autoreleasepool {
YTRoutePoint *point = points[i];
//wpt元素(包含經(jīng)緯度兩個屬性)
DDXMLElement *wptElement = [[DDXMLElement alloc]initWithName:@"wpt"];
DDXMLNode *wptLonAtt = [DDXMLNode attributeWithName:@"lon" stringValue:[NSString stringWithFormat:@"%f",point.lon]];
[wptElement addAttribute:wptLonAtt];
DDXMLNode *wptLatAtt = [DDXMLNode attributeWithName:@"lat" stringValue:[NSString stringWithFormat:@"%f",point.lat]];
[wptElement addAttribute:wptLatAtt];
//速度
DDXMLElement *speedElement = [[DDXMLElement alloc]initWithName:@"speed" stringValue:[NSString stringWithFormat:@"%f",point.speed]];
[wptElement addChild:speedElement];
//海拔
DDXMLElement *altudeElement = [[DDXMLElement alloc]initWithName:@"level" stringValue:[NSString stringWithFormat:@"%f",point.altude]];
[wptElement addChild:altudeElement];
//時間點(時間戳)
DDXMLElement *creatTimeElement = [[DDXMLElement alloc]initWithName:@"time" stringValue:[NSString stringWithFormat:@"%ld",(long)point.create_time]];
[wptElement addChild:creatTimeElement];
//坡度
DDXMLElement *slopeElement = [[DDXMLElement alloc]initWithName:@"slope" stringValue:[NSString stringWithFormat:@"%f",point.slope]];
[wptElement addChild:slopeElement];
//當(dāng)前點經(jīng)過的總距離
DDXMLElement *distacneElement = [[DDXMLElement alloc]initWithName:@"distacne" stringValue:[NSString stringWithFormat:@"%.1f",point.distance]];
[wptElement addChild:distacneElement];
[gpxElement addChild:wptElement];
}
}
NSString *xmlString = [@"<?xml version=\"1.0\"?>" stringByAppendingString:[gpxElement XMLString]];
// DLog(@"xmlString %@",xmlString);
DDXMLDocument *xmlDocument = [[DDXMLDocument alloc]initWithXMLString:xmlString options:0 error:nil];
NSString *path = [NSString stringWithFormat:@"%@/%@.gpx",[self userFolderPath],trackRoute.route_app_id];
DLog(@"路勁 == %@",path);
NSString *result = [NSString stringWithFormat:@"%@",xmlDocument];
BOOL writed = [result writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
if (writed) {
return path;
}
return nil;
}
有生成就有讀取秤朗,下面是讀取的代碼示例:
- (NSArray *)readGPXFileToPoints:(NSString *)filePath route_app_id:(NSString *)route_app_id
{
//轉(zhuǎn)成XML字符串
NSString *xmlString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
DDXMLDocument *xmlDoc = [[DDXMLDocument alloc]initWithXMLString:xmlString options:0 error:nil];
//開始解析
NSArray *children = [xmlDoc nodesForXPath:@"gpx/wpt" error:nil];
NSMutableArray *points = [NSMutableArray arrayWithCapacity:children.count];
//遍歷每個元素
YTRoutePoint *prevPoint = nil;
for (DDXMLElement *child in children) {
@autoreleasepool {
NSString *lat =[[child attributeForName:@"lat"] stringValue];
NSString *lon =[[child attributeForName:@"lon"] stringValue];
DDXMLElement *speedEle = [child elementForName:@"speed"];
DDXMLElement *timeEle = [child elementForName:@"time"];
DDXMLElement *distacneEle = [child elementForName:@"distacne"];
DDXMLElement *levelEle = [child elementForName:@"level"];
DDXMLElement *slopeEle = [child elementForName:@"slope"];
YTRoutePoint *point = [[YTRoutePoint alloc]init];
point.route_app_id = route_app_id;
point.lon = [lon doubleValue];
point.lat = [lat doubleValue];
point.speed = [[speedEle stringValue] doubleValue];
point.altude = [[levelEle stringValue] doubleValue];
point.distance = [[distacneEle stringValue] doubleValue];
point.slope = [[slopeEle stringValue] doubleValue];
point.create_time = [[timeEle stringValue] integerValue];
//去重
if(!prevPoint) {
[points addObject:point];
prevPoint = point;
}
else {
if(prevPoint.lat == point.lat && prevPoint.lon == point.lon) {
continue;
}
[points addObject:point];
prevPoint = point;
}
}
}
return [NSArray arrayWithArray:points];
}