如何在GPX文件解析中提取ele字段对应的海拔数据
GPX 解析中提取点位海拔值的实现方法
现有开发基础
当前应用已实现GPX文件导入能力,原有解析逻辑可正常提取文件内的经纬度坐标,完成地图上的轨迹渲染展示。待解决的问题为:GPX文件中<ele>标签承载的海拔数据,无法和对应点位绑定提取、存储。
参考GPX文件片段
实际使用的GPX点位存储结构如下:
<trkseg> <trkpt lat="51.47777000000001" lon="-0.9179800000000001"> <ele>35.85</ele> </trkpt> <trkpt lat="51.47795000000001" lon="-0.9184300000000001"> <ele>35.85</ele> </trkpt> </trkseg>
原有解析逻辑
当前仅在XMLParser的开始节点代理中处理经纬度提取,对应代码如下:
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { if elementName == "trkpt" || elementName == "wpt" || elementName == "rtept" { let lat = Double(attributeDict["lat"]!) let lon = Double(attributeDict["lon"]!) let coordinateData = CLLocationCoordinate2D(latitude: lat!, longitude: lon!) coordinates.append(coordinateData) } }
核心实现思路
XMLParser是事件驱动的逐节点回调机制,<ele>是点位标签内部的子元素,其数值为标签夹的纯文本内容,无法在开始节点的回调中直接拿到。需要通过临时状态标记,完成点位坐标和对应海拔的绑定,避免数据错位。
具体改造步骤
- 替换单一的纯坐标数组,采用结构化数据绑定坐标与海拔
原有仅存储CLLocationCoordinate2D的数组无法承载海拔信息,需定义对应数据模型,同时新增解析过程中需要的临时状态变量:// 结构化存储GPX点位 struct GPXTrackPoint { let coordinate: CLLocationCoordinate2D let elevation: Double? // 对应ele字段值,无海拔时为nil } // 全局存储数组,替换原有coordinates var trackPoints: [GPXTrackPoint] = [] // 解析临时状态变量 var currentLat: Double? var currentLon: Double? var pendingElevation: Double? var currentElevationText: String? var isInsideTrackPoint = false - 修改开始节点回调逻辑,识别点位上下文与ele标签
遇到点位标签时重置临时变量、读取当前经纬度;遇到ele标签时,标记准备读取后续的文本内容:func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { switch elementName { case "trkpt", "wpt", "rtept": // 进入点位节点,重置解析状态 isInsideTrackPoint = true currentLat = Double(attributeDict["lat"] ?? "") currentLon = Double(attributeDict["lon"] ?? "") currentElevationText = nil pendingElevation = nil case "ele": // 仅在点位内部时,才准备读取海拔文本 guard isInsideTrackPoint else { return } currentElevationText = "" default: break } } - 实现文本读取回调,获取ele标签的数值内容
通过foundCharacters代理方法拼接ele标签内部的文本内容:func parser(_ parser: XMLParser, foundCharacters string: String) { // 非ele标签上下文的文本直接忽略 guard currentElevationText != nil else { return } currentElevationText?.append(string) } - 修改结束节点回调逻辑,完成数据组装与存储
读取完ele标签时,将拼接的文本转为海拔数值暂存;点位标签闭合时,将坐标与暂存的海拔组装为完整点位存入数组,同时重置临时状态准备解析下一个点位:func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { switch elementName { case "ele": guard isInsideTrackPoint, let rawText = currentElevationText else { currentElevationText = nil return } // 清理文本前后的空白、换行后转成数值 let cleanText = rawText.trimmingCharacters(in: .whitespacesAndNewlines) pendingElevation = Double(cleanText) currentElevationText = nil case "trkpt", "wpt", "rtept": guard isInsideTrackPoint, let lat = currentLat, let lon = currentLon else { resetParsingState() return } // 组装完整点位 let coordinate = CLLocationCoordinate2D(latitude: lat, longitude: lon) let point = GPXTrackPoint(coordinate: coordinate, elevation: pendingElevation) trackPoints.append(point) resetParsingState() default: break } } // 复用状态重置逻辑 func resetParsingState() { isInsideTrackPoint = false currentLat = nil currentLon = nil pendingElevation = nil currentElevationText = nil }
注意事项
- 原有代码中对lat/lon的强制解包存在崩溃风险,需改为可选绑定,适配格式不标准的GPX文件。
- 不要在读取到ele标签时直接绑定到全局最后一个点位,复杂嵌套结构下容易出现数据错位,必须通过上下文标记保证海拔和点位的对应关系。
- ele文本转数值前需清理空白字符,避免因文本自带的换行、空格导致转换失败。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

