tkrajina / gpxpy

gpx-py is a python GPX parser. GPX (GPS eXchange Format) is an XML based file format for GPS tracks.
Apache License 2.0
1.01k stars 223 forks source link

Cannot parse files where the default namespace is http://www.garmin.com/xmlschemas/TrackPointExtension/v2 #242

Open KennethEvans opened 2 years ago

KennethEvans commented 2 years ago

Normally the default namespace for a GPX file is http://www.topografix.com/GPX/1/1.

However it doesn't have to be. Many of my files have the default namespace as http://www.garmin.com/xmlschemas/TrackPointExtension/v2

(TrackPointExtension/v2 is a common way to include heart rate data.)

It is not under my control how they do this, and I believe it is perfectly valid. These files open and parse correctly in all the other GPX applications I use. They open but don't parse correctly in gpxpy. In particular, no tracks are found.

The difference is Ok Files:

<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:ns2="http://www.garmin.com/xmlschemas/TrackPointExtension/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1" creator="Polar Access Manager" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">

Not OK files:

<ns2:gpx xmlns="http://www.garmin.com/xmlschemas/TrackPointExtension/v2" xmlns:ns2="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1" creator="Polar Access Manager" xsi:schemaLocation="http://www.topografix.com/GPX/1/1

gpx.nsmap gives: Ok Files:

Namespaces:
    defaultns: http://www.topografix.com/GPX/1/1
    ns2: http://www.garmin.com/xmlschemas/TrackPointExtension/v2
    xsi: http://www.w3.org/2001/XMLSchema-instance

Not Ok files:

Namespaces:
    defaultns: http://www.garmin.com/xmlschemas/TrackPointExtension/v2
    ns2: http://www.topografix.com/GPX/1/1
    xsi: http://www.w3.org/2001/XMLSchema-instanc

Notice xsi is not all there.

Sample files: gpxpy_issue.zip

KennethEvans commented 2 years ago

Yes, it is definitely not handling the case where the default namespace is not http://www.topografix.com/GPX/1/1. That seems to be a bug to me. In fact, even ElementTree by default will use ns0 for http://www.topografix.com/GPX/1/1 and no default namespace. It is valid.

I fixed it by using ElementTree to parse the file after setting the default namespace to be http://www.topografix.com/GPX/1/1 and then passing the resulting XML to gpxpy.parse.

import xml.etree.ElementTree as ET

        # Ensure GPX/1/1 is the default namespace
        ET.register_namespace('', "http://www.topografix.com/GPX/1/1")
        tree = ET.parse(file_name)
        root = tree.getroot();
        xml = ET.tostring(root, encoding='unicode');
        # Parse the xml string
        gpx = gpxpy.parse(xml)
tve commented 2 years ago

I'm having a perhaps similar problem. Converting garmin fit files to gpx results in:

<gpx version="1.1" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GP
X/1/1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpxtpx="http://www.garmi
n.com/xmlschemas/TrackPointExtension/v1">

and have trkpt looking like

      <trkpt lat="34.405181017" lon="-119.842143841">
        <ele>-4.200</ele>
        <time>2022-02-15T22:12:26Z</time>
        <extensions>
          <gpxtpx:TrackPointExtension>
            <gpxtpx:atemp>20.000000</gpxtpx:atemp>
            <gpxtpx:hr>153</gpxtpx:hr>
          </gpxtpx:TrackPointExtension>
        </extensions>
      </trkpt>

and after parsing segment points have an empty extensions field.

biran4454 commented 1 month ago

+1, OpenTracks saves the speed with gpxtpx even though the default namespace is the topografix 1.1 one, eg.:

<trkpt lat="12.34567" lon="12.34567">
<ele>72</ele>
<time>2024-05-04T00:00:00.000+01:00</time>
<extensions><gpxtpx:TrackPointExtension>
<gpxtpx:speed>1.3</gpxtpx:speed>
<opentracks:accuracy_horizontal>1.891</opentracks:accuracy_horizontal></gpxtpx:TrackPointExtension></extensions>

The extensions attribute of the GPXTrackPoint has one element with a tag '{http://www.garmin.com/xmlschemas/TrackPointExtension/v2}TrackPointExtension' and a text of '\n'.