← 全部文章

JSON vs YAML:区别与各自适合的场景

JSON 与 YAML 对比:语法、类型、注释,以及像 Norway problem 这类坑。YAML 是 JSON 的超集 —— 何时选哪个、如何相互转换。

JSON 和 YAML 解决的是同一个问题 —— 把结构化数据表示成文本 —— 但它们的取舍正好相反。JSON 为机器无歧义解析而优化;YAML 为人类编写而优化。从 YAML 1.2 开始,每一份合法的 JSON 文档也是合法的 YAML。本指南比较它们的语法、类型和特性,并说明何时该选哪个。

简短答案

程序之间交换的数据用 JSON —— API 响应、消息 payload、任何机器生成的东西。要人手写、手编辑的文件用 YAML —— CI pipeline、Kubernetes manifest、应用配置 —— 这些地方注释和可读性很重要。

并排语法对比

同样的数据,两种格式各写一遍:

# YAML
service: api
replicas: 3
ports:
  - 8080
  - 8443
env:
  LOG_LEVEL: info
  DEBUG: false
// JSON
{
  "service": "api",
  "replicas": 3,
  "ports": [8080, 8443],
  "env": {
    "LOG_LEVEL": "info",
    "DEBUG": false
  }
}

YAML 用缩进代替花括号和方括号,省掉了大多数引号,并允许注释。JSON 更啰嗦,但没有有意义的空白,这让它远比 YAML 更容易可靠地解析和生成。

YAML 是 JSON 的超集

从 YAML 1.2(2009)开始,YAML 是 JSON 的严格超集 —— 任何合法 JSON 文档都是合法 YAML,因为 YAML 直接采用了 JSON 的「flow」语法。所以你把 JSON 粘进 YAML 文件就能直接跑。背后的历史见 YAML 1.2 与 JSON 兼容性

# 这是合法 YAML —— 同时也是合法 JSON
{"service": "api", "replicas": 3}

特性比较

特性JSONYAML
注释有(#
尾随逗号不允许不适用(block 风格里没有逗号)
多行字符串只能用转义的 \n原生支持(|>
Anchor / 引用有(& / *
一个文件多个文档不支持支持(用 --- 分隔)
有意义的空白有(缩进有意义)
解析复杂度极简复杂
适合场景机器间数据交换人手编辑的配置

类型处理:YAML 的尖刺

YAML 急着推断类型,所以会出现 JSON 强制加引号能避开的意外:

# 「Norway problem」—— 在 YAML 1.1 解析器里这些会变布尔
countries:
  - NO   # → false (!)
  - SE
  - true # → 布尔,不是字符串 "true"

version: 1.20   # → 数字 1.2,末尾的零丢了
zip: 01234      # → 668(在某些解析器里被当成八进制)

JSON 完全没有这些歧义:"NO" 永远是字符串 NO"01234" 永远就是那个字符串。当一个 YAML 值必须是字符串时,请明确加引号。

TOML 和 JSON5 处在什么位置

另外两种常见的「对人友好」配置格式经常在同一个话题里出现:

  • TOML —— section/key 风格,专为人手编辑的应用配置设计(Cargo、Poetry、Hugo)。比 YAML 更严格,没有有意义的缩进,原生类型化的值(datetime、整数、浮点、数组、内联表)。当数据主要是扁平的表时最合适。
  • JSON5 —— 给开发者用的宽松 JSON:支持注释、尾随逗号、不带引号的 key、单引号、多行字符串。不是 标准 JSON 解析器能直接接受的;你要用 JSON5 库才行(或者用一个 JSONC 解析器,处理「注释 + 尾随逗号」子集,比如 tsconfig.json)。

大致的定位:机器间交换用 JSON;深度嵌套、人手编辑的配置用 YAML;扁平的应用 / 工具配置用 TOML;当你想要「带注释的 JSON」做编辑器配置又不想接受 YAML 的空白规则时,用 JSON5/JSONC

什么时候用哪个

  • 用 JSON:REST/GraphQL API、消息队列、浏览器 localStoragepackage.json、任何由代码生成或消费的东西。
  • 用 YAML:GitHub Actions / GitLab CI、Kubernetes 和 Docker Compose、Ansible playbook、需要人手编辑并写注释的应用配置。

一个常见模式:为可读性用 YAML 编写配置,然后在构建或加载时转成 JSON,让应用本身只解析 JSON。

在 JSON 和 YAML 之间转换

# Python —— YAML 转 JSON
import yaml, json
data = yaml.safe_load(open('config.yaml'))
print(json.dumps(data, indent=2))

# 用 yq 在命令行
yq -o=json '.' config.yaml      # YAML → JSON
yq -P '.' config.json           # JSON → YAML

或者用 fixjson 的 YAML ⇄ JSON 转换器 在浏览器里立刻转换 —— 贴 YAML 得到 JSON(或反过来),数据不会发到任何服务器。

常见问题

YAML 比 JSON 好吗?

没有哪个「更好」—— 它们是给不同活儿调过的。人手编辑的配置 YAML 更好(注释、可读性);机器间数据交换 JSON 更好(简单、快、解析无歧义)。

JSON 是合法 YAML 吗?

是。从 YAML 1.2 开始,YAML 是 JSON 的严格超集,所以任何合法 JSON 文档都是合法 YAML。反过来不成立 —— 大多数 YAML 不是合法 JSON。

为什么 YAML 把「NO」变成 false?

YAML 会从没引号的 scalar 推断类型,有些解析器会把 NOyesonoff 读成布尔(「Norway problem」)。给这个值加引号("NO")就能强制它是字符串。JSON 用强制引号完全避开了这个问题。

配置文件该用 YAML 还是 JSON?

需要人手编辑、需要注释和多行字符串就用 YAML;由工具生成或消费就用 JSON。很多团队用 YAML 编写,加载时转 JSON。

在浏览器里转换和校验