post

How to split a gpx ? In each track, segment or trkpt ? (Python)

I had a project in my master’s degree (Sigma) to use python for doing something with a GPX file. There was a project like finding summit or pass, but I choose to edit a GPX to split it into in each of his tracks, segments, or by cutting the file into a specific point.

I choose to use LXML library to parse and edit .gpx, and OS to batch the process with multiple .gpx.

Dealing with the GPX

I don’t post all the code, only the important part, but the project Gpxsplit is available in the Github project page.

When parsing a gpx, you have to define the namespace to edit it with LXML. So my solution was to remove it, and to write a new namespace at the end :

for elem in outRoot.getiterator():
            if not hasattr(elem.tag, 'find'): continue  # (1)
            i = elem.tag.find('}')
            if i >= 0:
                elem.tag = elem.tag[i+1:]
        objectify.deannotate(outRoot, cleanup_namespaces=True)

With that code (thanks to falsetru), you can open every single file without having his namespace.

Splitting in segment

On the test file, our gpx has two segments. I have define a def segment(): to do the job.

We start by searching the number of segments with nbseg :

# count number of segment
nbseg=int(gpx.xpath("count(//trkseg)"))
# If more than one segment, splitting file by segment and tell user
if nbseg>1:
# We do the job

Then, we create every tag (gpx with metadata) :

# add GPX metadata
gpx = etree.Element('gpx', xmlns="http://www.topografix.com/GPX/1/1")
# add metadata to gpx
gpxmetadata = etree.SubElement(gpx, 'metadata')
etree.SubElement(gpxmetadata, 'author').text = "GpxSplit"
etree.SubElement(gpxmetadata, 'name').text = noext+' split by segment'
# add TRK tag (children of GPX)
trk = etree.SubElement(gpx, "trk")
# add all elements in each segment (trkpt, ele, time...)
trk.append(seg)   

As we are in a loop, we save a file for each loop :

# create a file for each seg
# call resultdir() to create result folder if doesn't exist
with open(gpxsplit.resultdir()+noext+'_seg'+str(id+1)+'.gpx', mode='wb') as doc:
	doc.write(etree.tostring(gpx, pretty_print=True))

I don’t explain how to do with a track because it’s likely the same to splitting a segment.

Splitting into a specific point

I start by defining a new variable called <em>foundpoint</em>, set to <em>False</em>. By default the script don’t find the point.

# foundpoint=False, means inLon and inLat are currently not found in the GPX file
foundpoint=False

Then I recreate all the hierarchy (metadata, <gpx>, tag…), and here we go, let’s search the point by his lat/lon !

If lat is the same and lon  is the name, or if we already found the point, we save all the trkpt in a file called .
Else, we keep searching for this point !

if trkpt.attrib['lat']==inLat and trkpt.attrib['lon']==inLon or foundpoint==True:
	foundpoint=True
	seg2.append(trkpt)
	with open(gpxsplit.resultdir()+noext+'_part2'+'.gpx', mode='wb') as doc:
		doc.write(etree.tostring(gpx2, pretty_print=True))
# Add trkpt to part 1
elif foundpoint==False:
	seg1.append(trkpt)
	with open(gpxsplit.resultdir()+noext+'_part1'+'.gpx', mode='wb') as doc:
		doc.write(etree.tostring(gpx1, pretty_print=True))

To finish we tell the user the result of the operation, and if the point was found we indicate the result folder.

if foundpoint==False:
    print('Point',inLon,'/',inLat,'has not been found')
else:
    print("Done")
    print("Split file has been stored in \""+gpxsplit.resultdir()+"\" folder")

All data are available on the GitHub project page.