💻 第十一章 XML究竟是什么
📄 一句话概括

两拨人各自发明了 <名称>,撞名怎么办?命名空间给标签加上【姓】——前缀背后是全局唯一的 URI,同名标签从此各归各家。

📝 本节和前面几节的关系

上一节说交换要靠统一的标签约定,可不同行业、不同公司撞名怎么办?本节解决 XML 世界里的重名问题。

一、重名为什么是问题

卖电脑的公司用 <名称> 表示商品名,另一部门用 <名称> 表示公司名; 两份文档一合并,两个 <名称> 语义完全不同,程序无法区分; 改名字能躲一时——行业标准一多,靠改名避让迟早用尽词汇。

二、命名空间的做法

用 xmlns 声明一个前缀指向的命名空间标识符:xmlns:商品="urn:shop"; 此后 <商品:名称> 就是【姓商品的名字】,与 <公司:名称> 分属两个世界; 前缀只是给人看的简称——解析器内部把标签还原成 {urn:shop}名称 这样的完整形式; 标识符通常写成 URI(不要求真能访问),图的就是全局唯一:域名归各家自己管,天然不撞。

三、读法上的两处常见困惑

默认命名空间:写 xmlns="urn:a"(不带前缀)时,文档里所有无前缀标签都归它管辖; 前缀名可以随便起、不同文档里同一个 URI 可以用不同前缀——认 URI 不认前缀; 【⚠️ 2026 现状】所有现代 XML 方言都大量使用命名空间:打开任意 docx 解包可见 w:、r:、a: 等多个前缀并存。

四、动手 Demo:同名标签,各归各家

构造一份含两个 <名称> 的文档(一属商品、一属公司),用解析器读出两者的完整标签名。

import xml.etree.ElementTree as ET
xml = ('<报表>'
       '<商品:名称 xmlns:商品="urn:shop">笔记本电脑</商品:名称>'
       '<公司:名称 xmlns:公司="urn:corp">曦数科技</公司:名称>'
       '</报表>')
for e in ET.fromstring(xml):
    print(e.tag, "->", e.text)

实跑输出:

--------------------------------------------------------------------
可以为 XML 标签设定命名空间
--------------------------------------------------------------------

两个部门都用了 <名称> 标签: 一个是商品名, 一个是公司名——撞名了!
命名空间给标签加上【姓】, 前缀一写, 同名的两拨标签各归各家:

    <报表>
        <商品:名称 xmlns:商品="urn:shop">笔记本电脑</商品:名称>
        <公司:名称 xmlns:公司="urn:corp">曦数科技</公司:名称>
    </报表>

    解析后(前缀被还原成完整命名空间):
        {urn:shop}名称 -> 笔记本电脑
        {urn:corp}名称 -> 曦数科技

  写法                      含义
  ---------------------------------------------------------------------
  xmlns:商品="urn:shop"     声明前缀 商品 属于 urn:shop 命名空间
  <商品:名称>               这个名字姓【商品】, 与姓【公司】的互不干扰

    解析器看到的标签其实是 {urn:shop}名称 —— 前缀只是给人看的简称。

解析器输出 {urn:shop}名称 与 {urn:corp}名称——前缀被展开成命名空间,撞名不再成立。 注意两个 xmlns 是分别声明在两个子元素上的:谁声明谁生效(作用域跟着元素走)。

30 秒实验

  1. 给一段含两个重名元素的 XML 分别加上命名空间声明,跑解析看输出变化。
  2. 用一句话解释【前缀只是简称,认的是 URI】这句话的含义。

常见误区

  1. 以为前缀不同就等于命名空间不同——真正决定归属的是 xmlns 指向的 URI。
  2. 以为 xmlns 里的 URI 必须能访问——它只是唯一的标识串,浏览器打不开也完全正常。
自测三问(点开对答案) 1. 命名空间解决什么问题? —— 不同来源的同名标签撞车——给标签加上归属。 2. xmlns:商品="urn:shop" 的含义? —— 声明前缀 商品 归属 urn:shop 这个命名空间。 3. 解析器眼里的标签是什么形式? —— {urn:shop}名称——前缀已被展开成完整命名空间。

相关笔记