XML 转 JSON:namespace URI、prefix 与 localName 的区别
XML 前缀只是命名空间 URI 的局部别名,同一个 URI 可以绑定 a 或 b 前缀。若 XML 转 JSON 只保留 nodeName,前缀变化就会被误判为字段变化;若只保留 localName,不同 URI 的同名元素又会冲突。本文专门讨论 URI、prefix 和 localName 的边界。
一、问题概述: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 同名元素和属性命名空间。
来源与延伸阅读
技术审校所依据的规范与权威参考资料。
相关文章
XML 转 JSON:浏览器 DOMParser 的解析、错误检测与非流式边界
说明浏览器 DOMParser 的 XML 解析流程、parsererror 检测和 DOM 遍历转 JSON 方法,不编造性能数据,并明确 DOMParser 不是流式解析器。
错误排查XML 转 JSON:单节点与多节点的数组形状推断
解释 XML 只有一个子节点和出现多个同名节点时的 JSON 形状差异,比较始终数组、schema 驱动和后处理三种策略。
踩坑避坑XML Formatter:空白文本节点污染与 mixed content
区分纯字符串格式化和重新解析 DOM,说明缩进空白何时会成为文本节点,以及 mixed content 为什么不能随意插入换行。
继续阅读
可打开关联的浏览器工具,使用自己的样本验证文中的处理流程。
打开关联工具