Swift中XML解析问题:GPX文件解析时无描述解析错误
解析GPX文件遇到的问题排查与修复
首先,我帮你梳理了代码里的几个核心问题,这些问题不仅会导致解析结果不符合预期,也可能让你误以为出现了解析错误(虽然parserError显示nil,但实际是逻辑错误导致数据异常):
1. 全局变量导致的实例复用问题
你把wpt、gpx、foundCharacters都定义成了全局变量,这会导致每次解析<wpt>元素时,都是修改同一个Wpt实例,最终数组里的所有元素都会指向同一个对象,数据全部被最后一次解析的内容覆盖。
2. GPX经度属性名错误
GPX标准里的经度属性是lon,但你的代码里写的是attributeDict["long"],这会导致经度值永远无法被正确解析。
3. 未处理空白字符
foundCharacters会包含XML里的换行、空格等空白字符,直接赋值给name和time会导致字符串包含多余的空白。
4. 错误处理不够严谨
你强制解包XMLParser(contentsOf: filepath)!,如果文件路径错误或者文件不存在,会直接崩溃而不是优雅处理错误。
修正后的完整代码
import Foundation class Wpt { var lat: Float? var lon: Float? // 修正属性名 var name = "" var time = "" } class Parser: NSObject, XMLParserDelegate { // 将变量移到类内部,避免全局状态污染 private var gpx = [Wpt]() private var currentWpt: Wpt? private var foundCharacters = "" func test(filepath: URL) { guard let parser = XMLParser(contentsOf: filepath) else { print("无法创建解析器,文件路径或文件可能存在问题") return } parser.delegate = self let success = parser.parse() if success { print("解析完成") printResults() } else { print("解析错误: \(parser.parserError?.localizedDescription ?? "未知错误")") } } func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { foundCharacters = "" // 开始新元素时重置字符缓存 if elementName == "wpt" { currentWpt = Wpt() // 每次遇到wpt就创建新实例 if let latStr = attributeDict["lat"], let lat = Float(latStr) { currentWpt?.lat = lat } if let lonStr = attributeDict["lon"], let lon = Float(lonStr) { // 修正为lon currentWpt?.lon = lon } } } func parser(_ parser: XMLParser, foundCharacters string: String) { foundCharacters += string.trimmingCharacters(in: .whitespacesAndNewlines) // 去除空白字符 } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { guard let wpt = currentWpt else { return } switch elementName { case "name": wpt.name = foundCharacters case "time": wpt.time = foundCharacters case "wpt": gpx.append(wpt) currentWpt = nil // 完成当前wpt解析后清空引用 default: break } } private func printResults() { for wpt in gpx { print("名称: \(wpt.name)") print("纬度: \(wpt.lat ?? 0)") print("经度: \(wpt.lon ?? 0)") print("时间: \(wpt.time)\n") } } } // 注意:这里的路径建议使用相对路径或者通过FileManager获取正确的文档路径,避免硬编码绝对路径 let filePath = URL(fileURLWithPath: "/Document/Github/GPXParser/GPXParser/Location.gpx") Parser().test(filepath: filePath)
关键修改说明
- 移除全局变量:把
gpx、currentWpt、foundCharacters移到Parser类内部,每次解析都是独立的实例,避免数据污染。 - 修正经度属性名:将
long改为GPX标准的lon,确保经度值能被正确读取。 - 处理空白字符:在
foundCharacters拼接时去除多余的空白和换行,保证name和time的内容干净。 - 优化错误处理:用
guard let替代强制解包,避免因文件问题直接崩溃,同时更清晰地输出错误信息。 - 完善解析逻辑:每次遇到
<wpt>时创建新的Wpt实例,解析完成后添加到数组并清空当前引用,确保每个wpt都是独立对象。
另外,关于你提到的parserError为nil的情况,大概率是因为解析器本身没有检测到XML格式错误,但你的代码逻辑错误导致数据异常,看起来像是解析失败。修正上述问题后,应该就能正常解析GPX文件了。
内容的提问来源于stack exchange,提问作者Maxime Brunengo
相关产品推荐
相关产品推荐

