KernelRanch
返回文章列表

XML 明明有 item 却查不到:识别默认命名空间

2026-11-13 #xml#data-import#python

XML 上写着 <item>,查询 findall('item') 却返回空列表,先检查祖先元素是否声明了默认命名空间。查询需要匹配命名空间 URI 和本地名。生产方可以更换前缀,只要 URI 和本地名保持一致,消费者的查询就无需跟着改。

1. 本机复现

保存为 xml_lab.py,运行 python xml_lab.py。两个输入具有同样的元素身份,分别使用默认命名空间和显式前缀。

from xml.etree import ElementTree as ET

default = """
<feed xmlns="urn:demo:catalog" xmlns:meta="urn:demo:metadata">
  <item id="42" meta:id="m-42">widget</item>
  <meta:item>metadata</meta:item>
</feed>
"""
prefixed = """
<c:feed xmlns:c="urn:demo:catalog" xmlns:m="urn:demo:metadata">
  <c:item id="42" m:id="m-42">widget</c:item>
  <m:item>metadata</m:item>
</c:feed>
"""

ns = {"catalog": "urn:demo:catalog", "meta": "urn:demo:metadata"}
for label, source in (("default namespace", default), ("renamed prefixes", prefixed)):
    root = ET.fromstring(source)
    assert root.findall("item") == []
    (item,) = root.findall("catalog:item", ns)
    (metadata,) = root.findall("meta:item", ns)
    assert item.tag == "{urn:demo:catalog}item"
    assert (item.text, metadata.text) == ("widget", "metadata")
    print(f"{label}: {item.text} / {metadata.text}")

assert item.get("id") == "42"
assert item.get("{urn:demo:metadata}id") == "m-42"
assert item.get("{urn:demo:catalog}id") is None
print("attributes:", item.get("id"), item.get("{urn:demo:metadata}id"))

本地实测输出如下。

default namespace: widget / metadata
renamed prefixes: widget / metadata
attributes: 42 m-42

2. 根据完整元素名诊断导入失败

先查看解析后的 element.tag。ElementTree 用 {URI}localname 表示带命名空间的名字。查询时可以直接写该形式,也可以维护一份前缀到 URI 的映射。示例查询里的 catalog 是消费者自定义的前缀,和输入文件用什么前缀无关。

默认命名空间适用于作用域里的无前缀元素,但无前缀属性保持无命名空间。因此 id 和 meta:id 可同时出现,且需要分别读取。导入协议若会变更 URI,可把支持的 URI 当成契约的一部分,在查不到元素时报告收到的完整名字。按本地名全局匹配会把同名业务元素和元数据元素混在一起。

小结

按命名空间 URI 和本地名定位元素。读取属性时单独判断它是否带前缀。

数据来源与检索时间

检索时间 2026-11-13。

来源URL对应内容
W3C Namespaces in XML 1.0https://www.w3.org/TR/xml-names/#defaulting默认命名空间和无前缀属性
Python ElementTreehttps://docs.python.org/3.11/library/xml.etree.elementtree.html#parsing-xml-with-namespaces带命名空间的 tag 与查询映射

核验说明

  • Windows、Python 3.11.9 实测两种前缀写法、同名异域元素和两个 id 属性。样本是固定的可信 XML,未测试不可信文档的解析安全或外部 XML Schema。