免费YAML转JSON转换器

即时将YAML转换为JSON。处理所有YAML语法,包括列表、映射和锚点。完全在您的浏览器中运行。

您的数据从不离开设备
将YAML文件拖到此处 或点击浏览 (最大5 MB)

什么是YAML?

YAML(YAML Ain't Markup Language)是一种人类友好的数据序列化格式,常用于配置文件。它使用缩进和简单语法表示列表、字典和标量值等数据结构。

为什么要将YAML转换为JSON?

常见问题

支持哪些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上的官方宣传语。

规范版本时间线

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则变为falseYAML 1.2在规范层面修正了这一问题:与JSON对齐的核心模式只识别trueTrueTRUEfalseFalseFALSE,完全识别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

转换中会丢失什么

YAML的实际应用场景

YAML在现代基础设施中无处不在:Kubernetes清单(整个对象模型按惯例使用YAML;以---分隔的多文档文件是标准做法)、Docker Composedocker-compose.yml用于服务、网络、卷的配置)、GitHub Actions.github/workflows/*.yml:大体上遵循严格的YAML 1.2模式,但解析器仍将on:识别为键,这是GitHub明确处理的挪威问题擦边情况)、GitLab CI/CDAnsible剧本CircleCI / Travis CI / Drone / Bitbucket PipelinesJekyll / 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_ymlserde_yaml_ngserde_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)。

相关工具