GPX(GPS eXchange Format,GPS交换格式)是一个XML格式,为应用软件设计的通用GPS数据格式,专门用来存储地理信息。
一个GPX文件当中可能包含一些路点(waypoint)及一些轨迹点(trackpoint)。 以全球定位系统(GPS设备)所产生的GPX档为例, 路点可能是各自独立互不相干的重要标记点, 例如照相的地点或用户手动标记的休息站或路口等等;至于GPS设备自动定时记录的则是轨迹点。 有顺序的一串轨迹点构成一个轨迹(track)或者路程(route)。轨迹是一个人曾经走过的记录,可能包含走错的路等等;路程则经常是建议未来用路人可以走的路径。所以,一般来讲,轨迹里的点,包含时间信息,路程里的点,则没有时间信息。点击查看GPX文件内容示例
1、在iOS开发当中,可以通过Xcode创建一个GPX文件,如图:


2、可以从其他地方下载GPX文件放进项目工程使用。
这种方法可以用来给模拟器虚拟定位测试使用。Xcode模拟器可以指定当前Location来机进行地理位置测试。

然后就可以在模拟器选项里面选择所需要的GPX文件信息。
这里有一篇钉钉模拟器模拟打卡定位的文章
3、下面来说说代码创建GPX文件的做法。
既然GPX就是一个XML的话,那创建GPX就是创建XML,说道代码创建XML文件的话,iOS上可以搜出几个常用的库,具体就不详细说了,这里只结合项目需求来说说自己功能需求对应的GPX文件生成与读取。
iOS SDK 提供了两个xml框架。
NSXMLParser:它是基于objective-c语言的sax解析框架,是iOS SDK默认的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开发,可以读写xml文档,支持xpath查询。
项目里面我使用的是KissXML来进行数据的生成与解析。
项目需求是记录一段运动轨迹,记录下每个定位点的数据信息,包括“经纬度”、“海拔”、“距离”、“速度”、“时间”等相关轨迹信息,用来在地图控件上绘制一条运动轨迹线条。所以在获取定位点信息之后,必须把数据写入GPX文件,上传到服务器保存起来。看下最终生成的GPX定位信息文件:


这个XML根节点为gpx,wpt为gpx的子节点,在wpt子节点的下面就是包含location的定位信息,n个wpt子节点定位信息组成了一个完整的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元素(包含经纬度两个属性)
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];
//当前点经过的总距离
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
{
//转成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];
}