YAML vs JSON:语法对比与互转技巧
YAML 和 JSON 是现代开发中最常用的两种数据序列化格式。JSON 在 API 通信中占据主导,而 YAML 则是配置文件的首选。本文将深入对比两者的语法差异、各自优势,并教你如何在它们之间灵活转换。
基础语法对比
先通过一个实际例子直观感受两种格式的差异:
YAML
# 用户信息配置
name: 张三
age: 28
active: true
address: null
skills:
- JavaScript
- Python
- Go
contact:
email: zhangsan@example.com
phone: "138-0000-0000"
JSON
{
"name": "张三",
"age": 28,
"active": true,
"address": null,
"skills": [
"JavaScript",
"Python",
"Go"
],
"contact": {
"email": "zhangsan@example.com",
"phone": "138-0000-0000"
}
}
核心差异总结
| 特性 | YAML | JSON |
|---|---|---|
| 分隔符 | 缩进(空格) | 花括号 {} 和方括号 [] |
| 引号 | 字符串通常不需要引号 | 键名和字符串必须双引号 |
| 注释 | ✅ 支持(#) | ❌ 不支持 |
| 多行字符串 | ✅ 支持(| 和 >) | ❌ 只能用 \n 转义 |
| 锚点/引用 | ✅ 支持(& 和 *) | ❌ 不支持 |
| 多文档 | ✅ 支持(--- 分隔) | ❌ 不支持 |
| 数据类型 | 自动推断(可能有歧义) | 明确的类型标记 |
| 可读性 | ⭐⭐⭐ 更简洁 | ⭐⭐ 结构清晰但冗长 |
| 解析性能 | 较慢 | 更快 |
| 主要用途 | 配置文件 | API 通信、数据交换 |
YAML 独有特性
1. 注释
YAML 支持行内和单行注释,这是它在配置文件领域碾压 JSON 的主要原因:
# 数据库配置
database:
host: localhost # 开发环境使用本地
port: 5432 # PostgreSQL 默认端口
name: myapp_dev
# password: secret # 已移至环境变量
2. 多行字符串
YAML 提供两种多行字符串语法:
# | (Literal Block): 保留换行符
description: |
这是第一行
这是第二行
这是第三行
# 等价 JSON: "这是第一行\n这是第二行\n这是第三行\n"
# > (Folded Block): 换行变为空格
summary: >
这是一段很长的文本,
会被折叠成一行,
换行符变为空格。
# 等价 JSON: "这是一段很长的文本, 会被折叠成一行, 换行符变为空格。\n"
3. 锚点与引用
YAML 的锚点(&)和引用(*)可以复用配置,避免重复:
# 定义默认配置锚点
defaults: &defaults
adapter: postgres
host: localhost
port: 5432
# 引用并覆盖
development:
database:
<<: *defaults # 合并 defaults 的所有键值
name: myapp_dev
production:
database:
<<: *defaults
host: db.example.com # 覆盖 host
name: myapp_prod
💡 提示:锚点和引用在大型配置文件中非常有用,比如 Docker Compose 的服务定义、CI/CD 流水线配置等。
4. 多文档支持
# 第一个文档
---
name: app-frontend
version: 2.1.0
# 第二个文档
---
name: app-backend
version: 3.0.1
YAML 的常见陷阱
类型推断歧义
YAML 自动推断数据类型,这可能导致意外的结果:
# 这些值的实际类型可能出乎意料
version: 1.0 # 浮点数 1.0,不是字符串 "1.0"
country: NO # 布尔值 false(挪威国家代码!)
zip: 01onal # 八进制数(某些解析器)
time: 12:30 # 某些解析器会解析为数字 750
# 解决方案:用引号强制字符串
version: "1.0"
country: "NO"
zip: "01234"
⚠️ 挪威问题:这是 YAML 社区著名的 bug。在 YAML 1.1 中,
NO、no、off 会被解析为布尔值 false。YAML 1.2 修复了部分问题,但仍需注意。建议敏感值始终加引号。
缩进敏感
# ❌ 错误:混用 Tab 和空格
database:
host: localhost # Tab 缩进!YAML 不允许
# ✅ 正确:统一使用空格(推荐 2 个)
database:
host: localhost
port: 5432
互转方法
YAML → JSON(Python)
import yaml
import json
with open("config.yaml") as f:
data = yaml.safe_load(f)
json_str = json.dumps(data, indent=2, ensure_ascii=False)
print(json_str)
JSON → YAML(Python)
import yaml
import json
with open("data.json") as f:
data = json.load(f)
yaml_str = yaml.dump(data, allow_unicode=True, default_flow_style=False)
print(yaml_str)
命令行转换
# 使用 yq 工具(需安装)
# YAML → JSON
yq -o=json config.yaml
# JSON → YAML
yq -P data.json
# 使用 Python one-liner
python3 -c "import sys,yaml,json; print(json.dumps(yaml.safe_load(open(sys.argv[1])),indent=2))" config.yaml
如何选择?
- 选 YAML:人工编辑的配置文件、需要注释、Docker Compose、Kubernetes、GitHub Actions
- 选 JSON:API 响应/请求、程序间数据交换、package.json、需要严格类型
- 选 TOML:简单的配置文件(如 Cargo.toml、pyproject.toml)
💡 实际建议:在同一个项目中保持一致。如果团队习惯 YAML 就统一用 YAML,习惯 JSON 就统一用 JSON。混用反而增加认知负担。
🛠️ 在线 YAML 格式化与 JSON 互转工具
打开 YAML 工具 →延伸阅读
- JSON 格式化完全指南 — 深入了解 JSON 语法规则
- Base64 编解码详解 — YAML 中嵌入二进制数据
- 时间戳转换指南 — YAML 和 JSON 中的日期时间处理