JSON 转 XML 遇到数组、重复同名元素与属性层级冲突的解决方案
JSON 只有对象、数组、字符串和数字,没有原生属性、命名空间或重复兄弟元素。将 JSON 转换到 XML 之前,必须决定数组如何重复元素、属性写在哪里、文本如何表达,以及命名冲突如何解决。本文讨论该映射契约。
一、问题概述:同样 JSON 对应多种 XML 结构
一个 items 数组可以变成重复的 item 元素,也可以包一层 items 容器;一个 id 可以是子节点,也可以是属性。如果没有输入输出契约,转换器可能会生成合规但违背接收方 Schema 的 XML。
二、最小复现:明确数组与属性的标识规则
以下约定使用 attributes 表示属性、children 表示子节点、text 表示文本;数组值会重复同名子节点。它是本文的输入契约,不代表所有工具都采用相同键名。
const input = {
name: "order",
attributes: { id: "ord-1" },
children: {
customer: { text: "Ada" },
item: [{ attributes: { sku: "book" }, text: "1" }, { attributes: { sku: "pen" }, text: "2" }],
},
};
// <order id="ord-1"><customer>Ada</customer><item sku="book">1</item><item sku="pen">2</item></order>三、根因:JSON 没有同名节点和属性层级
对象键必须唯一,而 XML 允许多个同名兄弟元素;JSON 的键值也没有办法单独表达属性与文本节点。把数组索引拼到标签名会改变 XML vocabulary,把所有字段都变成子节点又可能违反对方的属性约定。
四、推荐方案:先写映射表再调用转换器
为每个对象确定元素名、属性集合、文本字段和子节点集合。数组统一采用重复元素还是容器元素;同一对象同时拥有 text 与 children 时,规定是否允许混合内容。对未知字段报错或列入扩展区,不要静默改名。
五、完整代码:把约定转换成节点列表
下面的函数只建立 XML 节点模型,序列化器可以据此转义文本和属性。它刻意保留重复节点,不把数组下标写进标签名。
type XmlNode = {
name: string;
attributes?: Record<string, string>;
text?: string;
children?: XmlNode[];
};
function orderToNodes(order: { id: string; customer: string; items: Array<{ sku: string; quantity: number }> }): XmlNode {
return {
name: "order",
attributes: { id: order.id },
children: [
{ name: "customer", text: order.customer },
...order.items.map((item) => ({ name: "item", attributes: { sku: item.sku }, text: String(item.quantity) })),
],
};
}
console.log(orderToNodes({ id: "ord-1", customer: "Ada", items: [{ sku: "book", quantity: 1 }] }));六、常见错误方案
将 items[0]、items[1] 直接作为标签名会让 schema 随数据长度变化;把属性和子节点同名会使接收端无法判断优先级;把空数组输出成空字符串也会混淆“没有节点”和“有一个空节点”。
七、边界条件:空数组、同名字段与顺序
空数组应按契约输出为空容器或不输出节点,不能临时猜测。多个同名元素的顺序可能有业务意义,序列化器必须稳定保留。若 JSON 同时出现属性候选和子节点候选,应在 schema 层拒绝冲突,而不是覆盖一个值。
八、如何验证输入输出
用单元素、多元素、空数组、缺失属性、空文本和包含 &<> 的值测试。断言元素名称、重复次数、属性集合、子节点顺序和转义结果;再用接收方 XSD 或示例报文验证结构,而不只比较缩进后的字符串。
九、FAQ
问:数组一定要包一层容器吗?答:不一定,取决于接收方 schema;重复同名元素是另一种合法约定。
问:同名 JSON 字段能直接生成同名 XML 节点吗?答:单个对象键不能重复,必须用数组表达多个兄弟节点。
问:属性能从字段名自动猜吗?答:不能,应使用明确的属性列表和未知字段策略。
十、总结
JSON 转 XML 的难点不是打印尖括号,而是定义数组、属性、文本和同名节点的契约。先确定元素模型与冲突策略,再生成重复节点并验证顺序、空值和转义;不要依赖转换器的默认猜测。
来源与延伸阅读
技术审校所依据的规范与权威参考资料。
相关文章
JSON 转 XML:属性与 CDATA 的映射约定
说明 JSON 不原生区分 XML 属性、文本和 CDATA,建立显式字段约定并处理 XML 转义与 CDATA 中的 ]]> 边界。
最佳实践JSON 转 XML 与 SOAP Web Service 桥接:Envelope、Body 和命名空间
从 JSON 业务输入生成受控的 SOAP 1.1 Envelope,说明 Body、namespace、Fault 与 HTTP 协议边界,避免把普通 XML 转换误称为完整 SOAP 客户端。
实现原理JSON 转 TypeScript 类型推断引擎:递归、数组合并与命名
从 JSON 样本递归推断 TypeScript 类型,处理对象字段、数组元素合并和非法标识符命名,并明确样本推断的局限。
继续阅读
可打开关联的浏览器工具,使用自己的样本验证文中的处理流程。
打开关联工具