跳到主要内容
数据处理2026-06-01Begin12 分钟阅读

YAML JSON 转换完全指南:原理、工具与实战避坑

什么是 YAML 和 JSON

在现代软件开发中,数据序列化格式无处不在。YAML 和 JSON 是两种最常用的结构化数据表示格式,它们各有特点,适用于不同的场景。

YAML 的定义和特点

YAML(YAML Ain't Markup Language)是一种人类友好的数据序列化标准,由 Clark Evans 于 2001 年首次提出。它的设计目标是让数据既易于人类阅读和编写,又便于机器解析和生成。

YAML 的核心特点:

  • 可读性强:使用缩进表示层级结构,类似 Python 的语法风格
  • 简洁语法:不需要引号、大括号等冗余符号
  • 丰富的数据类型:支持字符串、数字、布尔值、日期、空值、列表、字典等
  • 高级特性:支持锚点(&)、别名(*)、多行字符串、复杂键等
  • 注释支持:可以使用 # 添加注释,方便文档化

一个简单的 YAML 示例:

name: ToolVault
description: 开发者在线工具集
version: 2.0
features:
  - 格式转换
  - 编码解码
  - 文本处理
  - 加密哈希
is_free: true
founded: 2024-01-15

JSON 的定义和特点

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,由 Douglas Crockford 在 2001 年左右推广。把 API 返回的 JSON 转成 YAML 配置时,JSON 转 YAML 工具很常用。它源于 JavaScript 语言,但现在已经成为几乎所有编程语言都支持的通用格式。

JSON 的核心特点:

  • 语法简洁:使用大括号 {} 和方括号 [] 表示结构
  • 机器友好:解析速度快,几乎所有语言都有原生支持
  • 数据类型有限:支持对象、数组、字符串、数字、布尔值、null
  • 无注释:标准 JSON 不支持注释
  • 严格格式:键名必须用双引号,字符串必须用双引号

同样内容的 JSON 示例:

{
  "name": "ToolVault",
  "description": "开发者在线工具集",
  "version": 2.0,
  "features": ["格式转换", "编码解码", "文本处理", "加密哈希"],
  "is_free": true,
  "founded": "2024-01-15"
}

两者的关系和区别

YAML 和 JSON 有着密切的关系:JSON 在语法上是 YAML 1.2 的子集,也就是说,几乎所有合法的 JSON 都是合法的 YAML。这就是为什么 YAML 解析器通常可以直接解析 JSON 数据。

但有一个常被忽略的前提:这句话只在 YAML 1.2 的 JSON schema 下严格成立。像 {"flag": on} 这样的 JSON 输入,在 YAML 1.1 式解析器里 on 会被当成布尔值 true——语法是子集,标量解释不一定。后文「YAML 1.1 vs 1.2」一节会详细展开。

但反过来,YAML 的许多特性在 JSON 中并不存在,比如注释、锚点、多行字符串等。

为什么需要 YAML JSON 转换

在实际开发中,YAML 和 JSON 之间的转换是非常常见的需求。以下是几个典型的应用场景。

配置文件场景

YAML 因其良好的可读性,被广泛用作配置文件格式:

  • Kubernetes:所有资源定义(Deployment、Service、ConfigMap 等)都使用 YAML
  • Docker Compose:容器编排配置文件 docker-compose.yml
  • Ansible:自动化运维的 Playbook 使用 YAML 编写
  • GitHub Actions:CI/CD 工作流配置
  • OpenAPI/Swagger:API 文档规范通常用 YAML 编写

而这些配置工具的内部实现,往往是先把 YAML 解析成 JSON 结构再进行处理。

API 数据交换

在 Web API 领域,JSON 是事实上的标准数据交换格式。当你需要:

  • 把 YAML 配置的内容通过 API 发送给后端
  • 将 API 返回的 JSON 数据保存为 YAML 配置文件
  • 在支持 YAML 的工具和支持 JSON 的系统之间传递数据

这些场景都需要进行格式转换。

前后端协作

前端开发者通常更熟悉 JSON,而后端或运维工程师可能更习惯用 YAML 编写配置。在团队协作中,经常需要:

  • 后端提供 JSON 格式的 API 响应,前端需要转为 YAML 做配置
  • 运维用 YAML 写配置,开发需要转为 JSON 在代码中使用
  • 技术文档中同时提供两种格式的示例

YAML vs JSON 对比

让我们通过一个详细的对比表,来全面了解这两种格式的差异。

语法对比表格

特性YAMLJSON
语法风格缩进表示层级大括号和方括号
注释支持(#)不支持
字符串引号可选,大多数情况不需要必须使用双引号
键名引号可选必须使用双引号
多行字符串原生支持(`、>`)
数据类型丰富(日期、时间、空值等)有限(6 种基本类型)
锚点/别名支持(&、*)不支持
文件扩展名.yaml / .yml.json
人类可读性高中等
解析速度相对较慢快
语言支持需要第三方库大多数语言原生支持

各自的优势和适用场景

YAML 的优势:

  • 更适合人类阅读和编写
  • 支持注释,便于文档化
  • 多行字符串处理更自然
  • 可以用锚点和别名减少重复
  • 适合作为配置文件格式

JSON 的优势:

  • 解析速度更快
  • 几乎所有编程语言原生支持
  • 语法严格,不容易产生歧义
  • 适合作为 API 数据交换格式
  • 工具生态更完善

一句话总结:配置文件用 YAML,数据交换用 JSON。

YAML 转 JSON 的方法

下面介绍几种常见的 YAML 转 JSON 方法,从最简单的在线工具到命令行和代码实现。

在线工具转换

最快捷的方式是使用在线转换工具,无需安装任何软件。

使用 ToolVault 工具匣 YAML JSON 转换工具:

  1. 在左侧输入框粘贴 YAML 内容
  2. 右侧自动实时显示转换后的 JSON
  3. 点击复制按钮即可获取结果

这种方式适合临时转换、快速验证,以及不想安装工具的场景。

命令行工具

对于开发者来说,命令行工具效率更高,特别适合批量处理。

使用 yq

yq 是一个专门处理 YAML 的命令行工具,类似于处理 JSON 的 jq。

# 将 YAML 文件转为 JSON
yq eval -o=json input.yaml > output.json

# 或者使用简写
yq -o=json input.yaml

使用 Python

Python 标准库自带 JSON 模块,YAML 则需要安装 PyYAML:

# 安装 PyYAML
pip install pyyaml

# 单行命令转换
python -c "import yaml, json, sys; print(json.dumps(yaml.safe_load(sys.stdin), indent=2, ensure_ascii=False))" < input.yaml > output.json

编程语言实现

在项目代码中进行转换,是最灵活的方式。

JavaScript / Node.js

使用 js-yaml 库:

npm install js-yaml
const fs = require('fs');
const yaml = require('js-yaml');

const yamlContent = fs.readFileSync('input.yaml', 'utf8');
const data = yaml.load(yamlContent);
const jsonContent = JSON.stringify(data, null, 2);

console.log(jsonContent);

Python

import yaml
import json

with open('input.yaml', 'r', encoding='utf-8') as f:
    data = yaml.safe_load(f)

with open('output.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, indent=2, ensure_ascii=False)

提示:使用 yaml.safe_load() 而不是 yaml.load(),可以避免 YAML 反序列化安全问题。

JSON 转 YAML 的方法

JSON 转 YAML同样有多种实现方式。

在线工具

使用在线工具是最快的方式之一。

ToolVault 工具匣 YAML JSON 转换工具 支持双向转换:

  1. 点击中间的"切换方向"按钮,切换到 JSON → YAML 模式
  2. 在左侧输入 JSON 内容
  3. 右侧实时显示转换后的 YAML

命令行

使用 yq

# 将 JSON 文件转为 YAML
yq eval -P input.json > output.yaml

使用 Python

python -c "import yaml, json, sys; print(yaml.dump(json.load(sys.stdin), allow_unicode=True, default_flow_style=False))" < input.json > output.yaml

代码实现

JavaScript / Node.js

const fs = require('fs');
const yaml = require('js-yaml');

const jsonContent = fs.readFileSync('input.json', 'utf8');
const data = JSON.parse(jsonContent);
const yamlContent = yaml.dump(data, { indent: 2, lineWidth: -1 });

console.log(yamlContent);

Python

import json
import yaml

with open('input.json', 'r', encoding='utf-8') as f:
    data = json.load(f)

with open('output.yaml', 'w', encoding='utf-8') as f:
    yaml.dump(data, f, allow_unicode=True, default_flow_style=False, sort_keys=False)

常见问题和陷阱

YAML 和 JSON 之间的转换看起来简单,但实际操作中经常会遇到各种问题。下面是一些最常见的陷阱。

缩进问题

YAML 对缩进非常敏感,这是新手最容易踩的坑:

  • 必须使用空格缩进,不能用 Tab
  • 同一层级的缩进必须对齐
  • 通常使用 2 个或 4 个空格,但一个文件内要一致
# 正确
person:
  name: Alice
  age: 30

# 错误:缩进不一致
person:
  name: Alice
   age: 30  # 多了一个空格

解决方法:使用支持 YAML 的编辑器,开启显示空白字符功能;或者使用 ToolVault 工具匣 的 YAML 格式化工具 自动修复格式。

数据类型丢失

YAML 的自动类型推断有时会带来意外。但要先明确一个关键事实:这类坑绝大多数属于 YAML 1.1 的解析行为。YAML 1.2(2009 年发布)把布尔值收紧为只有 true / false,整数十进制化,yes/no/on/off、前导零八进制、六十进制全部回归普通字符串。新一代解析器(go-yaml v3、js-yaml、ruamel.yaml、yamllint)都按 1.2 规则解析;仍按 1.1 解析的著名例外是 PyYAML。

用 js-yaml 5.x(本工具所用库,默认 DEFAULT_SCHEMA,按 1.2 core schema 解析)实测:

# YAML 1.1 解析器(如 PyYAML)的行为          # js-yaml / YAML 1.2 的行为
enabled: yes      # → true(布尔)            # → "yes"(字符串)
flag: off         # → false                   # → "off"
port: 08080       # → 520(前导零按八进制!) # → 8080(十进制)
base: 0o17        # → 15                      # → 15(0o 前缀八进制仍然有效)
date: 2024-01-15  # → Date 对象               # → 字符串 "2024-01-15"

注意 js-yaml 下 2024-01-15 解析出来就是字符串(核心 schema 没有日期类型),不是 Date 对象——网上一些教程说 YAML 会把日期转成 Date,那是其他库(或旧版本)的行为。

挪威问题(The Norway Problem)

YAML 1.1 的布尔词表臭名昭著:y / n / yes / no / true / false / on / off(含各种大小写)共 22 种写法全是布尔值。于是:

countries:
  - NO   # 挪威国家代码,YAML 1.1 下被解析成 false!
  - CN

把国家列表从 YAML 1.1 系统迁到 YAML 1.2 系统(或反过来),NO 会在「布尔 false」和「字符串 "NO"」之间漂移,这就是配置社区常说的「挪威问题」。同样中招的还有 1:30 这类值——YAML 1.1 会把它按六十进制(sexagesimal)解析成 90,Docker Compose 的 ports 不写引号 8080:80 就曾因此踩坑(详见 docker run 转 compose 指南 中对端口引号的讨论)。

解决方法:

  • 需要保留为字符串的值一律加引号:port: "08080"、enabled: "yes"、country: "NO"
  • 升级工具链到按 YAML 1.2 解析的版本(go-yaml v3+、js-yaml、ruamel.yaml),PyYAML 项目注意它至今仍是 1.1 行为
  • 转换后用 JSON Schema 之类做类型校验,而不是肉眼抽查

循环引用

JSON 不支持循环引用,但 JavaScript 等语言中的对象可能存在循环引用。来源有两个:业务代码里手动构造的环,以及 YAML 锚点/别名在解析后天然形成的共享结构(见上一节对锚点的讨论):

const obj = { name: 'test' };
obj.self = obj;  // 循环引用
JSON.stringify(obj);  // 报错:TypeError: Converting circular structure to JSON

解决方法:

  • 避免在需要序列化的数据中使用循环引用
  • 使用专门的库处理循环引用(如 circular-json,但已废弃)

多行字符串处理

YAML 的多行字符串有多种语法,转换时需要注意:

# | 保留换行符
description: |
  第一行
  第二行

# > 折叠换行(变成空格)
summary: >
  这是一段
  很长的文字

转为 JSON 后分别是:

{
  "description": "第一行\n第二行\n",
  "summary": "这是一段 很长的文字\n"
}

注意:| 和 > 语法末尾的换行符处理方式不同,需要根据实际需求选择。

YAML 锚点和别名无法转 JSON

YAML 的锚点(&)和别名(*)是非常有用的特性,可以减少重复:

defaults: &defaults
  adapter: postgres
  host: localhost

development:
  <<: *defaults
  database: dev_db

production:
  <<: *defaults
  database: prod_db

上面 <<: *defaults 的合并键语法让 development 同时得到 adapter、host、database 三个字段。但 JSON 没有锚点和合并键的概念,转换后会变成展开的完整结构。虽然数据是正确的,但会失去「引用」的语义。

合并键 << 的边界更要小心。 上面的 <<: *defaults 合并键不在 YAML 1.2 核心规范里,只是类型仓库中的一个可选标签,各解析器支持程度不一:

  • PyYAML、go-yaml v3 支持合并键,development 会正确得到 adapter/host/database 三个字段
  • js-yaml 也支持 << 合并,但只有当合并键直接写在映射下时才生效;如果把它写进花括号内联映射(如 x: {<<: *d, b: 2}),它会被当成一个名叫 << 的普通键
  • 跨文档锚点是禁止的:别名只能引用同一文档内已定义的锚点,多文档流里 doc2 引用 doc1 的锚点会直接报错

锚点还有三个容易踩的边界:

  1. 别名是共享引用,不是拷贝。 在 JavaScript 里,*defaults 解出来的对象和 &defaults 指向同一内存。如果别名构成环(a: &x { self: *x }),转 JSON 时 JSON.stringify 会直接抛 Converting circular structure to JSON——这正是下一节的问题来源之一。
  2. 锚点可以覆盖。 同一文档内后出现的 &defaults 会覆盖先出现的,别名解析到「它之前最近的一个」。
  3. 别名不能被覆盖为映射做 merge 以外的用途。 想给某个环境只改一个字段,用合并键而不是在别名后追加键。

解决方法:如果需要保留引用关系,需要在业务代码中自己处理,或者选择其他支持引用的格式。转换前先用 yamllint 或解析器把锚点全部展开确认结果符合预期。

多文档流(--- / ...)

Kubernetes 清单、Helm 模板、CI 配置里经常一个文件装多个 YAML 文档,用 --- 分隔、... 结束:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app

这是 YAML 独有、JSON 完全没有对应物的结构。 各工具的处理方式差异很大:

  • js-yaml 的 load() 遇到多文档会直接报错(expected a single document in the stream)——这不是 bug,是刻意设计,防止静默丢数据
  • 要转多文档,得用 loadAll() 拿到数组再逐个 JSON.stringify
  • yq 默认对每个文档输出一条 JSON;jq -s 可以收拢成数组
  • Kubernetes 工具链(kubectl apply -f)原生接受多文档流

实用建议:把多文档 YAML 转 JSON 时,先确认下游期望的是「JSON 数组」还是「逐行 JSON(JSON Lines)」,两种形态都有人用。单文档转换器遇到 --- 报错时,先检查输入是不是多文档。

常见 lint / 解析错误排查

YAML 报错信息通常带行号列号,但有几类错误的原因不直观:

报错(js-yaml 原文)真实原因排查动作
bad indentation of a mapping entry同级键缩进不一致,或混用了 Tab编辑器打开「显示空白字符」,全局把 Tab 换成空格
duplicated mapping key同一映射里键名重复(js-yaml、yamllint 默认报错;PyYAML 默认静默后者覆盖前者)全局搜重复的键名;多人协作的 CI 配置最常见
unexpected end of the stream within a flow collection[ 或 { 没闭合从报错行往回找未闭合的括号
can not read an implicit mapping pair; a colon is missed值里带了 : (冒号+空格)却没加引号,如 time: 10:30给含冒号的值加引号:time: "10:30"
missed comma between flow collection entries行内写 key: value 时 value 含特殊字符同上,加引号;或改成块式写法

通用排查顺序:先 yamllint -d relaxed file.yaml 跑一遍;报错行看不懂时,把文件缩短到只剩报错行附近的最小片段再解析;还不行就把可疑值全部加引号试一遍——YAML 里 90% 的诡异解析错误都能用「加引号」解释。

使用 ToolVault 工具匣 在线 YAML JSON 转换工具

如果你需要快速、方便地进行 YAML 和 JSON 之间的转换,ToolVault 工具匣 的在线 YAML JSON 转换工具 是一个绝佳选择。

双向转换

工具支持 YAML → JSON 和 JSON → YAML 双向转换,一键切换方向,满足各种转换需求。无论是把配置文件转为 API 可用的 JSON,还是把接口返回的数据保存为 YAML 配置,都能轻松搞定。

实时预览

输入内容的同时,右侧结果实时更新,无需点击转换按钮。你可以边写边看转换结果,快速验证格式是否正确。

格式校验

工具会自动检测语法错误,并给出清晰的错误提示,帮你快速定位问题。无论是 YAML 的缩进问题,还是 JSON 的语法错误,都能一目了然。

此外,工具还支持:

  • 格式化美化:自动调整缩进和换行,让代码更易读
  • 压缩/最小化:JSON 可以转为压缩格式,减少体积
  • 大整数保护:JSON → YAML 方向对超出安全整数范围的数字自动字符串化,避免雪花 ID 之类被静默改写(详见文末实现注记)
  • 一键复制:转换结果一键复制到剪贴板
  • 纯前端运行:所有处理在浏览器本地完成,数据不上传服务器,保护隐私

最佳实践

1. 选择合适的格式

  • 配置文件:优先用 YAML,可读性好,支持注释
  • API 数据交换:用 JSON,兼容性好,解析速度快
  • 存储大量数据:考虑更紧凑的格式(如 MessagePack、Protocol Buffers)

2. 保持风格一致

在同一个项目中,保持格式风格的一致性:

  • YAML 缩进统一使用 2 空格或 4 空格
  • JSON 的缩进空格数保持一致
  • 命名风格统一(驼峰、下划线、连字符选一种)

3. 注意数据类型

  • 字符串如果可能被误解为数字、布尔值或日期,务必加引号
  • 浮点数精度问题要注意,尤其是金额相关的数据
  • 空值统一使用 null(JSON)或 null / ~(YAML)

4. 转换后验证

转换完成后,不要直接使用,先做验证:

  • 检查关键字段的值是否正确
  • 验证数据类型有没有发生意外变化
  • 确认没有丢失字段或数据

5. 安全地解析 YAML

  • 永远使用 safe_load 而不是 load,避免反序列化攻击
  • 不要解析来自不可信来源的 YAML 文件
  • 对解析后的数据做合法性校验

FAQ

YAML 和 JSON 哪个更好?

没有绝对的"更好",取决于使用场景。配置文件推荐用 YAML(可读性好、支持注释),API 数据交换推荐用 JSON(兼容性好、解析快)。

为什么 YAML 文件有时候会解析出错?

最常见的原因是缩进问题。YAML 对缩进非常敏感,必须使用空格(不能用 Tab),同一层级的缩进必须严格对齐。另外,特殊字符、未加引号的字符串也可能导致解析错误。

JSON 支持注释吗?

标准 JSON 不支持注释。但有些工具和库(如 JSON5、JSONC)扩展了 JSON 语法,支持注释。如果你需要带注释的配置文件,建议直接使用 YAML。

YAML 转 JSON 后数据类型变了怎么办?

先确认方向:是解析时就变了(YAML 1.1 式解析器把 yes 变 true、08080 变 520),还是序列化时变了(日期对象被 toJSON 成字符串、大整数超出 2^53 被截断)。前者靠加引号或升级解析器解决;后者要在转换前对数据做预处理。对字符串可能被误解的场景,统一加引号是成本最低的防御。

为什么我的多文档 YAML 转 JSON 报错了?

单文档转换器(如 js-yaml 的 load())遇到 --- 分隔的多文档流会抛 expected a single document in the stream。改用支持多文档的 API(loadAll())或 yq 逐文档输出;如果转换器明确只转第一份文档,务必确认那不是静默丢数据。

有没有批量转换的方法?

有。可以使用命令行工具(如 yq)配合 shell 脚本批量处理文件,或者用 Python/Node.js 写脚本遍历目录进行转换。对于简单的临时转换,也可以使用在线工具逐个处理。

实现注记(ToolVault 转换器实际行为)

这一节描述本站转换器的真实实现(js-yaml 5.2.1,yamlToJson / jsonToYaml 两个纯函数),与其他在线工具或本地库的行为可能有出入,以你手头工具的实测为准:

  • YAML → JSON:走 yaml.load()(1.2 core schema)→ JSON.stringify(obj, null, 2)。锚点/别名、合并键在解析阶段就展开成普通对象;遇到多文档流会抛出 expected a single document in the stream 错误而不是只转第一份;重复键直接报 duplicated mapping key。
  • JSON → YAML:先经自研的无损解析(parseLossless,基于 meriyah AST)把数字 token 原样保留,再把超出 Number.MAX_SAFE_INTEGER 的整数降级为字符串写进 YAML(js-yaml 的 dump 没有无损数字类型)。所以 {"id": 2099774875233849345} 转出的 YAML 是 id: '2099774875233849345'——数字 19 位雪花 ID 不会丢精度,但类型从 number 变成了 string,下游要注意。
  • 反向不对称:上述字符串化的大整数再走 YAML → JSON 时,回来的是字符串而不是原数字;而在安全整数范围内(±2^53 内)的数字可以无损往返。大整数的完整讨论见 JSON 整数精度陷阱。
  • 默认 dump 参数:indent: 2、lineWidth: 120——超过 120 字符的长字符串会被折叠换行, diff 时注意这不是数据变化。
  • 纯前端运行:所有转换在浏览器本地完成,不上传服务器。

延伸阅读


本文出自 ToolVault 工具匣。立即体验 在线 YAML JSON 转换工具,让数据格式转换变得简单高效。其他在线工具可在 首页 找到。