3

我有一个要解析的 XML,这对我来说真的很棘手。

<bundles>
  <bundle>
    <bitstreams>
      <bitstream>
        <id>1234</id>
      </bitstream>
    </bitstream>
    <name>FOO</name>
  </bundle>
  <bundle> ... </bundle>
</bundles>

我想遍历这个 XML 并找到名称元素值为“FOO”的包的比特流内的所有id值。我对任何未命名为“FOO”的捆绑包不感兴趣,并且捆绑包中可能有任意数量的捆绑包和任意数量的比特流。

我一直在用tree.findall('./bundle/name')它来查找 FOO 包,但这只是返回一个列表,我无法为id值单步执行:

for node in tree.findall('./bundle/name'):
if node.text == 'FOO':
 id_values = tree.findall('./bundle/bitstreams/bitstream/id')
 for value in id_values:
     print value.text

这会打印出所有的 id 值,而不是 bundle 'FOO' 的值。

我如何遍历这棵树,找到名为FOO的,获取这个节点并收集嵌套在其中的id值?XPath 参数在这里不正确吗?

我正在使用 Python 进行lxml绑定,但我认为任何 XML 解析器都可以;这些不是大型 XML 树。

4

2 回答 2

6

你可以使用xpath来达到目的。以下 Python 代码完美运行:

import libxml2
data = """
<bundles>
  <bundle>
    <bitstreams>
      <bitstream>
        <id>1234</id>
      </bitstream>
    </bitstreams>
    <name>FOO</name>
  </bundle>
</bundles>
"""
doc = xmllib2.parseDoc(data)
for node in doc.xpathEval('/bundles/bundle/name[.="FOO"]/../bitstreams/bitstream/id'):
    print node

或使用lxmldata与上面的示例相同):

from lxml import etree

bundles = etree.fromstring(data)

for node in bundles.xpath('bundle/name[.="FOO"]/../bitstreams/bitstream/id'):
    print(node.text)

输出:

1234

如果<bitstreams>元素总是在<name>元素之前,您还可以使用更高效的 xpath 表达式:

'bundle/name[.="FOO"]/preceding-sibling::bitstreams/bitstream/id'
于 2012-11-19T19:04:44.887 回答
2

您的问题之一是“这里的 XPath 参数不正确吗?”。好吧,findall()不接受 XPath 表达式。它使用称为ElementPath的简化版本。此外,您的第二次调用与第findall()一次调用的结果没有任何关系,因此它只会返回id所有 s 中bundle的 s。

对您的代码稍作修改也应该可以工作(它与 XPath 表达式基本相同):

for node in tree.findall('./bundle/name'):
    if node.text != 'FOO':
        continue
    id_values = node.getparent().findall('./bitstreams/bitstream/id')
    for value in id_values:
        print value.text
于 2012-11-19T19:59:06.913 回答