pe-perry
pe-perry

Reputation: 2621

Read GPX using lxml and xpath

From this post, I know that I can .find(), .findall() and .text() to get the values nested in the tags.

Take the following .gpx file as example,

<?xml version="1.0"?>
<gpx version="1.1" creator="Trails 1.28 - https://www.trails.io" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxtpx="http://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd" xmlns:trailsio="http://trails.io/GPX/1/0" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://trails.io/GPX/1/0 https://trails.io/GPX/1/0/trails_1.0.xsd">
    <metadata>
        <time>2016-03-27T06:30:06Z</time>
    </metadata>
    <trk>
        <name><![CDATA[xyz]]></name>
        <extensions><trailsio:TrackExtension><trailsio:activity>trekking</trailsio:activity></trailsio:TrackExtension></extensions>
        <trkseg>
            <trkpt lat="22.491121" lon="114.137634">
                <ele>41.270</ele>
                <time>2016-03-27T01:21:21Z</time>
            </trkpt>
            <trkpt lat="22.491104" lon="114.137612">
                <ele>42.777</ele>
                <time>2016-03-27T01:21:38Z</time>
            </trkpt>
        </trkseg>
    </trk>
</gpx>

If I want to obtain the elevation, I can try:

gpx = etree.parse("D:/Users/perry/Downloads/abc.gpx")
ele = gpx.findall("{http://www.topografix.com/GPX/1/1}trk")
ele = [x.findall("{http://www.topografix.com/GPX/1/1}trkseg") for x in ele][0]
ele = [x.findall("{http://www.topografix.com/GPX/1/1}trkpt") for x in ele][0]
ele = [x.findall("{http://www.topografix.com/GPX/1/1}ele") for x in ele]
[x[0].text for x in ele]

And the output is ['41.270', '42.777'], it is what I want! Great!

However, I would like to use .xpath(), but

gpx.xpath("//ele")

,

gpx.xpath("//{http://www.topografix.com/GPX/1/1}ele")

and

gpx.xpath("//ele", namespaces = {'ele': "http://www.topografix.com/GPX/1/1"})

either return [] or error "lxml.etree.XPathEvalError: Invalid expression".

How can I get the elevation using .xpath()?

Thank you!

Upvotes: 1

Views: 917

Answers (1)

Keith Hall
Keith Hall

Reputation: 16075

You are on the right track with:

gpx.xpath("//ele", namespaces = {'ele': "http://www.topografix.com/GPX/1/1"})

Because there is a default namespace in the XML, the XPath //ele on it's own won't find the ele element in the http://www.topografix.com/GPX/1/1 namespace.

It is therefore necessary to register a prefix with the XPath provider, which you have done. However, you then need to reference the element using it's registered prefix. So the following will work:

gpx.xpath("//gpx:ele", namespaces = {'gpx': "http://www.topografix.com/GPX/1/1"})

Upvotes: 1

Related Questions