JSON 转 XML、YAML 该选哪个?互转会丢的三样东西

2026-11-05约 10 分钟JSON 工具涉及 5 个工具

同一份数据写成 JSON、XML、YAML,转过去再转回来往往已经不是原来那份 —— 数字变字符串、注释消失、列表被摊平。这篇按「会丢什么」来选格式,而不是按语法好不好看。

核心要点
  • XML 不带类型,文本转回 JSON 全是字符串:<age>20</age> 得到 "20",硬猜会毁掉 007 这类值
  • YAML 的反向解析是子集实现,多行块标量(管道符)、锚点、流式写法都会静默降级成字面量,而不是报错
  • JSON 键名不一定能当 XML 标签名,含空格、数字开头、带 & 的键会生成非法 XML,工具不做改名以避免篡改数据
  • 三种格式表达列表各有做法:XML 用同名重复标签、YAML 用短横线、JSON 用方括号,这是互转时唯一不会丢的结构
  • JSON 压缩是解析后重新序列化,不是删空白:1.0 变 1、1e3 变 1000、超过 2^53 的整数会丢精度

#三种格式各自会丢什么

互转丢信息的根源不是工具写得差,而是三种格式的表达能力本来就不一样。 丢掉的东西集中在三处:类型、注释、以及列表的表达方式。

JSON 只有六种类型(对象、数组、字符串、数字、布尔、null),XML 只有「元素 + 文本 + 属性」,YAML 看起来最自由、但能被安全解析的子集其实很窄。所以「转过去」永远比「转回来」容易。

从 → 到会丢什么能不能救
JSON → XML数字与布尔的类型(都变文本)、null 的具体含义转回来时按字段名手工还原
XML → JSON属性变 @键,混合内容里的散落文本会丢只保留子元素,文本需要单独取
JSON → YAML一般不会丢,但空值写法可能变用引号区分 "true" 与 true
YAML → JSON多行块、锚点、合并键、标签会静默降级,必须先确认语法范围

#JSON 转 XML:文本一律变字符串

从 XML 转回 JSON 时,所有文本都是字符串,工具不做任何类型推断。 <age>20</age> 得到 "20",<ok>true</ok> 得到 "true"。

这不是偷懒。XML 本身不携带类型信息,硬猜一定会在某些值上出错:007 会被猜成 7(丢了前导零,工号、航班号立刻错),1.0 会被猜成 1,而 1.10 到底是版本号还是数字无法判断。宁可全给字符串,让调用方按自己的 schema 转换。

用 JSON 转 XML 时还有两条固定规则:

  • 根标签固定是 <root>,对象的键直接做标签名
  • 数组里每个元素生成一个同名重复标签,而不是 <item index="0"> 这种带下标的容器 —— 后者在 XML 里没有通用约定

反过来(XML → JSON)也有三条固定映射:属性变成 @ 前缀的键(<book id="1"> → "@id": "1")、同名兄弟标签合并成数组、只有属性没有子元素的节点把文本放进 #text。这样往返能还原,不丢信息。

注意

JSON 的键名不一定能当 XML 标签名。 含空格、以数字开头、或者带 &、< 这类字符的键会生成非法 XML。工具不会替你改名 —— 改名等于篡改数据,改了你就认不出原字段。遇到这种结构,先把键统一成下划线或驼峰形式,或者干脆改用 YAML,YAML 对键名没有这类限制。

#JSON 转 YAML:可读性最好,但解析器是子集

这个工具能把 JSON 转成 YAML,反向解析用的是自举的子集实现,不是完整 YAML 解析器。 支持块映射、块序列、按缩进嵌套、整行 # 注释、单双引号字符串、--- 与 ... 文档标记。

不支持的语法会静默降级,这是最需要留意的地方:

YAML
# 输入:Kubernetes、GitHub Actions 里常见的多行块
command: |
  npm install
  npm test

用 JSON 转 YAML 的 YAML → JSON 方向解析上面这段,得到的是 "command": "|",紧跟的缩进块整体被跳过。不报错,只是结果残缺 —— 比报错更危险。

除了多行块,锚点与引用(& *)、合并键 <<、流式写法({a: 1}、[1, 2])、标签(!!str)也都不支持。拿现成的 CI 配置来转换之前,先确认目标文件里没有这几样。

还有两个类型细节:yes / no / on / off 在 YAML 1.1 里是布尔,这里按字符串处理;行尾注释 key: value # 说明 不会被剥掉,会连同 # 一起进值里。注释请单独占一行。

技巧

YAML 转 JSON 之后发现某个值多了一串 # xxx,那不是 bug,是行尾注释被当成值的一部分。把注释挪到单独的上一行再转一次即可。

#XML 美化与压缩:注释留不留取决于你点哪个

