JSON 转 XML:属性与 CDATA 的映射约定
JSON 字符串只有字符内容,不携带 XML 的属性节点或 CDATA 标记。转换器必须通过约定键名或中间模型表达这些意图;否则把字符串放进属性、普通文本或 CDATA 的结果会依赖工具默认行为。本文只讨论属性与 CDATA 的映射,不讨论数组冲突或 SOAP。
一、问题概述:字符串内容不等于 XML 表示方式
description: "a < b" 在 XML 中可以是转义后的普通文本,也可以放进 CDATA;id 还可能要求作为属性。三种表示的字符结果、schema 类型和接收方处理方式不同,不能只看最终显示文本。
二、最小复现:先约定属性与 CDATA 键
本文采用 $attributes 表示属性、$text 表示普通文本、$cdata 表示 CDATA。一个节点只能在 $text 和 $cdata 中选择一个,属性值始终按 XML 属性规则转义。
const input = {
message: {
$attributes: { id: "m-1" },
$cdata: "if (a < b && c > d) return;",
},
};
// <message id="m-1"><![CDATA[if (a < b && c > d) return;]]></message>三、根因:CDATA 是 XML 语法标记,不是 JSON 数据类型
JSON.parse 和 JSON.stringify 不会保留“这是 CDATA”这一意图;它们只处理字符串。属性同样不是 JSON 的原生层级。必须在转换边界引入明确约定,并让 schema 验证器拒绝同时出现普通文本和 CDATA 的对象。
四、推荐方案:使用中间模型并显式选择表示
先把输入规范化为 name、attributes、text 或 cdata,再交给 XML serializer。普通文本必须转义 &、< 和 >;属性还要处理引号。CDATA 不能包含 ]]>,遇到该序列时要拆成多个 CDATA 段,而不是直接拼接无效 XML。
五、完整代码:安全处理属性和 CDATA
下面的代码返回 XML 内容片段,展示属性转义和 CDATA 分段;它不负责命名空间、数组或 SOAP Envelope。
function escapeAttribute(value: string): string {
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll("\"", """);
}
function wrapCdata(value: string): string {
return "<![CDATA[" + value.replaceAll("]]>", "]]]]><![CDATA[>") + "]" + "]>";
}
function messageXml(id: string, script: string): string {
return "<message id=\"" + escapeAttribute(id) + "\">" + wrapCdata(script) + "</message>";
}
console.log(messageXml("m&1", "if (a < b && c > d) return;"));六、常见错误方案
把所有字符串都包进 CDATA 会改变需要实体转义的普通文本约定;把 $cdata 当成属性会生成错误层级;直接输出 ]]> 会截断 CDATA。只转义 < 而不处理 &,也会让已有实体片段产生非法或不同语义。
七、边界条件:混合内容、空值与控制字符
空字符串可以是空元素、空 CDATA 或缺失字段,必须在契约中区分。一个节点同时拥有文本和子元素时属于 mixed content,不应被普通对象遍历器随意排序。非法 XML 控制字符也应在序列化前拒绝,而不是替换成问号。
八、如何验证映射结果
测试属性中的 &<>"、CDATA 中的 ]]>、空字符串、换行、Unicode 和控制字符。先用 XML parser 验证文档可解析,再检查属性值、文本值和 CDATA 内容是否保持;最后用接收方 schema 确认该字段确实允许 CDATA 等价的字符内容。
九、FAQ
问:CDATA 能保存任意字符串吗?答:不能直接包含 ]]>,且 XML 仍禁止某些控制字符。
问:CDATA 与普通文本的值有区别吗?答:解析后的字符通常可相同,但序列化形式和 schema/接收方约定可能不同。
问:JSON 能自动恢复原来的属性吗?答:不能,属性意图必须由输入约定或外部 schema 提供。
十、总结
JSON 没有属性和 CDATA 类型,必须通过显式键名或中间模型表达。属性按 XML 规则转义,普通文本与 CDATA 分开选择,并对 ]]>、控制字符和混合内容做边界验证。
来源与延伸阅读
技术审校所依据的规范与权威参考资料。
相关文章
JSON 转 XML 遇到数组、重复同名元素与属性层级冲突的解决方案
在 JSON 转 XML 前定义数组、属性、文本和重复同名元素规则,附带有明确输入输出契约的订单转换示例。
最佳实践JSON 转 XML 与 SOAP Web Service 桥接:Envelope、Body 和命名空间
从 JSON 业务输入生成受控的 SOAP 1.1 Envelope,说明 Body、namespace、Fault 与 HTTP 协议边界,避免把普通 XML 转换误称为完整 SOAP 客户端。
实现原理Myers 算法用于 JSON 数组 Diff 的边界与实现
说明 Myers 最短编辑脚本适合比较有序 JSON 数组,演示 insert、delete、equal 操作和路径 patch 的生成,并解释对象匹配与重复元素的限制。
继续阅读
可打开关联的浏览器工具,使用自己的样本验证文中的处理流程。
打开关联工具