ElementTree XPath - 根据属性选择元素

49 投票
2 回答
55494 浏览
提问于 2025-04-11 17:40

我在使用ElementTree中的属性XPath选择器时遇到了问题,按照文档的说法,我应该能够做到这一点。

这里有一些示例代码:

XML

<root>
 <target name="1">
    <a></a>
    <b></b>
 </target>
 <target name="2">
    <a></a>
    <b></b>
 </target>
</root>

Python

def parse(document):
    root = et.parse(document)
    for target in root.findall("//target[@name='a']"):
        print target._children

我收到了以下异常:

expected path separator ([)

2 个回答

34

这段代码有几个问题。

  1. Python自带的ElementTree(简称ET)并不真正支持XPATH,只支持一些有限的功能。举个例子,它不支持从根节点查找的表达式,比如//target

    需要注意的是,文档提到过"//",但仅限于子节点:所以像.//target这样的表达式是有效的;而//...则不是!

    还有一个替代的实现方式:lxml,它功能更强大。看起来文档是针对内置代码的,但这并不匹配/有效。

  2. @name的写法中,选择的是xml的属性;而key=value的表达式是在xml标签内的。

    所以这个名字-值对必须是1或2,才能在给定的文档中选择某个东西。或者,可以查找有子元素 'a'的目标:target[a](不需要@)。

对于给定的文档,使用内置的ElementTree(v1.3)解析到根节点,以下代码是正确且有效的:

  • root.findall(".//target") 查找所有目标
  • root.findall(".//target/a") 查找两个a元素
  • root.findall(".//target[a]") 这会再次找到所有目标,因为它们都有一个a元素
  • root.findall(".//target[@name='1']") 只查找第一个目标。注意,1周围的引号是必须的;否则会出现语法错误
  • root.findall(".//target[a][@name='1']") 也是有效的;用来查找那个目标
  • root.findall(".//target[@name='1']/a") 只查找一个a元素;...
36

你想用的语法是在ElementTree 1.3中新增的。

这个版本是和Python 2.7或更高版本一起提供的。如果你使用的是Python 2.6或更低版本,那你还是在用ElementTree 1.2.6或更低的版本。

撰写回答