正在 Python 中解析 Google 地球 KML 文件(lxml、命名空间)
Parsing Google Earth KML file in Python (lxml, namespaces)
我正在尝试使用 xml 模块将 .kml 文件解析为 Python(在 BeautifulSoup 中失败后,我将其用于 HTML).
因为这是我第一次这样做,所以我遵循了官方tutorial并且一切顺利,直到我尝试构造一个迭代器以通过根迭代提取我的数据:
from lxml import etree
tree=etree.parse('kmlfile')
这是我试图模拟的教程中的 example:
If you know you are only interested in a single tag, you can pass its name to getiterator() to have it filter for you:
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"...) ,但我不知道不懂
{} 中的部分与我的具体示例完全相关
为什么和教程不一样
- 以及我做错了什么
非常感谢任何帮助!
这是我的解决方案。
因此,最重要的事情是阅读 Tomalak 发布的 this。它对命名空间的描述非常好,而且易于理解。
我们将使用 XPath to navigate the XML document. Its notation is similar to file systems, where parents and descendants are separated by slashes /. The syntax is explained here, but note that some commands are different for the lxml implementation。
###问题
我们的目标是提取城市名称:<Placemark>
下<name>
的内容。这是相关的 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 不理解什么是默认名称空间(参见 docs)。因此,我们需要像 Tomalak 上面建议的那样欺骗它:我们为默认设置一个前缀并将其添加到我们的搜索词中。例如,我们可以将其称为 kml。这段代码实际上起到了作用:
tree.xpath('//kml:Placemark/kml:name/text()', namespaces={"kml":"http://www.opengis.net/kml/2.2"})
tutorial mentions that there is also an ETXPath 方法,它的工作方式与 Xpath 类似,只是将名称空间写在大括号中而不是在字典中定义它们。因此,输入的样式为 {http://www.opengis.net/kml/2.2}Placemark
.
我正在尝试使用 xml 模块将 .kml 文件解析为 Python(在 BeautifulSoup 中失败后,我将其用于 HTML).
因为这是我第一次这样做,所以我遵循了官方tutorial并且一切顺利,直到我尝试构造一个迭代器以通过根迭代提取我的数据:
from lxml import etree
tree=etree.parse('kmlfile')
这是我试图模拟的教程中的 example:
If you know you are only interested in a single tag, you can pass its name to getiterator() to have it filter for you:
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"...) ,但我不知道不懂
{} 中的部分与我的具体示例完全相关
为什么和教程不一样
- 以及我做错了什么
非常感谢任何帮助!
这是我的解决方案。 因此,最重要的事情是阅读 Tomalak 发布的 this。它对命名空间的描述非常好,而且易于理解。
我们将使用 XPath to navigate the XML document. Its notation is similar to file systems, where parents and descendants are separated by slashes /. The syntax is explained here, but note that some commands are different for the lxml implementation。
###问题
我们的目标是提取城市名称:<Placemark>
下<name>
的内容。这是相关的 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 不理解什么是默认名称空间(参见 docs)。因此,我们需要像 Tomalak 上面建议的那样欺骗它:我们为默认设置一个前缀并将其添加到我们的搜索词中。例如,我们可以将其称为 kml。这段代码实际上起到了作用:
tree.xpath('//kml:Placemark/kml:name/text()', namespaces={"kml":"http://www.opengis.net/kml/2.2"})
tutorial mentions that there is also an ETXPath 方法,它的工作方式与 Xpath 类似,只是将名称空间写在大括号中而不是在字典中定义它们。因此,输入的样式为 {http://www.opengis.net/kml/2.2}Placemark
.