findall() 默认忽略命名空间,必须显式传入命名空间字典(如{"ns": "http://example.com/ns"})并在xpath中使用前缀(如"ns:item"),uri需严格匹配,否则静默返回空列表。

findall() 找不到带命名空间的元素?先补全命名空间映射
Python 的 xml.etree.ElementTree.findall() 默认忽略命名空间,哪怕 XML 里写了 xmlns="http://example.com/ns",直接用 findall("item") 也啥都找不到。
必须显式传入命名空间字典,格式是 {'prefix': 'http://full/namespace/uri'}。注意:XML 中没写 prefix(比如默认命名空间 xmlns="...")时,不能省略 key,得自己起个前缀名(如 'ns'),并在 XPath 中用它。
- 错误写法:
root.findall("item")→ 永远返回空列表 - 正确写法:
root.findall("ns:item", {"ns": "http://example.com/ns"}) - 如果 XML 用的是默认命名空间(
xmlns="http://example.com/ns"),仍需绑定前缀,不能用空字符串或None作 key
默认命名空间(xmlns="")怎么处理?别信网上“用 {}”的野路子
有人试过 findall("{http://example.com/ns}item"),语法上能跑,但极其脆弱:一旦 XML 命名空间 URI 变了,所有硬编码的花括号路径全得改,没法复用,也不支持通配或复杂 XPath。
真正可靠的方式还是走命名空间映射字典,并在 XPath 中统一用前缀。哪怕原始 XML 没定义 prefix,你也得自己指定一个——这是 ElementTree 的设计约束,不是 bug。
立即学习“Python免费学习笔记(深入)”;
- 可行:
ns = {"d": "http://example.com/ns"}; root.findall("d:item", ns) - 不推荐:
root.findall("{http://example.com/ns}item")—— 可读性差、无法组合查询、和find()/iter()行为不一致 - 注意:前缀名(如
"d")可以任意取,只要和 XPath 中的一致,跟 XML 里是否真实存在该 prefix 无关
findall() 和 iter() 在命名空间下行为一致吗?基本一致,但要注意作用域
findall() 和 iter() 都接受命名空间字典参数,调用方式完全一样。区别在于:前者只查直接子元素,后者递归遍历全部后代。但两者对命名空间的解析逻辑是一致的——都依赖你传的字典,都不自动识别默认命名空间。
- 想查所有后代中的
item:list(root.iter("ns:item", {"ns": "http://example.com/ns"})) - 想查某一层级下的多个同名元素:
root.findall("ns:section/ns:item", ns),注意路径中每段都要加前缀 - 不支持省略前缀写法,比如
"ns:section/item"是错的,item也必须带ns:
解析失败没报错,但结果为空?检查命名空间 URI 是否完全匹配
ElementTree 对命名空间是严格字符串匹配的。多一个空格、少一个斜杠、协议从 http 写成 https,都会导致匹配失败,且不会抛异常,只会静默返回空列表——这是最常被忽略的坑。
- 建议把命名空间 URI 单独抽成常量,避免拼写误差:
NAMESPACE = "http://example.com/ns" - 用
print(root.tag)看根节点实际的命名空间(会显示为{http://example.com/ns}root),复制那段 URI 最保险 - 如果 XML 里有多个命名空间(如
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"),只需映射你实际要查的那些,不用全列
findall() 就安静地返回空。










