ElementTree 的 findall '或' 操作符

7 投票
2 回答
6620 浏览
提问于 2025-04-17 23:17

如果我有一个这样的xml文件:

<root>
  <item>
    <prop>something</prop>
  </item>
  <test>
    <prop>something</prop>
  </test>
  <test2>
    <prop>something</prop>
  </test2>
</root>

我可以用 xmlTree.getroot().findall("item") 来获取所有的'item'元素。

那么我该怎么才能获取所有的'item'或者'test'元素呢?我想要的效果是这样的:

xmlTree.getroot().findall("item or test")

在文档的例子里我没有看到类似的用法。有没有什么想法呢?

2 个回答

0

大数据集的“通配符”解决方案

这里有一个方法,你不需要指定“A | B | ...”。你可以用“*”作为通配符,然后通过索引来过滤掉不需要的部分,下面的代码就展示了这个方法(比如,在这个问题中,最后一个标签“test2”可以通过使用 lst[:-1] 来排除)。

import xml.etree.ElementTree as ET
data='''
<root>
  <item>
    <prop>something1</prop>
  </item>
  <test>
    <prop>something2</prop>
  </test>
  <test2>
    <prop>something3</prop>
  </test2>
</root>'''
root = ET.fromstring(data)
lst = root.findall('*')
for x in lst[:-1]:
    print(x.find('prop').text)

输出结果:

something1

something2

14

因为标准库里的 ElementTree 只支持有限的 xpath,所以如果你想用 | 这个 xpath 的“或”运算符,就必须使用 lxml 这个库:

from lxml import etree as ET


data = """<?xml version="1.0"?>
<data>
<item>1</item>
<test>2</test>
</data>"""

tree = ET.fromstring(data)

for element in tree.xpath('//item|//test'):
    print element.text

这段代码会输出:

1
2

如果你用的是 xml.etree.ElementTree,你可以把两个单独的 findall() 调用的结果结合起来:

for element in tree.findall('.//item') + tree.findall('.//test'):
    print element.text

或者,在循环里检查标签名:

for element in tree.iter():
    if element.tag in ('item', 'test'):
        print element.text

撰写回答