Change the tag id attribute in KML (Simplekml)

610 views Asked by At

Is it possible to change the id attribute in a tag in simplekml?

import simplekml
kml = simplekml.Kml()
pnt = kml.newpoint(name='A Point')
pnt.coords = [(1.0, 2.0)]
kml.save("icon.kml")

This will generate the following document

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
    <Document id="1">
        <Folder id="2">
            <Style id="5">
                <IconStyle id="6">
                    <colorMode>normal</colorMode>
                    <scale>1</scale>
                    <heading>0</heading>
                    <Icon id="7">
                        <href>https://www.gstatic.com/mapspro/images/stock/503-wht-blank_maps.png</href>
                    </Icon>
                </IconStyle>
            </Style>
            <Placemark id="4">
                <name>A Point</name>
                <styleUrl>#5</styleUrl>
                <Point id="3">
                    <coordinates>1.0,2.0,0.0</coordinates>
                </Point>
            </Placemark>
        </Folder>
    </Document>
</kml>

Note that in some tags, an id attribute appears as if it had been generated from some simplekml index. I needed to change the ID assigned to the <Style id="5"> tag to <Style id="icon-1532-0288D1-nodesc-normal">

This would change the icon on Google My Maps. How can I do this using simplekml?

1

There are 1 answers

2
Thomas Duquemin On

It looks like in the (getting started) documentation, https://simplekml.readthedocs.io/en/latest/gettingstarted.html, the id tag is generated differently for different kinds of objects, ie 'feat_1', 'feat_2', 'geom_0':

import simplekml
kml = simplekml.Kml()
pnt = kml.newpoint(name="A Point")
print kml.kml()

This is what is generated:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
    <Document id="feat_1">
        <Placemark id="feat_2">
            <name>A Point</name>
            <Point id="geom_0">
                <coordinates>0.0, 0.0, 0.0</coordinates>
            </Point>
        </Placemark>
    </Document>
</kml>

I looked through the source code, and it looks like, at least in version 1.3.2, they got away from that, and generate tag id's by just counting up.

class Kmlable(object):
    """Enables a subclass to be converted into KML."""
    _globalid = 0
    _currentroot = None
    _compiling = False
    _namespaces = ['xmlns="http://www.opengis.net/kml/2.2"', 'xmlns:gx="http://www.google.com/kml/ext/2.2"']
    
    def __init__(self):
        self._id = str(Kmlable._globalid)
        Kmlable._globalid += 1
        try:
            from collections import OrderedDict
            self._kml = OrderedDict()
        except ImportError:
            self._kml = {}

For some reason, these id tags are designed to be read only:

    @property
    def id(self):
        """The id string (read only)."""
        return self._id

One hack-y way you could change this is something like (in base.py):

class Kmlable(object):
    """Enables a subclass to be converted into KML."""
    #_globalid = 0
    _globalid = 'your_string_here'
    _currentroot = None
    _compiling = False
    _namespaces = ['xmlns="http://www.opengis.net/kml/2.2"', 'xmlns:gx="http://www.google.com/kml/ext/2.2"']
    
    def __init__(self):
        self._id = str(Kmlable._globalid)
        #Kmlable._globalid += 1
        try:
            from collections import OrderedDict
            self._kml = OrderedDict()
        except ImportError:
            self._kml = {}

But that would set the same id for every object you have in your kml document:

import simplekml
kml = simplekml.Kml()
pnt = kml.newpoint(name="A Point")
print(kml.kml())

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
    <Document id="your_string_here">
        <Placemark id="your_string_here">
            <name>A Point</name>
            <Point id="your_string_here">
                <coordinates>0.0, 0.0, 0.0</coordinates>
            </Point>
        </Placemark>
    </Document>
</kml>

Hopefully that helps your understanding. Not a full-stop answer, but too long to post in the comments.