Python,lxml - 获取兄弟标签(大)孩子的文本

时间:2012-11-19 17:18:51

标签: python xml-parsing lxml siblings dspace

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

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

我想遍历此XML并找到比特流内的所有 id 值,以获取捆绑,其中 name 元素的值为'FOO'。我对任何未命名为'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值,而不是捆绑'FOO'的值。

如何遍历此树,使用名称 FOO找到捆绑,使用此捆绑节点并收集 id 嵌套在其中的值?这里的XPath参数是否不正确?

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

1 个答案:

答案 0 :(得分: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'