首页 > 解决方案 > 由于命名空间前缀问题 Python,无法从 XML 中检索评论

问题描述

我有以下“example.xml”文档,我的主要目标是能够检索文档中每个标签的评论。请注意,由于没有命名空间前缀,我已经能够检索到这个答案的评论,但是鉴于此,我得到了以下错误。

<?xml version="1.0" encoding="UTF-8"?>
<abc:root xmlns:abc="http://com/example/URL" xmlns:abcdef="http://com/another/example/URL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <tag1>
    <tag2>
        <tag3>tag3<!-- comment = “this is the tag3.1 comment”--></tag3>
        <tag4>tag4<!-- comment = “this is the tag4.1 comment”--></tag4>
    </tag2>
  </tag1>
  <tag1>
    <tag2>
        <tag3>tag3<!-- comment = “this is the tag3.2 comment”--></tag3>
        <tag4>tag4<!-- comment = “this is the tag4.2 comment”--></tag4>
    </tag2>
  </tag1>
</abc:root>

我试图通过两个选项,都导致错误。

我本质上是在遍历文档的每个节点并检查相关的评论。代码如下:

from lxml import etree
import os

tree = etree.parse("example.xml")
rootXML = tree.getroot()

print(rootXML.nsmap)

for Node in tree.xpath('//*'):
    elements = tree.xpath(tree.getpath(Node), rootXML.nsmap)
    basename = os.path.basename(tree.getpath(Node))
    for tag in elements:
        comment = tag.xpath('{0}/comment()'.format(tree.getpath(Node)))
        print(tree.getpath(Node))
        print(comment)

但是,执行此代码会给我以下错误:

TypeError: xpath() 正好采用 1 个位置参数(给定 2 个)

我也尝试遵循这个答案并在 xpath 中定义命名空间。这样做,我的代码变成:

from lxml import etree
import os

tree = etree.parse("example.xml")
rootXML = tree.getroot()

print(rootXML.nsmap)

for Node in tree.xpath('//*'):
    elements = tree.xpath(tree.getpath(Node), namespaces={rootXML.nsmap})
    basename = os.path.basename(tree.getpath(Node))
    for tag in elements:
        comment = tag.xpath('{0}/comment()'.format(tree.getpath(Node)))
        print(tree.getpath(Node))
        print(comment)

唯一的变化是替换elements = tree.xpath(tree.getpath(Node), rootXML.nsmap)elements = tree.xpath(tree.getpath(Node), namespaces={rootXML.nsmap}). 但是,这会导致修改后的行出现以下错误。

类型错误:不可散列的类型:'dict'

编辑:根据答案之一修改了右括号。

标签: pythonxml

解决方案


您在此行的末尾缺少一个右括号:

comment = tag.xpath('{0}/comment()'.format(tree.getpath(Node))


更新

这是一个工作示例:

from lxml import etree
import os

xml = """<?xml version="1.0" encoding="UTF-8"?>
<abc:root xmlns:abc="http://com/example/URL" xmlns:abcdef="http://com/another/example/URL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <tag1>
    <tag2>
        <tag3>tag3<!-- comment = “this is the tag3 comment”--></tag3>
        <tag4>tag4<!-- comment = “this is the tag4 comment”--></tag4>
    </tag2>
  </tag1>
  <tag1>
    <tag2>
        <tag3>tag3<!-- comment = “this is the tag3 comment”--></tag3>
        <tag4>tag4<!-- comment = “this is the tag4 comment”--></tag4>
    </tag2>
  </tag1>
</abc:root>""".encode('utf-8')

rootElement = etree.fromstring(xml)
rootTree = rootElement.getroottree()

print(rootElement.nsmap)

for Node in rootTree.xpath('//*'):
    elements = rootTree.xpath(rootTree.getpath(Node), namespaces=rootElement.nsmap)
    basename = os.path.basename(rootTree.getpath(Node))
    for tag in elements:
        comment = tag.xpath('{0}/comment()'.format(rootTree.getpath(Node)), namespaces=rootElement.nsmap)
        print(rootTree.getpath(Node))
        print(comment)

getPath主要问题是当需要使用namespaces关键字参数给出命名空间时,尝试将命名空间作为位置参数传递。另一个问题是试图在_Element只能在_ElementTrees 上调用方法时调用方法,反之亦然。

同样在您的第二个示例中,您尝试执行此操作namespaces={rootXML.nsmap}rootXML.nsmap已经是一本字典,你不需要任何花括号。此外,该语法不会创建字典,它会创建 a Set,因此它抱怨您尝试放入其中的内容不可散列。


推荐阅读