2款车型不排队: RFC 8259 定义了六种没有属性的 JSON 类型,同时 XML 1.0 has属性、命名空间和有序混合内容,走这个方向就是选择区别怎么办。
JSON数据第一次必须发送到一个只会说XML的系统中,我做了一件天真的事情:我在文本编辑器中手写了角度括号,这是一个供应商提要,期望有一个SOAP-ish信封,我的来源是一个整洁的JSON阵列从一个Laravel API中出来。二十分钟,我在第四十条记录周围的某个地方不匹配一个结束标签,接收解析器在文档元素"之后抛出一个"垃圾错误,这告诉了我什么都没有 哪里。那天晚上给我上了一课,我从那以后应用在每一个集成上:JSON和XML之间的转换不是一个创造性的行为,这是一个有少量规则的映射问题,当你把这些规则写下来的那一刻,整个事情就变得机械化了。
本指南是我希望 I'd 拥有的映射版本。我构建 [toolz。dev](/,其中一个工具是基于浏览器的 JSON 到 XML 转换器 that恰恰适用了下面的约定。但本文的重点不是按钮-it's理解 为什么 键变成元素,为什么是 @-prefixed key变成属性,以及为什么一个数组会变成重复的标签而不是编号列表,一旦这三个想法点击,如果必须的话,可以手工将任何JSON转换为XML,并且可以在下游系统拒绝输出时调试它。
TL;博士: JSON 转换为 XML,要将每个对象键映射到一个元素,每个
@-其父元素上属性的前缀键,以及#textkey到元素's文本内容。将每个数组扩展为共享key's名称的重复兄弟元素。逃避&、<、和>文(加)中"在属性值中),并清理任何是't合法xml名称的密钥。在浏览器中执行此操作,以便有效负载令牌或客户数据永远不会离开您的机器。
为什么首先要将 JSON 转换为 XML?
JSON在几年前赢得了Web API战争,如果你在React,Laravel或Node度过了你的日子,你可能会合理地问你'd什么时候根本需要XML答案是:不断,只是不在你所看到的地方XML是一个巨大的系统安装基础的通用语言,这些系统早于JSON时代,并且不会去任何地方SOAP Web服务 - 仍然是银行,保险,物流和政府集成的支柱 - 在XML中携带他们的有效负载RSS和Atom源是XML站点地图是XML。Android布局, .docx 並 .xlsx internals(office Open XML)、SVG、RSS 播客源以及无数 B2B EDI 风格的交换都是 XML。
所以现实世界的场景几乎总是相同的形状:你有数据 在 JSON,因为那's你的堆栈产生什么,你需要它 在 XML因为那's对方所要求的。也许你're将产品数据推入一个只接受XML提要的市场。也许你're将API响应包裹在一个SOAP主体中。也许你're从JSON内容导出生成RSS提要。在每种情况下,你't每次都想重新发明序列化- 你想要一个可预测的规则,它可以把任何JSON结构变成有效的XML,所以你可以自动化它,停止思考它。
There's也是一个更安静的原因:调试时的可读性当你're盯着一个深嵌套的JSON blob试图理解一个层次结构时,将其转换为缩进的XML有时会使树结构跳出,因为XML's打开/关闭标签使嵌套显式的方式JSON's大括号don't。I保留 JSON 到 XML 转换器 而反之 XML 到 JSON 转换器 I'd猜测的更频繁地在相邻选项卡中打开。
JSON 究竟如何映射到 XML?
Zhe里是它的核心,只有四个规则,其他的都是细Jie。
规则 1:对象键成为元素。 JSON 对象 { "book": { "title": "..." } } 变成 <book><title>...</title></book>。关键是标签名称;值是内部内容。
规则 2: @-前缀键成为属性。 XML元素可以携带属性,而JSON对它们没有原生概念,所以我们需要一个约定,广泛使用的一个- 我的工具使用的那个- 是一个前缀字符, @ 默认情况下。所以 { "book": { "@id": "bk101", "title": "..." } } 变成 <book id="bk101"><title>...</title></book>。属性只能保存原始值(字符串、数字、布尔值),永远不能嵌套结构,这与 XML 属性实际工作方式相匹配。
规则 3: #text key 变成文本内容。 当元素需要时 两者 属性和文本 - 思考 <title lang="en">Hello</title> -你可以't用一个普通的字符串值来表达,因为字符串没有给属性留下空间,约定是一个保留键, #text: { "title": { "@lang": "en", "#text": "Hello" } }.如果一个元素只有文本,没有属性,可以跳过 #text 并且仅使用纯字符串值。
规则 4:数组成为重复元素。 XML没有数组类型,一列事物表示为重复的同标签名同兄弟元素,这是人们最常出错的,所以 { "tags": { "tag": ["computer", "web"] } } 变成 <tags><tag>computer</tag><tag>web</tag></tags> - 不是 <tag>0</tag> or任何基于索引的废话。的数组's 键 提供重复的标签名称。
将它们放在一起放在一个现实的对象上,输出正是下游 XML 解析器所期望的:
{
"catalog": {
"book": [
{ "@id": "bk101", "author": "Gambardella, Matthew", "price": 44.95 },
{ "@id": "bk102", "author": "Ralls, Kim", "price": 5.95 }
]
}
}
变成
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<price>44.95</price>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<price>5.95</price>
</book>
</catalog>
请注意,单个顶级密钥, catalog,成为文档's根元素。that's刻意:一个格式良好的XML文档必须恰好有一个根,当你的JSON已经有一个单包裹键时,那个键 於 the root。don't时- 当你把转换器交给一个多键对象或一个裸数组时- 该工具将所有内容都包裹在一个可配置的根元素下(root 默认情况下),因此输出保持格式良好。
转义和无效的名字怎么样?
有两件事悄悄地打破了比任何嵌套错误更多的转换:未逃脱的特殊字符和非法元素名称。
逃跑。 XML 保留一小撮字符。内元素文本, &、 <、和 > 必须写为 &、 <、和 >.在一个双引号属性值内,你另外要把双引号转义为 "。如果您的 JSON 字符串包含 Tom & Jerry 然后你把它扔进 XML raw,裸露的安培数使文档格式错误,解析器就会死亡。正确的转换器会自动转义,因此 "a < b & c" 变成 a < b & c 在输出和解析时往返回原文。这不是可选的抛光 - it's有效和无效XML的区别。
元素名称。 XML对于标签名称可能包含什么有严格的规则,名称可以't包含空格,可以't以数字、连字符或句号开头,并排除大多数标点符号,JSON键没有这样的限制- "first name"、 "123"、和 "total($)" 是完全合法的JSON密钥和所有非法的XML名称,一个忽略此内容的转换器会产生任何解析器都不会接受的文档,务实的修复,以及我的工具所做的,是清理:用下划线替换非法字符,并在名称以数字开头时前面加上下划线所以 "123 bad" 变成 <_123_bad>。It's不迷人,但保证输出解析,就是整个点。
如何使用基于浏览器的转换器?
工作流程开启 Toolz.dev/tools/json-to-xml 反映了上述规则,并有一些实际边缘案例的选项。
JSON粘贴到输入中,按Convert,如果你的JSON格式错误,你得到一个清晰的解析错误而不是沉默的垃圾 - 我靠浏览器'自己的 JSON.parse(soap requests and feed payloads especials),所以错误消息与您'd在您的控制台中看到的内容相匹配,当您想要一个人类可读的文档进行审查时,选择2或4个缩进空格,或者选择Minify将整个内容折叠到单行上,当您'重新通过电线和每个字节计数(尤其是SOAP请求和馈送有效负载)。为您的JSON没有单个包装密钥的情况设置根元素名称。切换XML声明(<?xml version="1.0" encoding="UTF-8"?>) 开或关取决于消费者是否期望序言。并决定空节点是否应自闭为 <tag/> 或扩展到 <tag></tag> - 一些严格的消费者关心。
Everything运行客户端。转换器是一个用TypeScript编写的无依赖序列化器,而不是一个围绕远程API的包装器。这比听起来更重要:API响应和配置文件通常包含访问令牌,客户记录和内部标识符,以及一个"免费在线转换器",将您的有效负载发布给某人's服务器是一个等待发生的数据泄露。因为这个从来不进行网络调用,您可以安全地转换敏感数据,并且它一直工作,完全没有连接。如果浏览器工具中的隐私是您想到的 - 如果您处理其他人's数据,它应该是 - 我在其中写了更多关于它的信息 数据隐私工具指南。
JSON 与 XML:快速比较
它有助于保持两种格式'权衡,因为 原因 映射需要诸如此类的约定 @ 並 #text XML 是可以表达 JSON 可以表达的东西 't,反之亦然。
| 方面 | JSON | XML |
|---|---|---|
| 属性 | 没有本机概念 | 一流的(<tag attr="v">) |
| 数组/列表 | 本土 [ ] 类型 |
重复的兄弟元素 |
| 评论 | 不允许 | <!-- ... --> 支持 |
| 命名空间 | 没有 | 全名空间支持 |
| 混合内容(文本+元素) | 尴尬 | 本土 |
| 架构/验证 | JSON 架构(附加) | XSD、DTD、RELAX NG(成熟) |
| 冗长 | 紧凑 | 更多冗长(关闭标签) |
| 今天的典型用途 | Web API,配置 | SOAP、饲料、文件、企业 |
的 @ 前缀的存在是为了桥接 "属性"行;重复标签规则桥接"数组"行;和 #text 桥"混合内容"行。一旦你将映射视为跨越这些特定间隙的桥梁,它就不再感到任意了。
JSON 到 XML 往返是否干净?
大多数情况下,是的 - 以及设计的 's。我的 json 到 xml 並 XML 到 JSON 工具共享相同 @ 属性前缀和 #text content key,所以转换XML → JSON并返回一般都会重现原始文档,如果你're构建一个必须双向移动数据的管道,那么这种对称性就值得依赖。
Where round-tripping gets fuzzy is the same place each JSON/XML mapping gets fuzzy: order and mixed content。JSON objects are officially unordered, so a converster may not preserve excel sibling order of differently named elements。the interleveling text and child elements (<p>Hello <b>world</b>!</p>) does't有一个干净的JSON表示,并作为近似值返回。并且有时出现一次,有时出现多次的元素是模糊的-是单个值还是一个数组。这些都是't在任何特定工具中的错误;它们'是两个数据模型不't完美重叠的事实所固有的。知道接缝在哪里可以让你设计你的JSON,这样转换就保持无损:对事物是否始终是数组保持一致,并避免在可以的地方混合内容。
如果您经常使用 JSON,它'值得在整个转化系列中建立流畅性 - 我收集了我在转化中最能接触到的那些 JSON 工具的终极指南的,以及更广阔的 编码工具指南 涵盖格式转换器适合日常工作流程的位置。对于反向和相邻格式, JSON 到 YAML 转换器 还有一片平原 JSON 格式化程序 完善布景。
JSON 转换为 XML 时常见的错误
I've击中或看着其他人击中的几个陷阱:
将数组索引视为标签名称。 如果你看到 <item0>、 <item1> someone's输出中,他们构建了错误的转换器。阵列变成 重复 带有标签 同 name,取自数组's键。
忘记只能有一个根。 将多键对象直接交给序列化器而不包裹它会产生多个顶级元素,这不是一个格式良好的文档。包裹它。
跳过转义"因为数据看起来很干净。" 在一份产品说明中包含一个 ampersand 或 a 之前,它看起来很干净 <.永远逃避;永远不要假设。
将结构化数据放入属性中。 Attributes 持有原语。如果你尝试将嵌套对象推入一个 @-前缀键,一个正确的转换器将(并且应该)丢弃它或忽略它,因为那里's没有有效的XML为它。将其建模为子元素。
高级:为消费者选择缩进和声明
一个习惯让我与集成合作伙伴反复来回地挽救:匹配输出 完全正确 到消费者所期望的,然后停止。一些 SOAP 端点拒绝包含字节顺序标记或意外序言的文档;其他则要求 <?xml ... ?> declaration 和 415 you without it 有些提要验证器希望漂亮打印,缩进的 XML 用于自己的调试;大多数生产运输工具希望它最小化。我不是争论,而是生成规格要求的任何变体。that's 为什么转换器暴露缩进(包括最小化选项),声明切换和自我关闭行为作为一流的控制 - 他们're 不是装饰,他们're 确定挑剔的消费者是否接受您的文档的旋钮第一次尝试。
常问问题
如何将JSON转换为XML?
JSON粘贴到编辑器中,然后按Convert。对象键成为XML元素,数组成为重复标签,结果显示为可复制或下载的状态。没有上传 - 转换发生在您的浏览器中。
xml中的json属性是如何表示的?
按照惯例,任何以 "@" 前缀开头的对象键都写为其父元素上的属性,而不是子元素。例如,{"book": {"@id": "bk101", "标题": "..."}} 变为
转换器如何处理 JSON 数组?
数组的每个元素都作为共享密钥的重复兄弟元素发出's name。so {"标签": {"标签": ["a", "b"]}}产生
#text 密钥是干什么用的?
当元素同时需要属性和文本内容时,文本存储在"#text"键下。 {"标题": {"@lang": "en", "#text": "你好"}}变为
我可以获得缩小的 XML 而不是缩进输出吗?
是的。 将缩进设置为 0(缩进),转换器将整个文档发出在单行中,标签之间没有空白。 这对于有效负载大小很重要的 SOAP 请求或提要有用;当您需要可读文档时,切换回 2 或 4 个空格。
不是有效的 XML 元素名称的键会发生什么?
XML元素名称不能包含空格,不能以数字、连字符或句号开头,并排除大多数标点符号。违反这些规则的密钥将被清理 - 无效的字符成为下划线,并在需要时添加前导下划线 - 因此输出始终解析,即使您的JSON密钥不适合XML。
是否使用XML to JSON工具来执行JSON到XML的往返?
对于它所做的常见结构。该工具和 XML 到 JSON 工具共享相同的 "@" 属性前缀和 "#text" 内容密钥,因此将 XML 转换为 JSON 并返回通常会复制相同的文档。与订单无关的细节和混合内容是通常的小差异来源,就像任何 XML/JSON 映射一样。
在这里转换敏感的JSON是否安全?
是的。转换器是普通的 JavaScript,完全在您的浏览器中运行 - 您粘贴的任何内容都不会传输到服务器、记录或存储。这使得它对于包含令牌或个人数据的 API 响应、配置文件和记录来说是安全的,并且它可以在没有网络连接的情况下继续工作。



