【问题标题】:Python, lxml - get a sibling tag's (grand)child's textPython,lxml - 获取兄弟标签的(大)孩子的文本
【发布时间】:2012-11-07 16:11:10
【问题描述】:

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

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

我想遍历这个 XML 并找到 bitstreams 内的所有 id 值,用于 bundle,其中 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”的值。

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

我在 Python 中工作,使用 lxml 绑定 - 但我相信任何 XML 解析器都可以;这些不是大型 XML 树。

【问题讨论】:

  • 你能告诉我们你到目前为止的代码吗?

标签: python xml-parsing lxml siblings dspace


【解决方案1】:

您可以使用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

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

'bundle/name[.="FOO"]/preceding-sibling::bitstreams/bitstream/id'

【讨论】:

  • 基本上你会找到名为 foo 的 bundle .. 然后去父节点并遍历回比特流 id ...
  • 还添加了一个 lxml 示例,因为它是 OP 使用的。希望没关系。
  • 是的,这工作正常。我完全误解了 lxml 中的 XPath。
【解决方案2】:

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

对您的代码稍作修改也应该可以工作(它与 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多