Я пытаюсь:
- read a KML file
- remove the Placemark element if name = 'ZONE'
- write a new KML file without the element
Это мой код:
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
и это 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>
Проблема в том, что когда я пишу новый файл KML, в нем все еще есть элемент, который я хочу удалить. Фактически, я хочу удалить элемент, содержащий name = ZONE. Что я делаю не так? Спасибо.
--- Окончательный код Это рабочий код благодаря @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))
И вы импортируете etree
из библиотеки lxml
, которая никогда не используется. Почему вы дважды разбираете его, используя две разные библиотеки?
@DawidFerenczy Извините, я сегодня немного устал. Я разместил код без тестовых строк. Но теперь я не могу понять, как снова записать файл без удаленного элемента.
Работает ли это для вас? Я протестировал его, и он работает, как ожидалось.
@DawidFerenczy Привет, я тестировал прямо сейчас, но он не удаляет элемент "ZONE", я пытаюсь понять это. Большое спасибо
Добавлен рабочий код, я печатал неправильную переменную =)
В вашем коде есть следующие проблемы:
folder = parser.parse(f).getroot().Document.Folder
), но вы хотите записать его обратно в файл, поэтому вам нужно его сохранитьremoveList
, когда можно удалять элементы прямо в первом циклеПопробуйте следующий код:
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))
Все очень просто:
tree
.Рассмотрим XSLT, язык специального назначения, предназначенный для преобразования файлов XML. А поскольку KML-файлы являются XML-файлы, это решение жизнеспособно. Сторонний модуль Python, lxml
, может запускать сценарии XSLT 1.0 и делать это без единого цикла.
В частности, сценарий XSLT запускает Преобразование идентичности для копирования всего документа как есть. Затем сценарий запускает пустой шаблон для элемента (в зависимости от конкретной логики), чтобы удалить этот элемент. Чтобы приспособить пространство имен по умолчанию, для поиска XPath используется префикс док.
XSLT(сохраните как файл .xsl, специальный файл .xml, который будет загружен в Python ниже)
<?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>
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)
Выход
<?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>
Этот код вообще не имеет смысла. Сначала вы анализируете файл KML с помощью библиотеки XML в переменную
tree
. Затем вы снова анализируете его, используя библиотекуpykml
, и проделываете некоторые операции с результатом. Наконец, вы просто записываете оригинальный нетронутыйtree
обратно в файл. Я действительно понятия не имею, каковы ваши намерения здесь.