用 XML 格式化 时,「注释会不会留下」取决于点的是美化还是压缩。 压缩会整段丢弃注释(省字节的常规做法),CDATA、DOCTYPE、处理指令保留;美化则原样保留注释。

美化用 2 个空格缩进,元素里只有一段短文本时保持 <title>x</title> 同行,不硬拆成三行。

识别则按 token 严格走:

  • CDATA → 注释 → 处理指令 <? ?> → DOCTYPE → 普通标签
  • 标签内部的单双引号都受保护,所以属性值里出现 > 不会把标签截断

用正则「查找替换」重排 XML 最容易翻车的地方正是这里 —— 一条 s/></>\n</g 就会把属性里的 > 也换掉。

注意

纯数据 XML 无所谓,但混合内容会被改写:<p>你好 <b>世界</b></p> 里那个空格可能被吃掉,排版敏感的 XHTML 别用它重排。另外本工具只做排版,不检查标签是否闭合;要确认一段 XML 是否合法,用 JSON 转 XML 的 XML → JSON 方向解析一次,它走浏览器原生解析器,语法错误会直接报出来。

#改完再看一眼结构

转完格式之后,用眼睛确认一遍层级比读一遍输出文本快得多。 用 JSON 视图查看器 展开节点,默认展开到第 3 层,顶部有展开全部 / 折叠全部,状态栏会给出节点总数与最大嵌套深度。

它只读:不能编辑、不能导出。要改内容请回到 JSON 格式化校验,改完再回来查看。节点是用 textContent 建的,JSON 里含 <script> 这类字符串时只会原样显示成文本、不会被执行,粘贴来源不明的结构是安全的。

说明

节点数上万时渲染会明显变慢,因为所有节点是一次性建进 DOM 的、没有虚拟滚动。这种情况先折叠大数组,或者把要看的字段裁出来单独看。

如果目标是把体积压到最小,用 JSON 压缩转义。注意它的「压缩」不是删空白,而是 JSON.parse 之后重新序列化。

后果是具体的:1.0 变 1、1e3 变 1000、重复键只留最后一个,超过 2^53(9007199254740992)的整数会按双精度近似 —— 18 到 19 位的雪花 ID、订单号会变成另一串数字。压这类数据前先确认字段本来就是字符串。

#什么时候该用哪个工具

你想做的事用哪个要注意
把 JSON 给 Java / 老系统用JSON 转 XML键名必须是合法标签名
写配置文件、给 K8s 或 CI 用JSON 转 YAML反向解析不支持 `\` 多行块
整理别人给的 XMLXML 格式化压缩会丢注释
看一份大 JSON 的层级JSON 视图查看器节点上万时会变慢
把 JSON 塞进日志或代码字符串JSON 压缩转义会重新序列化,大整数丢精度
只是想校验和美化 JSONJSON 格式化校验报错会给出行列位置

选格式的顺序建议反过来问:下游系统能读什么,就用什么。 内部服务之间传数据,JSON 足够;要给配置管理工具或人读,YAML 更合适;要和遗留系统、SOAP 接口、Office 文档打交道,只能是 XML。

#常见问题

#JSON 转 XML 后数字怎么变成字符串了?

XML 里没有独立的数字类型,元素内容都是文本。转回 JSON 时工具不猜类型,所以 20 变成 "20"。如果你的下游需要数字,在消费端按 schema 转一次,不要指望往返自动保持一致 —— 让工具硬猜会毁掉 007 这种带前导零的值。

#YAML 里的 | 和 > 是什么?为什么转不了?

它们是 YAML 的多行块标量标记:| 保留换行(每行原样),> 折叠换行(把多行并成一段)。这两种写法需要真正的 YAML 解析器才能处理,而 JSON 转 YAML 的反向方向是子集实现,遇到时会把 | 本身当成字符串值,后面的缩进块被跳过。

#为什么 JSON 压缩后我的 ID 变了?

因为压缩是解析后重新序列化。JSON 规范里数字就是双精度浮点,超过 2^53 的整数无法精确表示,1234567890123456789 会变成 1234567890123456800。雪花 ID、订单号这类值应该在接口里就用字符串传,而不是靠压缩工具回避。

#XML 压缩后注释没了,能恢复吗?

不能。压缩时注释是整段丢弃的,产物里没有任何痕迹。要保留注释就用美化方向,或者压缩前自己留一份原文。

#三种格式互转,哪种最不容易出问题?

JSON ↔ YAML 之间最平滑,因为两者都是「对象 / 数组 / 标量」这套模型,差异主要在写法。涉及 XML 时必然要面对「元素还是属性」「文本无类型」这两个结构性差异,往返一次一定会丢信息,能不做往返就别做。

本文提到的工具

相关文章