XML 转 JSON

在浏览器里把 XML 文档转换成 JSON。属性以 @ 前缀键保留,重复元素自动折叠成数组,数字、布尔和 null 的类型推断可按需开启。

把 XML 读成它本来就想成为的对象树。 粘贴一份 XML 文档即可得到 JSON。属性以 @ 前缀键保留,重复元素折叠成数组,类型推断默认关闭,因此编号前面的 0 不会丢。

JSON 输出

每个 XML 转 JSON 工具都必须回答的三个问题

属性没有天然的落脚点

XML 在属性和子元素之间划了一条硬线。<user id="7"><name>Ada</name></user><user><id>7</id><name>Ada</name></user> 表达的是不同的东西,尽管多数应用会一视同仁地处理它们。JSON 里没有对应的区分,所以转换器要么丢掉属性,要么给它们造一个位置。

被广泛使用、本工具也采用的约定是:属性键加 @ 前缀;当一个元素同时带属性和文本时,文本存放在 #text 键下。于是上面第一个例子变成 {"user": {"@id": "7", "name": "Ada"}}。这个前缀并不属于任何标准,但足够常见,多数下游代码都认得,而且它让转换保持可逆。如果你确定这些属性只是用不上的元数据,关掉它可以得到更干净的输出。

是一个条目,还是只有一项的列表?

这是一个没有正确答案的问题。在 XML 里,只有一个 <item> 子元素的父节点和有五个的父节点结构上看起来差不多,但它们分别应该变成一个对象和一个数组——而文档本身完全没有透露 schema 的本意。没有 schema 的工具只能从看到的内容去猜。

这里的规则是:同名的兄弟元素折叠成数组,孤零零的元素保持为单个值。阅读时这符合直觉,但也意味着消费输出的代码必须同时处理两种形态,因为一个今天恰好只有一条记录的列表会产出对象而不是单元素数组。如果消费端在你手里,遍历前先用 [].concat(value) 之类的写法归一化。

XML 里的一切都是字符串

没有 schema 的 XML 文档里不存在类型。<count>42</count><sku>0042</sku> 都只是文本,只有人或者一份 XSD 才知道前者是数字、后者是必须保留前导零的编号。

这正是类型推断做成复选框而不是默认行为的原因。开启后,只有往返完全一致的值才会被转换——数字字符串只有在重新格式化后文本完全相同时才转成数字,这就保护了 0042+71e999truefalse 和空元素会变成布尔值和 null。关闭时所有值保持字符串,这对编号、电话号码、邮编以及任何超过 2^53 的整数都更安全,否则 JavaScript 的数字精度会悄悄改掉这些值。

开源说明:使用原生 JavaScript 实现,不依赖第三方库。

常见问题

我的 XML 会被上传吗?
不会。解析使用浏览器内置的 DOMParser,JSON 也在本地生成,文档不会离开这个页面。
属性是怎么表示的?
作为加了 @ 前缀的键,与子元素并列。如果一个元素同时有属性和文本,文本会存放在 #text 键下。
为什么单个元素没有变成数组?
没有 schema 就无法判断一个子元素代表单个值还是只有一项的列表。同名重复元素会变成数组,孤立元素保持为单个值。
类型推断做了什么?
把数字、布尔和空值从文本转换过来。数字只有在往返完全一致时才转换,所以 0042 和 +7 仍然是字符串。
什么时候应该关掉类型推断?
处理编号、电话号码、邮编以及超过 2^53 的整数时都应该关掉,否则 JavaScript 的数字精度会无声地把值四舍五入。
为什么提示 XML 无效?
说明文档不是格式良好的:常见原因是标签未闭合或不匹配、出现未转义的 & 或 <、或者存在多个根元素。