JSON 转 YAML 完全指南
JSON 与 YAML:语法对比
YAML(YAML Ain't Markup Language)和 JSON 都是数据序列化格式,YAML 实际上是 JSON 的超集——所有有效的 JSON 都是有效的 YAML。但两者的常用写法差异很大:YAML 使用缩进表示层级,不需要花括号和引号,支持注释,更面向人类阅读;JSON 则使用花括号和引号,结构严格,无注释,更适合机器解析和传输。
两种格式表达同样的数据:
// JSON
{
"name": "Alice",
"age": 30,
"roles": ["admin", "editor"],
"address": {
"city": "Beijing",
"country": "China"
}
}
# YAML
name: Alice
age: 30
roles:
- admin
- editor
address:
city: Beijing
country: China
JSON 转 YAML 的规则
理解转换规则有助于手动调整和验证转换结果:JSON 对象({})变为 YAML 的键值对形式,用缩进表示嵌套;JSON 数组([])变为 YAML 的列表项,每项前加 - ;字符串不一定需要引号(纯数字字符串、含特殊字符的字符串例外);数字、布尔值、null 直接写,不加引号;注释在 YAML 中用 # 表示,JSON 中不支持注释。
需要特别注意的转换陷阱:在 YAML 中,yes/no/true/false/on/off 都是布尔值,如果你的 JSON 字符串键恰好是这些词,转换为 YAML 后需要加引号。纯数字的 JSON 字符串(如 "123")转为 YAML 时必须保持引号,否则会被解析为整数。
命令行工具转换
yq 是专为 YAML 设计的命令行工具(类似 JSON 的 jq),支持 JSON 和 YAML 之间的互转:
# 安装 yq / Install yq
brew install yq # macOS
# 或 / or: snap install yq
# JSON 转 YAML / JSON to YAML
yq -p json -o yaml input.json > output.yaml
# YAML 转 JSON / YAML to JSON
yq -p yaml -o json input.yaml > output.json
# 从标准输入转换 / Convert from stdin
cat data.json | yq -p json -o yaml
# 使用 python 内置模块转换
# Convert using Python built-in modules
python3 -c "import sys,json,yaml; yaml.dump(json.load(sys.stdin), sys.stdout, allow_unicode=True)" < input.json
# 使用 nodejs 转换
# Convert using Node.js
node -e "const y=require('js-yaml'); const j=require('fs').readFileSync(0,'utf8'); process.stdout.write(y.dump(JSON.parse(j)));"
各语言的代码实现
# Python
import json
import yaml
# JSON 字符串转 YAML / JSON string to YAML
def json_to_yaml(json_str):
data = json.loads(json_str)
return yaml.dump(data, allow_unicode=True, default_flow_style=False)
# YAML 字符串转 JSON / YAML string to JSON
def yaml_to_json(yaml_str):
data = yaml.safe_load(yaml_str)
return json.dumps(data, ensure_ascii=False, indent=2)
// JavaScript (使用 js-yaml 库)
// JavaScript (using js-yaml library)
import yaml from 'js-yaml';
// JSON 对象转 YAML 字符串
function jsonToYaml(obj) {
return yaml.dump(obj, { indent: 2 });
}
// YAML 字符串转 JSON 对象
function yamlToJson(yamlStr) {
return yaml.load(yamlStr);
}
// Go (使用 gopkg.in/yaml.v3)
// Go (using gopkg.in/yaml.v3)
import (
"encoding/json"
"gopkg.in/yaml.v3"
)
func jsonToYaml(jsonBytes []byte) ([]byte, error) {
var obj interface{}
if err := json.Unmarshal(jsonBytes, &obj); err != nil {
return nil, err
}
return yaml.Marshal(obj)
}
YAML 在 DevOps 工具中的应用
YAML 在 DevOps 生态中无处不在,理解 JSON 与 YAML 的转换关系,有助于在这些工具之间灵活迁移配置:Kubernetes:所有资源配置(Deployment、Service、ConfigMap)都使用 YAML 格式,但 Kubernetes API 实际上接受 JSON,kubectl 会自动转换。GitHub Actions:工作流文件是 YAML 格式,理解其数据结构有助于调试复杂的工作流配置。Ansible:Playbook 和 inventory 文件使用 YAML,变量可以用 JSON 格式的字符串传递。Docker Compose:docker-compose.yml 是 YAML 格式。
# Kubernetes Deployment(YAML,等效于 JSON 格式的 API 调用)
# Kubernetes Deployment (YAML, equivalent to JSON-format API call)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
spec:
containers:
- name: app
image: my-app:latest
ports:
- containerPort: 8080
YAML 特有功能:锚点和引用
YAML 比 JSON 多出一些独特功能,其中最实用的是锚点(Anchor)和引用(Alias):使用 &anchor_name 定义一个锚点,用 *anchor_name 在其他地方引用它,从而避免重复定义。这在配置文件中特别有用——比如多个服务共享相同的基础配置:
YAML 还支持多行字符串(使用 | 保留换行,使用 > 折叠换行)、空文档分隔符(---)可以在一个文件中包含多个 YAML 文档(JSON 不支持这些特性)。这些功能在从 JSON 转换为 YAML 后可以手动添加,以充分利用 YAML 的表达能力。
# YAML 锚点和引用示例 / YAML anchor and alias example
defaults: &defaults
timeout: 30
retries: 3
logLevel: info
development:
<<: *defaults # 继承 defaults 的所有字段 / Inherit all defaults fields
debug: true
logLevel: debug # 覆盖继承的字段 / Override inherited field
production:
<<: *defaults
replicas: 10
ssl: true
转换时的常见陷阱
布尔值陷阱:YAML 1.1 将 yes/no/on/off/true/false 都解析为布尔值,但 YAML 1.2(更严格)只有 true/false。确保使用的 YAML 库版本支持的规范,并对可能被误解析的字符串加引号。
八进制数字陷阱:在 YAML 1.1 中,以 0 开头的数字被解析为八进制(如 010 被解析为 8)。如果 JSON 中有类似格式的字符串 ID(如 "0123456789"),转换后要确保它们带引号。
空字符串陷阱:JSON 的 "" 在 YAML 中需要写成 "" 或 '',不能省略引号(因为省略引号的空值在 YAML 中被解析为 null)。
缩进敏感性:YAML 对缩进极为敏感,混用 Tab 和空格会导致解析错误。始终使用空格(推荐 2 个空格)进行缩进。
立即免费使用相关工具
免费使用 →