关于 JSON 转 YAML / TOML
JSON 转 YAML 与 TOML 工具会解析一份 JSON 文档,再把它重新输出为 YAML 或 TOML,与原文并排显示,让你不必重新敲一遍就能把配置在几种格式之间搬运。转换是结构性的 —— 键、嵌套和顺序都会保留 —— 但三者的类型系统并不相同,真正要做的功课是检查「哪里变了」。
这三种格式在映射、列表、字符串、数字和布尔值上取得了一致,在其余几乎所有地方都不一致。JSON 只有一种数字类型,没有注释、没有日期,也没有任何表达引用的办法。YAML 补上了注释、锚点和块标量,同时 —— 取决于你的读取方实现了规范的哪个版本 —— 还带来一套隐式类型规则,能毫不犹豫地把字符串变成布尔值。TOML 提供了真正的日期时间类型和严格的表模型,却完全没有 null。所以「转换成功」只是起点:输出在目标格式下语法正确,但它是否还表示同一件事,取决于下一个读它的解析器。
如何使用这个开发者工具
- 把合法 JSON 粘贴到左侧面板。文档会先被解析,因此语法错误会在任何转换开始之前就报出来。
- 把格式开关切到 YAML 或 TOML。点击转换后右侧面板给出结果,复制按钮会取走整段输出。
- 读输出时要看隐式类型,而不是看排版。凡是「去掉引号后可能被当成布尔值、数字、日期或时间」的值,都要逐个过一遍。
- 转 TOML 时,把输出的键数量和输入对一对。值为 null 的键在输出里根本不会出现,因为 TOML 没有 null。
- 在提交之前,用真正会消费它的加载器解析一遍结果 —— PyYAML、SnakeYAML、go-yaml、tomllib。这趟往返才是唯一真正的证明。
实例:现场演示「挪威问题」
六个再普通不过的配置值转成 YAML。输出是合法且正确的 —— 前提是按 YAML 1.2 来读。换成 YAML 1.1 的解析器,六个里有三个会变类型。
{
"country": "no",
"version": "1.10",
"release": "2026-09-21",
"window": "12:30",
"replicas": 5432,
"tls": { "enabled": false, "ca": null }
}country: no
version: "1.10"
release: 2026-09-21
window: 12:30
replicas: 5432
tls:
enabled: false
ca: null输出器给 "1.10" 加了引号,因为不加引号它就是浮点数 1.1;但它没给 country、release、window 加引号,因为在 YAML 1.2 的 core schema 里这三个都是普通字符串。把同一个文件交给 PyYAML、SnakeYAML 或 gopkg.in/yaml.v2 —— 它们实现的都是 YAML 1.1 —— country 会变成布尔值 false,release 会变成日期对象,window 会变成整数 750,也就是 12 个 60 加 30,因为 YAML 1.1 有六十进制整数。
三种格式各自能表达什么
把它当兼容性矩阵来读:三列不一致的那几行,正是转换可能悄悄改变语义的地方。
| 能力 | JSON | YAML | TOML |
|---|---|---|---|
| 注释 | 完全没有 | # 到行尾 | # 到行尾 |
| 空值 | null | null、~ 或留空 | 没有 null 类型;值为 null 的键会从输出里被丢掉 |
| 数字 | 只有一种数字类型,即 IEEE 754 双精度 | 区分整数与浮点数 | 区分整数与浮点数;5_432 是合法整数,也是本工具实际输出的写法 |
| 日期与时间 | 没有,日期只能是字符串 | 1.1 有时间戳类型;1.2 core schema 下是普通字符串 | 一等公民:带偏移日期时间、本地日期时间、本地日期、本地时间 |
| 多行字符串 | 只能用 \n 之类的转义 | 块标量 | 与 > | 三引号 """ 与 ''' |
| 顶层值 | 任意值,包括数组 | 任意值,包括序列 | 必须是表;顶层数组根本写不出来 |
| 重复键 | 接受,最后一个静默胜出 | 1.2 中是错误,但老解析器会保留最后一个 | 错误 |
| 混合类型数组 | 允许 | 允许 | 本工具所用的写出器会拒绝 |
| 含点号的键 | 普通键 | 普通键 | 必须加引号,因为裸点号表示嵌套 |
| 文档内复用 | 没有 | 用 & 定义锚点、用 * 引用 | 没有 |
常见问题排查
一个字符串值到了应用那边变成了布尔值、日期或数字。
成因 YAML 1.1 的隐式类型。no、yes、on、off 是布尔值,2026-09-21 是时间戳,12:30 是六十进制整数 750。本工具的输出器遵循 YAML 1.2,没有这些规则,所以不给这些值加引号。
解决办法 把文件交给 YAML 1.1 解析器之前,先给所有「可能被读成别的类型」的值加上引号 —— 而市面上大多数解析器正是 1.1:PyYAML、SnakeYAML、gopkg.in/yaml.v2 都是。常见受害者包括国家代码、版本号、时间,以及被人随手写成 y 或 n 的值。
TOML 输出里少了一些键。
成因 TOML 没有 null。JSON 里值为 null 的键在 TOML 中没有任何可写的形式,写出器选择整个省略这个键,而不是替你编造一个值。
解决办法 转换之前先想清楚这个配置项的 null 意味着什么。要么从 JSON 里删掉这个键,让「缺失」成为一个明确的表态;要么把 null 换成应用本来会使用的真实默认值。
TOML 转换直接失败。
成因 常见有两种原因。TOML 文档必须是一个表,因此顶层是数组的 JSON 根本写不出来。另外写出器会拒绝元素类型不一致的数组,于是 [1, "two", {"three": 3}] 会让转换中止。
解决办法 把顶层数组包进一个对象,给它起个有意义的键名。遇到混合数组,要么拆成若干个类型一致的键,要么改转 YAML —— YAML 没有这条限制。
版本号在下游莫名其妙少了一位。
成因 不加引号时,version: 1.10 在任何 YAML 版本里都是浮点数 1.1;1.10.2 之所以是字符串,仅仅因为它有两个点。补零的值也会踩同一个坑:build: 007 是整数 7。
解决办法 版本号、构建号、邮编、电话号码和各类标识符,一律加引号,没有例外。本工具在输出时会替你加上,但之后手动编辑这个文件的人不会。
适合用这个工具的场景
- 把已有的 JSON 配置搬进以 YAML 为主的工具里,比如 Kubernetes、GitHub Actions 或 Docker Compose。
- 用手头已有的 JSON 数据,为 Rust、Python 或 Hugo 项目生成一份 TOML 起始文件。
- 把层层嵌套的文档看得更清楚 —— YAML 的缩进和 TOML 的表都比大括号更容易扫读。
- 在提交之前确认:哪些值如果不加引号,会被 YAML 解析器重新解读。
应该换用别的工具的场景
- 校验 JSON 本身。请先粘进 JSON 格式化与校验工具,它会报出语法错误的精确偏移量。
- 反向转换。YAML 和 TOML 都带有注释、锚点、日期、多行标量这些 JSON 没有对应物的构造,因此往返本身就是有损的。
- 检查结果对你的应用是不是一份合法配置。转换器校验的是格式而不是 schema;必填键和跨字段规则属于应用自己的加载器。
隐私与数据处理
解析和输出都在当前浏览器标签页内完成,用的是随页面一起打包的 YAML 与 TOML 库;文档不会上传,标签页关闭后也不留存。配置文件是最容易出现明文数据库口令的地方,粘贴前请换成占位符;另外请记住,输出面板对屏幕共享的观众来说和输入面板一样清晰可读。
相关开发者工具
常见问题
我的注释会被保留吗?
本来就没有注释可保留。JSON 没有注释语法,所以从 JSON 源头里什么都恢复不出来。请在决定文件将落在哪里之后再加注释;从那一刻起,把那个文件而不是 JSON 当作事实来源。
输出针对的是哪个 YAML 版本?
YAML 1.2 及其 core schema,输出器的加引号策略正是照着它来的。1.2 是现行规范,但实际部署中相当大一部分解析器仍然实现 1.1,而 1.1 多出一批隐式类型。搞不清读取方时,请按防御性原则加引号。
为什么 TOML 写的是 5_432 而不是 5432?
下划线是 TOML 整数里合法的数位分隔符,写出器为了可读性会插入它。所有符合规范的解析器都会忽略下划线,因此这个值精确等于 5432。如果下游工具读不了,那它就不符合 TOML 规范。
键的顺序会保留吗?
会,输出遵循解析后 JSON 对象的顺序。TOML 还会额外把嵌套对象提升成 [table] 小节,排在父级标量键之后 —— 这是格式的要求而不是工具的选择,因此文件读起来的顺序会和 JSON 略有不同。
超大整数会怎样?
它们在转换器运行之前就已经受损了。JSON 数字按双精度解析,所以 9007199254740993 在解析阶段就变成了 9007199254740992。请把大标识符在 JSON 里序列化成字符串,这样它们在 YAML 和 TOML 中都会以带引号的字符串存活下来。
能转换顶层是数组的 JSON 吗?
转 YAML 可以,它会变成一个序列。转 TOML 不行:TOML 文档就是一个表,裸列表没有地方安放。请把数组包进一个对象、配一个有描述性的键名 —— 反正生成的 TOML 本来也需要这么一个键。