如何从GPX文件提取数据(并解析gpx文件)?

时间:2018-07-19 23:34:53

标签: xml gpx xmllint

我正在Linux下使用bash进行编码。我正在尝试提取一系列gpx文件中每个轨道的轨道名称第一时间戳

我尝试使用以下命令(和其他变体)使用xmllint解析gpx文件:

xmllint --xpath "//gpx/trk/name/text()" test.gpx
xmllint --xpath "//gpx/trk/trkseg[1]/time/text()" test.gpx

它失败,并返回以下消息:XPath set is empty

以下是文件 test.gpx

的示例
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<gpx creator="www.flyisfun.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">
  <trk>
    <name>Track_n1</name>
    <trkseg>
      <trkpt lat="-48.843895" lon="10.9835696">
        <ele>126.75549</ele>
        <time>2016-04-16T11:05:00Z</time>
      </trkpt>
      <trkpt lat="-48.843254" lon="11.9823042">
        <ele>126.90486</ele>
        <time>2016-04-16T11:05:05Z</time>
      </trkpt>
    </trkseg>
  </trk>
</gpx>

我原本希望得到这个测试用例

Track_n1
2016-04-16T11:05:00Z

我想知道为什么使用xmllint的命令不起作用,以及是否可以在不更改原始gpx文件的情况下将它们调整为有效。

谢谢您的帮助。

4 个答案:

答案 0 :(得分:1)

XML示例包含默认名称空间xmlns="http://www.topografix.com/GPX/1/1"xmllint --shellsetns结合可以用来获取值。
将默认(空)命名空间更改为已知的命名空间:

echo -e 'setns ns=http://www.topografix.com/GPX/1/1\ncat //ns:gpx/ns:trk/ns:name/text()' \
| xmllint --shell test.xml | grep -Ev '^([/]| [-])'

结果:

Track_n1

local-name() xml函数也可以使用,但是有时使复杂的xpath表达式难以阅读。

答案 1 :(得分:1)

如果您愿意使用xmllint的替代方法,那么xmlstarlet是一个不错的选择。 xmlstarlet中有很多命令,但是仅查询数据sel (select)即可。

我喜欢如何将名称空间绑定到前缀或如何使用_作为默认名称空间的前缀(在1.5.0+版本中)。 See here for more details.我更喜欢这样做,而不是将回显传递给xmllint。

将默认名称空间绑定到前缀...的示例...

xmlstarlet sel -N g="http://www.topografix.com/GPX/1/1" -t -m "/g:gpx/g:trk" -v "g:name" -n -v "g:trkseg/g:trkpt[1]/g:time" -n test.gpx

使用_作为默认名称空间前缀的示例...

xmlstarlet sel -t -m "/_:gpx/_:trk" -v "_:name" -n -v "_:trkseg/_:trkpt[1]/_:time" -n test.gpx

以上两个示例均产生以下输出...

Track_n1
2016-04-16T11:05:00Z

答案 2 :(得分:0)

我已设法将 Garmin GPX 转换为此处提供的解决方案中的文本格式。以下是一些工作语法:

xmlstarlet sel -N g="http://www.topografix.com/GPX/1/1" -T -t -m "/g:gpx/g:trk/g:trkseg/g:trkpt" -v "@lat" -o "|" -v "@lon" -o "|" -v "g:ele" -o "|" -v "g:time" -n my_track.gpx

xmlstarlet sel -N g="http://www.topografix.com/GPX/1/1" -T -t -m "/g:gpx/g:trk/g:trkseg/g:trkpt" -v "concat(@lat,'|',@lon,'|',g:ele,'|',g:time)" -n my_track.gpx

xmlstarlet sel -T -t -m "/_:gpx/_:trk/_:trkseg/_:trkpt" -v "concat(@lat,'|',@lon,'|',_:ele,'|',_:time)" -n my_track.gpx

xmlstarlet select --text --template --match "/_:gpx/_:trk/_:trkseg/_:trkpt" --value-of "concat(@lat,'|',@lon,'|',_:ele,'|',_:time)" --nl my_track.gpx

答案 3 :(得分:0)

也可以使用perl解决:

#!/usr/bin/perl
# https://unix.stackexchange.com/questions/343636/from-gpx-to-csv-file

use warnings;
use strict;
use XML::Twig;

    my $xml = XML::Twig -> new -> parsefile('my_track.gpx'); 

foreach my $wpt ( $xml -> get_xpath('/gpx/trk/trkseg/trkpt') ) {
     print $wpt -> att('lat') . "|" . $wpt -> att('lon') . "|" . $wpt -> first_child_text('ele') . "|" . $wpt -> first_child_text('time') . "\n";
}