Записать файл kml из другого

Я пытаюсь:

- 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))

Этот код вообще не имеет смысла. Сначала вы анализируете файл KML с помощью библиотеки XML в переменную tree. Затем вы снова анализируете его, используя библиотеку pykml, и проделываете некоторые операции с результатом. Наконец, вы просто записываете оригинальный нетронутый tree обратно в файл. Я действительно понятия не имею, каковы ваши намерения здесь.

David Ferenczy Rogožan 10.08.2018 17:30

И вы импортируете etree из библиотеки lxml, которая никогда не используется. Почему вы дважды разбираете его, используя две разные библиотеки?

David Ferenczy Rogožan 10.08.2018 17:33

@DawidFerenczy Извините, я сегодня немного устал. Я разместил код без тестовых строк. Но теперь я не могу понять, как снова записать файл без удаленного элемента.

xCloudx8 10.08.2018 17:40

Работает ли это для вас? Я протестировал его, и он работает, как ожидалось.

David Ferenczy Rogožan 10.08.2018 18:35

@DawidFerenczy Привет, я тестировал прямо сейчас, но он не удаляет элемент "ZONE", я пытаюсь понять это. Большое спасибо

xCloudx8 13.08.2018 09:41

Добавлен рабочий код, я печатал неправильную переменную =)

xCloudx8 13.08.2018 10:50
2
6
1 144
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В вашем коде есть следующие проблемы:

  • вы нигде не храните все дерево проанализированных объектов (у вас есть только ссылка на узел "Document.Folder": folder = parser.parse(f).getroot().Document.Folder), но вы хотите записать его обратно в файл, поэтому вам нужно его сохранить
  • Не понимаю, зачем нужны два цикла и список removeList, когда можно удалять элементы прямо в первом цикле
  • вы не читаете документацию - в документации библиотеки pykml хорошо описано, как записать дерево объектов в файл под Примеры

Попробуйте следующий код:

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))

Все очень просто:

  • KML-файл анализируется в дереве объектов и сохраняется в переменной 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>

Демонстрация XSLT Fiddle

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>

Другие вопросы по теме