Write KML file from another

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Write KML file from another



I'm trying to:


- read a KML file
- remove the Placemark element if name = 'ZONE'
- write a new KML file without the element



This is my code:


from pykml import parser
kml_file_path = '../Source/Lombardia.kml'

removeList = list()

with open(kml_file_path) as f:
folder = parser.parse(f).getroot().Document.Folder

for pm in folder.Placemark:
if pm.name == 'ZONE':
removeList.append(pm)
print pm.name

for tag in removeList:
parent = tag.getparent()
parent.remove(tag)
#Write the new file
#I cannot reach the solution help me



and this is the KML:


<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>Lombardia</name>
<Style>
...
</Style>
<Folder>
<Placemark>
<name>ZOGNO</name>
<styleUrl>#FEATURES_LABELS</styleUrl>
<Point>
<coordinates>9.680530595139061,45.7941656233647,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>ZONE</name>
<styleUrl>#FEATURES_LABELS</styleUrl>
<Point>
<coordinates>10.1315885854064,45.7592449779275,0</coordinates>
</Point>
</Placemark>
</Folder>
</Document>
</kml>



The problem is that when I write the new KML file this still has the element I want to delete.
In fact, with I want to delete the element that contains name = ZONE.
What i'm doing wrong?
Thank you.



--- Final Code
This is the working code thanks to @Dawid Ferenczy:


from lxml import etree
import pykml
from pykml import parser

kml_file_path = '../Source/Lombardia.kml'

# parse the input file into an object tree
with open(kml_file_path) as f:
tree = parser.parse(f)

# get a reference to the "Document.Folder" node
folder = tree.getroot().Document.Folder

# iterate through all "Document.Folder.Placemark" nodes and find and remove all nodes
# which contain child node "name" with content "ZONE"
for pm in folder.Placemark:
if pm.name == 'ZOGNO':
parent = pm.getparent()
parent.remove(pm)

# convert the object tree into a string and write it into an output file
with open('output.kml', 'w') as output:
output.write(etree.tostring(folder, pretty_print=True))





That code doesn't make a sense at all. First, you parse the KML file using the XML library into a tree variable. Then you parse it again using the pykml library and you do some operations with the result. Finally, you just write the original untouched tree back into a file. I really have no clue what are your intentions here.
– Dawid Ferenczy
Aug 10 at 15:30



tree


pykml


tree





And you import etree from the library lxml which is never used. Why are you parsing it twice using two different libraries?
– Dawid Ferenczy
Aug 10 at 15:33


etree


lxml





@DawidFerenczy Sorry i'm kinda tired today. I've posted the code without the test rows. But now i cannot figure out how to write again the file without the deleted element.
– xCloudx8
Aug 10 at 15:40





Does it work for you? I have tested it and it's working as expected.
– Dawid Ferenczy
Aug 10 at 16:35





@DawidFerenczy Hi, i've tested right now but it does not delete the element "ZONE" i'm trying to figure it out. Thanks a lot
– xCloudx8
Aug 13 at 7:41




2 Answers
2



You have the following issues in your code:


folder = parser.parse(f).getroot().Document.Folder


removeList



Try the following code:


from lxml import etree
from pykml import parser

kml_file_path = './input.kml'

# parse the input file into an object tree
with open(kml_file_path) as f:
tree = parser.parse(f)

# get a reference to the "Document.Folder" node
folder = tree.getroot().Document.Folder

# iterate through all "Document.Folder.Placemark" nodes and find and remove all nodes
# which contain child node "name" with content "ZONE"
for pm in folder.Placemark:
if pm.name == 'ZONE':
parent = pm.getparent()
parent.remove(pm)

# convert the object tree into a string and write it into an output file
with open('output.kml', 'w') as output:
output.write(etree.tostring(tree, pretty_print=True))



It's very simple:


tree



Consider XSLT, the special purpose language designed to transform XML files. And because KML files are XML files, this solution is viable. Python's third-party module, lxml can run XSLT 1.0 scripts and do so without a single loop.


lxml



Specifically, the XSLT script runs the Identity Transform to copy entire document as is. Then, script runs an empty template on the element (conditional to specific logic) to remove that element. To accommodate the default namespace, a prefix, doc, is used for XPath search.



XSLT (save as .xsl file, a special .xml file to be loaded in Python below)


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:doc="http://earth.google.com/kml/2.2">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>

<xsl:template match="doc:Placemark[doc:name='ZONE']"/>

</xsl:stylesheet>



XSLT Fiddle Demo



Python


import lxml.etree as et

# LOAD XML AND XSL
doc = et.parse('/path/to/Input.xml')
xsl = et.parse('/path/to/XSLT_Script.xsl')

# CONFIGURE TRANSFORMER
transform = et.XSLT(xsl)

# RUN TRANSFORMATION
result = transform(doc)

# PRINT RESULT
print(result)

# SAVE TO FILE
with open('output.xml', 'wb') as f:
f.write(result)



Output


<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>Lombardia</name>
<Style>
...
</Style>
<Folder>
<Placemark>
<name>ZOGNO</name>
<styleUrl>#FEATURES_LABELS</styleUrl>
<Point>
<coordinates>9.680530595139061,45.7941656233647,0</coordinates>
</Point>
</Placemark>
</Folder>
</Document>
</kml>






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard