---
title: "XML 明明有 item 却查不到：识别默认命名空间"
date: 2026-11-13
slug: xml-default-namespace-lookup
canonical: https://kernelranch.com/blog/2026/11/xml-default-namespace-lookup
markdown_url: https://kernelranch.com/blog/2026/11/xml-default-namespace-lookup.md
tags: ["xml", "data-import", "python"]
---XML 上写着 `<item>`，查询 `findall('item')` 却返回空列表，先检查祖先元素是否声明了默认命名空间。查询需要匹配命名空间 URI 和本地名。生产方可以更换前缀，只要 URI 和本地名保持一致，消费者的查询就无需跟着改。

## 1. 本机复现

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

```python
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"))
```

本地实测输出如下。

```text
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.0 | https://www.w3.org/TR/xml-names/#defaulting | 默认命名空间和无前缀属性 |
| Python ElementTree | https://docs.python.org/3.11/library/xml.etree.elementtree.html#parsing-xml-with-namespaces | 带命名空间的 tag 与查询映射 |

## 核验说明

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