用Python解析Google Earth KML文件(lxml,命名空间)

时间:2016-07-04 17:13:58

标签: python xml xpath lxml xml-namespaces

我正在尝试使用xml模块将.kml文件解析为Python(未能在BeautifulSoup中使用它,我将其用于HTML)。

由于这是我第一次这样做,我跟着官方tutorial,一切顺利,直到我尝试构建迭代器以通过root迭代提取我的数据:

from lxml import etree
tree=etree.parse('kmlfile')

以下是我试图模仿的教程中的example

  

如果您知道自己只对单个标签感兴趣,可以将其名称传递给getiterator(),让它为您过滤:

for element in root.getiterator("child"):
    print element.tag, '-', element.text

我想在' Placemark'下获取所有数据,所以我尝试了

for i in tree.getiterterator("Placemark"):
    print i, type(i)

它没有给我任何东西。工作是什么:

for i in tree.getiterterator("{http://www.opengis.net/kml/2.2}Placemark"):
    print i, type(i)

我不明白这是怎么发生的。 www.opengis.net列在文档开头的标签中( kml xmlns =" http://www.opengis.net/kml/2.2" ... ),但我不明白

  • {}中的部分如何与我的具体示例相关

  • 为什么它与教程不同

  • 以及我做错了什么

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:3)

这是我的解决方案。 因此,最重要的是阅读Tomalak发布的this。这是一个非常好的名称空间描述,易于理解。

我们将使用XPath来导航XML文档。它的表示法类似于文件系统,其中父项和子句用斜杠 / 分隔。语法解释为here,但请注意lxml implementation的某些命令不同。

问题

我们的目标是提取城市名称:<name><Placemark>的内容。这是相关的XML:

<Placemark> <name>CITY NAME</name> 

相当于我上面发布的非功能代码的XPath是:

tree=etree.parse('kml document')
result=tree.xpath('//Placemark/name/text()')

需要text()部分才能将文字包含在//Placemark/name位置。

现在这不起作用,正如Tomalak指出的那样,因为这两个节点的名称实际上是{http://www.opengis.net/kml/2.2}Placemark{http://www.opengis.net/kml/2.2}name。大括号中的部分是默认命名空间。它没有显示在实际文档中(这使我感到困惑),但它在XML文档的开头定义如下:

xmlns="http://www.opengis.net/kml/2.2"

解决方案

我们可以通过设置namespaces参数来为xpath提供名称空间:

xpath(X, namespaces={prefix: namespace})

对于具有实际前缀的名称空间,这很容易,在本文档中为<gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>,其中gx前缀在文档中定义为xmlns:gx="http://www.google.com/kml/ext/2.2"

但是,Xpath不了解默认命名空间是什么(cf docs)。因此,我们需要欺骗它,就像上面提到的Tomalak:我们为默认值创建了一个前缀并将其添加到我们的搜索词中。我们可以称之为kml。这段代码实际上可以解决问题:

tree.xpath('//kml:Placemark/kml:name/text()', namespaces={"kml":"http://www.opengis.net/kml/2.2"})

tutorial提到还有一个ETXPath方法,它的工作方式与Xpath类似,只是将命名空间用大括号括起来而不是在字典中定义它们。因此,输入将是样式{http://www.opengis.net/kml/2.2}Placemark