免费YAML转JSON转换器
即时将YAML转换为JSON。处理所有YAML语法,包括列表、映射和锚点。完全在您的浏览器中运行。
什么是YAML?
YAML(YAML Ain't Markup Language)是一种人类友好的数据序列化格式,常用于配置文件。它使用缩进和简单语法表示列表、字典和标量值等数据结构。
为什么要将YAML转换为JSON?
- 通用兼容性 · 几乎所有编程语言和工具都支持JSON。
- 配置管理 · 许多工具期望JSON用于配置或数据交换。
- API集成 · Web API通常需要JSON格式。
- 数据处理 · 转换YAML配置文件以用于自动化工作流程。
常见问题
支持哪些YAML功能?
该转换器支持所有标准YAML功能,包括映射、列表、字符串、数字、布尔值、空值、多行字符串、锚点和别名。
复杂的YAML结构会正确转换吗?
是的。该转换器处理嵌套结构、对象列表、注释(会被剔除)以及所有YAML语法。如果存在语法错误,您将获得清晰的错误信息。
YAML注释会保留吗?
不会。注释不是数据结构的一部分,因此不会包含在JSON输出中。
YAML简史:2001年邮件列表上的一个衍生项目
YAML的史前史始于sml-dev邮件列表,是xml-dev在21世纪初的一个分支,聚集了一群认为XML对人工编辑的数据来说过于繁重的人。两条并行轨道在此汇聚:Ingy döt Net为Inline Perl模块编写的Perl序列化格式Data::Denter,以及Oren Ben-Kiki与Clark Evans以简化XML为目标的合作成果。2001年5月11日,Clark Evans在sml-dev上发布了「YAML草案0.1」,该格式翌日在xmlhack上的一篇文章中首次公开亮相。
这个缩写最初的展开颇为戏谑:Yet Another Markup Language(又一种标记语言),是对2001年标记格式泛滥现象的调侃。2001年12月至2002年4月间,作者们将其改造为递归缩写YAML Ain't Markup Language(YAML不是标记语言),一方面是为了强调YAML是一种数据序列化格式,而非XML或HTML那样的文档标记格式;另一方面是因为原来的玩笑已经过时了。这个递归展开至今仍是yaml.org上的官方宣传语。
规范版本时间线
- 草案0.1:2001年5月11日,在sml-dev邮件列表上公告。
- YAML 1.0:2004年1月29日,由Ben-Kiki、Evans和Ingy döt Net共同发布的第一个稳定规范。
- YAML 1.1:2005年1月18日,大多数「遗留」解析器至今仍默认模拟的版本。挪威问题及大多数隐式类型转换的怪异行为均源于此版本。
- YAML 1.2.0:2009年7月21日,第一个明确以「JSON超集」为目标的修订版本。隐式类型转换已重写,以与JSON的标记对齐。
- YAML 1.2.1:2009年10月1日,仅含勘误修正的1.2.0刷新版。
- YAML 1.2.2:2021年10月1日,由2020年成立的新YAML语言开发团队发布的勘误修订版。
1.2.2规范明确指出「相对于YAML规范v1.2,无规范性变更」;其工作内容包括:将源文档从DocBook转换为Markdown、从纯文本LaTeX重新生成图表,以及开放开发流程,使外部贡献者能够提交针对规范本身的Pull Request。自2009年以来,语言层面未发布任何新特性:此后所有解析器合规性问题,要么是1.1版本的遗留问题,要么是对一个已稳定逾十五年的规范的偏差。官方MIME类型application/yaml于2024年最终确定;文件扩展名.yaml和.yml自2006年前后均已获得认可,其中.yaml是推荐用法。
JSON关系:「几乎是超集」的由来
YAML 1.2.2规范措辞审慎:「纯属巧合,JSON几乎是YAML的一个完整子集。」JSON出现于YAML 1.0(2004年)和YAML 1.1(2005年)之间,YAML作者是事后才发现这种重叠的。1.2修订版的明确目标(其原话)是「使YAML成为JSON的严格超集」,这对JSON格式的YAML 1.2文档来说几乎成立,但对YAML 1.1来说并不成立。
实际上:每个JSON文档都是有效的YAML 1.2,流式映射{"a": 1, "b": [true, null]}在两者中的解析结果完全相同。大多数JSON文档并不是有效的YAML 1.1,这是因为布尔值和挪威问题等陷阱:包含字面字符串"NO"的JSON文档,如果经过默认设置的1.1解析器往返转换,会被重新输出为false。反向永远不成立:YAML能表达JSON无法表达的内容,包括注释(转换时丢失)、锚点和别名(转换时解析)、标签(通常被丢弃)、多文档流(只有第一个或全部作为数组保留)以及映射中的非字符串键。
挪威问题
YAML中被引用最多的陷阱。之所以以挪威命名,是因为挪威的ISO 3166-1两字母国家代码是NO,而YAML 1.1的布尔值正则表达式会将NO匹配为布尔值false。在YAML 1.1中(或在任何仍默认使用1.1行为的1.2解析器中,大多数解析器如此)写入country: NO,解析后转为JSON,得到的是{"country": false}。这个bug是静默的,没有警告,没有类型错误,只有数据损坏。
官方yaml.org/type/bool.html模式中完整的YAML 1.1布尔值正则表达式为:
y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
这涵盖六个词素(y/n、yes/no、on/off、true/false),每个有三种大小写变体,共二十二个字符串,全部无警告地转换为布尔值。有效回复列表[y, n, maybe]变为[true, false, "maybe"];功能标志dark_mode: on被解析为dark_mode: true;端口模式设置写作OFF则变为false。YAML 1.2在规范层面修正了这一问题:与JSON对齐的核心模式只识别true、True、TRUE、false、False、FALSE,完全不识别y/n/yes/no/on/off。但这一修正尚未在实际中得到普及,PyYAML和LibYAML在所有当前发行版本中仍默认使用1.1。本转换器使用js-yaml v4,默认采用YAML 1.2与JSON兼容的模式;这也是使用浏览器端转换器实际上比在PyYAML中运行yaml.load()再转换更为安全的原因之一。
其他隐式类型转换陷阱
八进制数。YAML 1.1遵循C语言惯例:前导零表示八进制。因此010被解析为整数8,而permissions: 0777(一种写Unix文件权限的自然方式)被解析为511。YAML 1.2的修正是要求使用与现代Python一致的显式0o前缀:0o777是511,而0777只是777。仍停留在1.1默认值的解析器对此处理仍有误。
六十进制数。YAML 1.1从早期序列化格式继承了一种惯例:任何以冒号分隔的十进制数字组序列都应被解析为以60为基数(六十进制)的整数或浮点数。宣传的用例是时间长度:1:11:00将被解析为整数4260(一小时十一分钟转换为秒数)。这一规则在实践中仍会造成困扰,当人们写出类似21:00的时间戳或2:3:4这样的版本号时,会发现它们被静默转换为整数。六十进制在YAML 1.2中被静默移除,但PyYAML及其他默认使用1.1的解析器仍会对其进行处理。
日期时间自动转换。YAML 1.1还会自动检测ISO 8601时间戳,并将其解析为宿主语言的原生日期/时间类型;如果你想要的是字符串,这就是个问题。写入version: 2024-01-15,得到的是Python的date对象,而非字符串"2024-01-15"。这是由Ruud van Asseldonk的「YAML document from hell」一文所强调的普遍教训:始终将任何可能被解析为其他类型的字符串用引号括起来。国家代码、版本号、文件权限、时间戳,以及来自固定词汇表的任何值,都应用单引号或双引号括起来。
锚点、别名与合并键
YAML的锚点/别名系统允许用&name标记一个节点,之后用*name重用它。经典示例:
defaults: &defaults timeout: 30 retries: 3 production: <<: *defaults host: prod.example.com
这里&defaults锚定了该映射,<<: *defaults(合并键,一个被大多数解析器保留的1.1模式特性)将其拼接到production块中。转换为JSON时,别名被完全解析,JSON输出包含字面上重复的内容而非引用。锚点和别名消失,所有合并键被展平。
这个系统著名的失效模式是十亿笑脸攻击:由于锚点可以被多次引用,而别名目标本身也可以包含别名,一个小型YAML文件可以展开成一个极其庞大的内存结构(10层×10倍嵌套 = 10¹⁰个字符串元素)。PyYAML、LibYAML等均不得不添加展开限制来缓解这一问题。浏览器端转换器有天然的内存上限(在宿主机遭受影响之前,标签页早已内存溢出),但结构性风险是真实存在的。
多文档流与前置元数据
一个YAML流可以包含多个文档。文档之间用内容恰好为---的行分隔(也用作第一个文档开头的指令结束标记,这就是为什么Jekyll、Hugo和Eleventy中的前置元数据要用---行括起来)。包含...的行标记文档结束而不开启新文档,在流式协议中很有用。
Kubernetes使用---将多个资源清单捆绑在一个文件中。JSON没有对应功能。转换器在遇到多文档YAML时有三种选择:只输出第一个文档、输出文档的JSON数组,或将每个---分隔的文档输出为一行JSON(即JSON Lines格式)。大多数转换器默认采用第一或第二种方式;js-yaml的loadAll返回一个数组。
多行字符串:折叠风格与字面风格
YAML有两种块标量风格。字面风格(|)完整保留换行符。折叠风格(>)将单个换行符替换为空格,并将空行保留为段落分隔符。两者均接受截断指示符:|-和>-剥离所有尾部换行符,|+和>+保留所有尾部换行符,而不加修饰的|或>(「截断」模式)保留单个尾部换行符。转换为JSON时,两种风格均生成普通字符串值:折叠块变成一个长字符串,仅在保留的空行处包含\n;字面块则在每个换行处都有\n。
转换中会丢失什么
- null表示形式被归一化。YAML接受
null、Null、NULL、~以及空值(key:后面什么都没有)作为空值。这五种形式均转换为JSON的null,无从区分。 - 注释静默消失。YAML注释以
#开头,1.2规范明确指出它们只是表示性内容,不属于数据模型的一部分。JSON没有注释语法。如需保留,请在转换前将其存储为数据(例如使用_comment字段)。 - 非字符串键被强制转换。YAML映射允许任意节点作为键,包括整数(
1: foo)、布尔值(true: yes),甚至嵌套序列。JSON要求字符串键。大多数转换器会将其字符串化("1": "foo");少数会抛出异常。 - 标签通常被丢弃。自定义标签如
!!set、!!omap或应用特定的!myapp/Type在JSON中没有对应物。 - 日期时间以字符串形式往返。YAML中的日期或时间戳通常在JSON中变为ISO 8601字符串,因为JSON没有原生日期类型。
- 大整数在JavaScript中精度丢失。JavaScript中的JSON数字是IEEE 754双精度浮点数,因此YAML整数
9007199254740993在转换后会静默变为9007199254740992。 - 锚点被展开。在多个位置共享子树的YAML图,转换为JSON时该子树会被复制。循环引用(YAML允许)在JSON中根本无法表示。
YAML的实际应用场景
YAML在现代基础设施中无处不在:Kubernetes清单(整个对象模型按惯例使用YAML;以---分隔的多文档文件是标准做法)、Docker Compose(docker-compose.yml用于服务、网络、卷的配置)、GitHub Actions(.github/workflows/*.yml:大体上遵循严格的YAML 1.2模式,但解析器仍将on:识别为键,这是GitHub明确处理的挪威问题擦边情况)、GitLab CI/CD、Ansible剧本、CircleCI / Travis CI / Drone / Bitbucket Pipelines、Jekyll / Hugo / Eleventy / Gatsby / Astro前置元数据、OpenAPI / Swagger规范(官方定义为「可用JSON或YAML表示的JSON对象」)、Prometheus / Grafana / Loki / Tempo监控栈配置、cloud-init(EC2/GCE/Azure虚拟机首次启动配置),以及AWS CloudFormation / Azure Resource Manager / Google Cloud Deployment Manager。对于其中大多数场景,每当需要将配置嵌入仅支持JSON的协议、用jq比较文件,或将输出传递给需要JSON的工具时,YAML到JSON的转换都不可或缺。
为什么浏览器端转换比服务器端更安全
PyYAML的yaml.load()在默认设置下,可通过!!python/object标签在任何不可信输入上执行任意Python代码,该标签会反序列化为具有副作用的实际Python对象,这是CVE-2017-18342(CVSS v3.1评分9.8,严重级别),已在PyYAML 5.1(2019年3月)中修复,方法是弃用不安全的默认行为并将safe_load()设为推荐入口点。Java的SnakeYAML也有类似问题(CVE-2022-1471,同样CVSS 9.8),涉及允许任意实例化的Constructor类。Rust事实上的标准serde_yaml包于2024年3月被废弃;生态系统仍在围绕继任者(serde_yml、serde_yaml_ng、serde_norway)进行整合。
在浏览器中通过js-yaml v4运行解析规避了所有这些问题:没有服务器可被入侵,js-yaml没有通过标签执行任意代码的机制(未知标签变为普通标量而非构造对象),且v4默认采用更安全的1.2模式。Absolutool工具默认即可从中受益。
更多问题
转换器如何处理多文档YAML文件?
它使用js-yaml的loadAll加载,该方法返回已解析文档的数组,因此JSON输出是一个JSON数组,每个---分隔的文档对应一个元素。如果只有单个文档,也会得到一个包含单个元素的JSON数组;如需明确的单文档语义,请在输入中加上---/...标记。
我的Kubernetes清单能正确转换吗?
几乎总是可以。Kubernetes使用的YAML内容大体上与YAML 1.2兼容,js-yaml v4可以处理所有标准原语(字符串、整数、布尔值、null、序列、映射)以及锚点和别名。无法保留的两类内容是:注释(会被剥离)以及展开为重复内容而非引用的锚点。
为什么我的国家代码NO被识别为布尔值?
在本转换器中不应出现这种情况,js-yaml v4默认使用YAML 1.2与JSON兼容的模式,不会将y/n/yes/no/on/off识别为布尔值。如果你在其他工具中遇到这个问题(例如PyYAML),解决方法是用引号括起该值:country: "NO"。
文件大小限制是多少?
上传组件限制为5 MB,但粘贴内容在浏览器内存允许的情况下可以更大。瓶颈是内存中的表示,而非网络,整个过程没有服务器参与。对于大于约50 MB的文件,建议考虑桌面YAML工具链(例如命令行的yq)。