从另一个文件编写KML文件

3

我正在尝试:

- 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文件时,仍然会有我想要删除的元素。 实际上,我想要删除包含名称为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))

3
这段代码完全没有意义。首先,你使用XML库将KML文件解析为“tree”变量。接着,你再次使用“pykml”库进行解析,并对其进行一些操作。最后,你只是将原始未更改的“tree”写回到文件中。我真的不知道你在这里想干什么。 - David Ferenczy Rogožan
你从库lxml中导入了etree,但是却没有使用它。为什么要使用两个不同的库来解析两次呢? - David Ferenczy Rogožan
@DawidFerenczy 抱歉,我今天有点累。我已经发布了没有测试行的代码。但现在我无法想出如何重新编写文件而不删除元素。 - xCloudx8
1
它对你有效吗?我已经测试过了,它按预期工作。 - David Ferenczy Rogožan
@DawidFerenczy 你好,我刚刚进行了测试,但它没有删除"ZONE"元素,我正在努力弄清楚原因。非常感谢。 - xCloudx8
添加了可工作的代码,我之前打印的变量是错误的 =) - xCloudx8
2个回答

2
考虑一下XSLT,这是一种专门设计用于转换XML文件的语言。由于KML文件就是XML文件,因此这个解决方案是可行的。Python的第三方模块lxml可以运行XSLT 1.0脚本,并且可以在没有单个循环的情况下运行。
具体而言,XSLT脚本运行Identity Transform以按原样复制整个文档。然后,在元素上运行一个空模板(根据特定逻辑条件),以删除该元素。为了适应默认命名空间,XPath搜索使用前缀docXSLT (另存为.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 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)

输出

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

1

您的代码存在以下问题:

  • 没有将整个解析的对象树存储在任何地方(您只有一个指向节点“Document.Folder” 的引用:folder = parser.parse(f).getroot().Document.Folder),但是您想要将其写回到文件中,因此需要将其存储起来。
  • 我不明白为什么您需要两个循环和列表removeList,当您可以在第一个循环中直接删除元素。
  • 您没有阅读文档-在 pykml 库的文档examples中很清楚地说明了如何将对象树写入文件。

尝试以下代码:

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
  • 直接操作相同的对象树(删除元素)
  • 将相同的对象树写回文件

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接