Python ElementTree解析XML时findall方法部分路径返回空列表的原因咨询
为什么ElementTree的findall在某些XML路径下返回空列表?
首先来看你的代码和遇到的问题:
import xml.etree.ElementTree as ET # 补充你可能省略的导入代码 input = ''' <stuff> <users> <user x="2"> <id>001</id> <name>Chuck</name> </user> <user x="7"> <id>009</id> <name>Brent</name> </user> </users> </stuff>''' stuff=ET.fromstring(input) print(stuff.findall('stuff')) #返回空列表 print(stuff.findall('users')) #返回包含1个元素的列表 print(stuff.findall('user')) #返回空列表 print(stuff.findall('users/user')) #返回包含2个元素的列表 print(stuff.findall('stuff/users')) #返回空列表 print(stuff.findall('stuff/users/user')) #返回空列表
核心原因:findall的路径是相对当前节点的
当你用ET.fromstring(input)解析这段XML时,返回的stuff变量本身就是XML的根元素<stuff>。所以所有findall的路径都是从这个根元素开始查找的,而不是从整个文档的“顶层”重新开始。
我们逐个分析你的疑问:
stuff.findall('stuff'):你在根元素<stuff>下面找名为stuff的子元素,但根元素的直接子元素只有<users>,自然找不到,返回空列表。stuff.findall('users'):根元素的直接子元素就是<users>,所以能找到1个元素,符合预期。stuff.findall('user'):user是<users>的子元素,不是根元素的直接子元素,所以直接找user找不到,返回空。stuff.findall('users/user'):路径表示“根元素下的<users>子元素里的所有<user>”,这正好匹配XML结构,所以返回2个元素。stuff.findall('stuff/users'):你想找“根元素下的<stuff>子元素里的<users>”,但根元素下根本没有<stuff>子元素,所以返回空。stuff.findall('stuff/users/user'):和上面同理,路径的开头stuff在当前节点(根元素)下不存在,整个路径匹配失败,返回空。
和BeautifulSoup的区别
你之前用BeautifulSoup处理HTML时习惯的查找逻辑是全局查找,比如soup.find_all('user')会遍历整个文档树找所有<user>元素。但ElementTree的findall默认是相对路径查找,只在当前节点的直接或间接子元素中按路径匹配,不会全局遍历(除非你用XPath的特殊语法)。
解决方法
如果想实现类似BeautifulSoup的全局查找,或者更灵活的路径匹配,可以用XPath的//语法:
- 全局找所有
<user>:stuff.findall('.//user') - 全局找所有
<users>:stuff.findall('.//users')
如果要写完整的绝对路径(从文档根开始),可以用/开头:
- 找根元素下的
<users>:stuff.findall('/stuff/users') - 找根元素下的
<users>里的<user>:stuff.findall('/stuff/users/user')
这样就能得到你预期的结果啦~
内容的提问来源于stack exchange,提问作者user18344984
相关产品推荐
相关产品推荐

