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

pat*_*ick 4 python xml xpath lxml xml-namespaces

我正在尝试使用 xml 模块将.kml文件解析为 Python(在我用于 HTML 的 BeautifulSoup 中失败后)。

由于这是我第一次这样做,我遵循了官方教程并且一切顺利,直到我尝试构建一个迭代器来通过根迭代提取我的数据:

from lxml import etree
tree=etree.parse('kmlfile')
Run Code Online (Sandbox Code Playgroud)

这是我试图模仿的教程中的示例

如果你知道你只对一个标签感兴趣,你可以将它的名称传递给 getiterator() 让它为你过滤:

for element in root.getiterator("child"):
    print element.tag, '-', element.text
Run Code Online (Sandbox Code Playgroud)

我想获取“地标”下的所有数据,所以我尝试了

for i in tree.getiterterator("Placemark"):
    print i, type(i)
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • {} 中的部分与我的具体示例有什么关系

  • 为什么它与教程不同

  • 我做错了什么

任何帮助深表感谢!

pat*_*ick 6

这是我的解决方案。所以,最重要的事情是阅读Tomalak 发布的这篇文章。这是对命名空间的非常好的描述并且易于理解。

我们将使用XPath来导航 XML 文档。它的符号类似于文件系统,其中父项和子项由斜杠/分隔。此处解释语法,但请注意,某些命令对于lxml 实现是不同的。

###问题

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

<Placemark> <name>CITY NAME</name> 
Run Code Online (Sandbox Code Playgroud)

与我上面发布的非功能代码等效的 XPath 是:

tree=etree.parse('kml document')
result=tree.xpath('//Placemark/name/text()')
Run Code Online (Sandbox Code Playgroud)

text()获取包含在 location 中的文本所需的部分//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"
Run Code Online (Sandbox Code Playgroud)

###解决方案

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

xpath(X, namespaces={prefix: namespace})
Run Code Online (Sandbox Code Playgroud)

这是有实际的前缀,这个文件例如在命名空间很容易的<gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>,其中gx前缀的文件中定义xmlns:gx="http://www.google.com/kml/ext/2.2"

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

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

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