Javascript is required
踩坑避坑发布于 2026-07-28审校于 2026-08-084 分钟阅读

XML 转 JSON:namespace URI、prefix 与 localName 的区别

XML 前缀只是命名空间 URI 的局部别名,同一个 URI 可以绑定 ab 前缀。若 XML 转 JSON 只保留 nodeName,前缀变化就会被误判为字段变化;若只保留 localName,不同 URI 的同名元素又会冲突。本文专门讨论 URI、prefix 和 localName 的边界。

XML to JSONNamespacesPrefixlocalName

一、问题概述:prefix 变化不一定改变元素身份

<a:item xmlns:a="urn:shop"><b:item xmlns:b="urn:shop"> 的 prefix 不同,但 namespace URI 和 localName 相同。相反,<item xmlns="urn:other"> 的 localName 也叫 item,却属于另一个命名空间。

二、最小复现:比较 namespaceURI 与 localName

DOM 元素通常提供 namespaceURI、prefix、localName 等字段。下面的纯数据示例展示比较逻辑,不依赖某个 parser 的具体对象实现。

type ExpandedName = { namespaceURI: string | null; prefix: string | null; localName: string };
const first: ExpandedName = { namespaceURI: "urn:shop", prefix: "a", localName: "item" };
const second: ExpandedName = { namespaceURI: "urn:shop", prefix: "b", localName: "item" };
const other: ExpandedName = { namespaceURI: "urn:other", prefix: null, localName: "item" };

console.log(first.namespaceURI === second.namespaceURI && first.localName === second.localName); // true
console.log(first.namespaceURI === other.namespaceURI); // false

三、根因:prefix 是词法别名,URI 才是命名空间身份

命名空间声明把 prefix 绑定到 URI;同一文档甚至可以在不同子树重新绑定前缀。JSON 键若直接使用带前缀名称,序列化结果会随别名变化;若完全丢弃 URI,不同词汇的同名字段会合并。

四、推荐方案:保存 expanded name,再决定 JSON 键

中间模型至少保存 namespaceURI 和 localName,prefix 只作为可选显示信息。生成 JSON 时可以使用 {uri}localName、URI 映射表或按 schema 分组;选定一种稳定规则后,所有相同 URI/localName 的节点才可合并。

五、完整代码:用 expanded name 判断同一字段

以下函数把 URI 和 localName 组合成稳定键,并刻意不把 prefix 放进身份判断。空 URI 表示无命名空间,不应与任意有 URI 的元素混合。

type ExpandedName = { namespaceURI: string | null; prefix: string | null; localName: string };

function expandedKey(name: ExpandedName): string {
  return "{" + (name.namespaceURI ?? "") + "}" + name.localName;
}

function sameExpandedName(a: ExpandedName, b: ExpandedName): boolean {
  return a.namespaceURI === b.namespaceURI && a.localName === b.localName;
}

console.log(expandedKey({ namespaceURI: "urn:shop", prefix: "b", localName: "item" })); // {urn:shop}item
console.log(sameExpandedName(
  { namespaceURI: "urn:shop", prefix: "a", localName: "item" },
  { namespaceURI: "urn:shop", prefix: "b", localName: "item" },
)); // true

六、常见错误方案

把 prefix 当作稳定字段名会因重命名而产生重复键;只取 localName 会把不同 URI 的 item 合并;读取属性时也不能假设无前缀属性自动属于默认命名空间。把 namespace 声明节点本身当业务字段,还会污染输出。

七、边界条件:默认命名空间与属性

默认命名空间影响元素,但未加 prefix 的属性通常不自动继承默认命名空间;属性需要单独查看 namespaceURI。前缀可能为空、被重新绑定或只出现在序列化文本中,不能用字符串切分冒号替代解析器提供的字段。

八、如何验证转换结果

准备相同 URI 不同 prefix、不同 URI 相同 localName、默认命名空间和无命名空间属性四组样本。验证 JSON 键是否按 expanded name 规则稳定生成,并确认重序列化时 prefix 改变不会改变 URI 语义。

九、FAQ

问:prefix 改了,XML 元素就变了吗?答:只要绑定的 URI 和 localName 相同,命名空间身份不变。

问:只保存 localName 可以吗?答:只有在 schema 已保证 URI 唯一时才安全,否则会发生同名冲突。

问:属性也使用默认 namespace 吗?答:通常不能这样假设,属性应单独检查 namespaceURI。

十、总结

XML 命名空间身份由 URI 与 localName 组成,prefix 只是可替换别名。XML→JSON 中应保存 expanded name,按明确规则生成键,并分别验证默认命名空间、不同 URI 同名元素和属性命名空间。

来源与延伸阅读

技术审校所依据的规范与权威参考资料。

相关文章

继续阅读

可打开关联的浏览器工具,使用自己的样本验证文中的处理流程。

打开关联工具