WolfgangR
WolfgangR

Reputation: 1

How to add metadata to a gpxfile using gpxpy

I am extracting data from gpx files using gpxpy. Data example:

<?xml version="1.0" encoding="UTF-8"?>
<gpx 
 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" 
 version="1.1" 
 creator="xyz3">
        <metadata>
                <name>Cubieres-St.Paul</name>
                <desc>Export from GpsPrune</desc>
        </metadata>
        <trk>
...
        </trk>
</gpx>

The code goes like this:

def gpxinfo(gpx): # gpx =: class gpxpy.gpx.GPX
    "extract from GPX-file"
    gpxname = "No gpxname"
    description = "No description"
    if gpx.name:
        gpxname = gpx.name
    if gpx.description:
        description = gpx.description
    return {'gpxname': gpxname,
            'description': description}

Now, I want to add the <metadata>..</metadata> section for other gpx files where it is missing.

The problem in gpxpy for me is to insert the 'name' and 'desc' tags into the internal data structure that gpxpy builds up when parsing the file. I don't come to grips even by looking into the gpxpy source code.

Upvotes: 0

Views: 136

Answers (1)

Hermann12
Hermann12

Reputation: 3417

I don’t have gpxpy, but what I read, this Modul use lxml for parsing the gpx. gpx-Documentation.

I added 3 functions to manipulate the gpx:

from lxml import etree as et
from io import BytesIO

gpx_ = b"""\
<?xml version="1.0" encoding="UTF-8"?>
<gpx 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" 
 version="1.1" 
 creator="xyz3">
    <wpt> wptType </wpt>
    <rte> rteType </rte>
    <trk> trkType </trk>
    <extensions> extensionsType </extensions>
</gpx>
"""

def change_meta(root, namespaces, my_meta_data):
    """ Replace text for existing tags """
    for k,v in my_meta_data.items():
        try:
            t = root.find(f"./metadata/{k}", ns)
            t.text = v
        except:
            print(f"Tag {k} not found in gpx file")
    return root


def extend_meta(root, namespaces, my_meta_data):
    """ Replace text and add additional tags in metadata """
    ns = namespaces
    meta = root.find(".//metadata", ns)
    
    d = []
    # Change existing nodes
    for elem in meta.iter():
        for k,v in my_meta_data.items():
            if k in elem.tag:
                elem.text = v
                d.append(elem.tag.split('}')[1])
                
    # add missing nodes
    for k,v in my_meta_data.items():
        if k not in d:
            t = et.Element(f"{{http://www.topografix.com/GPX/1/1}}{k}")
            t.text = v
            meta.append(t)   
    return root

def create_meta(root, namespaces, my_meta_data):
    """ Add missing metadata tag and text in metadata """
    ns = namespaces
    meta = et.Element('metadata')
    root.insert(0, meta)
    for k,v in my_meta_data.items():
        t = et.Element(f"{{http://www.topografix.com/GPX/1/1}}{k}")
        t.text = v
        meta.append(t)
    return root

def write_gpx(root, filename):
    et.indent(root, space='  ')
    et.dump(root)
    tree = et.ElementTree(root)
    tree.write(filename, xml_declaration=True, encoding='UTF-8')
            

if __name__ == "__main__":
    file = BytesIO(gpx_)
    root = et.parse(file).getroot()
    #root = et.parse("landscape.gpx")
    ns = root.nsmap
    #print(root)
    #print(ns)
    
    # My new data tag-name : text
    meta_data = {
    "name" :"No gpxname", 
    "desc": "No description",
    "author": "No author",
    "copyright": "No copyright", 
    "link": "No link", 
    "time": "1970-01-31T23:59:59Z", 
    "keywords": "No keywords", 
    "bounds": "No bounds", 
    "extensions": "No extensions"}

    # Change metadata
    #new_gpx = change_meta(root, ns, meta_data)
    #et.dump(new_gpx)

    # Change and extend metadata
    #new1_gpx = extend_meta(root, ns, meta_data)

    # add metadata if missing
    meta_gpx = create_meta(root, ns, meta_data)

    # print and write the changed gpx
    write_gpx(meta_gpx, "newGpx.gpx")

Output (print and file):

<gpx 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" version="1.1" creator="xyz3">
  <metadata>
    <name>No gpxname</name>
    <desc>No description</desc>
    <author>No author</author>
    <copyright>No copyright</copyright>
    <link>No link</link>
    <time> 1970-01-31T23:59:59Z</time>
    <keywords>No keywords</keywords>
    <bounds>No bounds</bounds>
    <extensions>No extensions</extensions>
  </metadata>
  <wpt> wptType </wpt>
  <rte> rteType </rte>
  <trk> trkType </trk>
  <extensions> extensionsType </extensions>
</gpx>

Upvotes: 0

Related Questions