PowerShell修改GPX XML文件时无法遍历trkpt节点求助
解决PowerShell读取GPX XML时节点为空的问题
问题描述
我尝试用PowerShell编辑GPX格式的XML文件,目标是修正更换GPS电池后特定时间点之后的轨迹点(trkpt)的海拔坐标。但脚本未进入foreach循环,推测$nodes数组为空,仅保存命令正常,需要解决这个问题。
原脚本
$filePath = "c:\users\g\documents\bat\PetroglifosV.gpx" $xml = [xml] (Get-Content $filePath) $nodes = $xml.SelectNodes("//trkpt") # Write-Host "Tratando: " $nodes foreach ($element in $nodes) { Write-Host "Tratando elemento: " $element.ele.InnerText if ($element.time.InnerText.Substring(11,5) -gt "08:48") { $element.ele.InnerText = 217 + $element.ele.InnerText } Write-Host "Tratado elemento: " $element.ele.InnerText } $xml.Save("c:\users\g\documents\bat\petrotemp.txt")
原GPX文件内容
<?xml version="1.0" encoding="UTF-8"?> <gpx creator="Wikiloc - https://www.wikiloc.com" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"> <metadata> <name>Wikiloc - Baiona a los petroglifos de Outeiro dos Lameiros</name> <author> <name>guigargi</name> <link href="https://www.wikiloc.com/wikiloc/user.do?id=657054"> <text>guigargi on Wikiloc</text> </link> </author> <link href="https://www.wikiloc.com/hiking-trails/baiona-a-los-petroglifos-de-outeiro-dos-lameiros-26925951"> <text>Baiona a los petroglifos de Outeiro dos Lameiros on Wikiloc</text> </link> <time>2018-07-23T09:55:48Z</time> </metadata> <trk> <name>Baiona a los petroglifos de Outeiro dos Lameiros</name> <cmt> </cmt> <desc> </desc> <trkseg> <trkpt lat="42.117677" lon="-8.847421"> <ele>-12.431</ele> <time>2018-07-23T06:55:22Z</time> </trkpt> <trkpt lat="42.117649" lon="-8.847403"> <ele>-12.461</ele> <time>2018-07-23T06:55:23Z</time> </trkpt> <trkpt lat="42.117661" lon="-8.847388"> <ele>-12.407</ele> <time>2018-07-23T06:55:24Z</time> </trkpt> <trkpt lat="42.117687" lon="-8.847385"> <ele>-12.408</ele> <time>2018-07-23T06:57:09Z</time> </trkpt> <trkpt lat="42.117593" lon="-8.847370"> <ele>-12.435</ele> <time>2018-07-23T06:57:25Z</time> </trkpt> <trkpt lat="42.113513" lon="-8.838031"> <ele>-184.594</ele> <time>2018-07-23T09:55:38Z</time> </trkpt> <trkpt lat="42.113517" lon="-8.838084"> <ele>-184.520</ele> <time>2018-07-23T09:55:48Z</time> </trkpt> </trkseg> </trk> </gpx>
问题原因
你的GPX文件包含默认命名空间xmlns="http://www.topografix.com/GPX/1/1",而SelectNodes方法默认不会处理命名空间,直接用//trkpt查询会找不到任何节点,导致$nodes为空。
另外,原脚本中用字符串截取时间进行比较的方式不够可靠,建议转换成DateTime对象进行时间比较,避免字符串格式问题;直接用字符串拼接计算海拔也会导致错误(比如217 + "-184.594"会变成字符串而非数值)。
修正后的脚本
$filePath = "c:\users\g\documents\bat\PetroglifosV.gpx" $xml = [xml] (Get-Content $filePath) # 注册GPX命名空间 $nsManager = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) $nsManager.AddNamespace("gpx", "http://www.topografix.com/GPX/1/1") # 使用带命名空间前缀的XPath查询trkpt节点 $nodes = $xml.SelectNodes("//gpx:trkpt", $nsManager) # 定义目标时间(转换为DateTime对象) $targetTime = [DateTime]"2018-07-23T08:48:00Z" foreach ($element in $nodes) { $currentEle = [double]$element.ele.InnerText Write-Host "处理前海拔: $currentEle" $currentTime = [DateTime]$element.time.InnerText if ($currentTime -gt $targetTime) { # 计算新海拔并保留三位小数 $newEle = [math]::Round($currentEle + 217, 3) $element.ele.InnerText = $newEle.ToString() } Write-Host "处理后海拔: $($element.ele.InnerText)" } # 保存为GPX格式(建议用.gpx后缀) $xml.Save("c:\users\g\documents\bat\petrotemp.gpx")
关键修改点
- 新增命名空间管理器,注册GPX的命名空间前缀
gpx,查询时使用//gpx:trkpt定位节点 - 将时间字符串转换为
DateTime对象进行比较,逻辑更准确 - 将海拔转换为数值类型计算,避免字符串拼接导致的错误
- 对计算后的海拔保留三位小数,保持原数据格式一致
内容的提问来源于stack exchange,提问作者GGG
相关产品推荐
相关产品推荐

