5月28日 03:48

YAML 1.1 和 YAML 1.2 有什么区别?

YAML 1.1 和 YAML 1.2 的核心差异在于类型推断规则。YAML 1.1 对隐式类型推断非常激进——yes/no/on/off 全部解析为布尔值,010 解析为八进制 8,3:25:45 解析为六十进制秒数。YAML 1.2 砍掉了这些"聪明"的推断,只认 true/false 为布尔值,八进制必须写 0o10,六十进制格式直接移除。1.2 的目标是和 JSON 完全兼容——任何合法 JSON 都是合法的 YAML 1.2,但 1.1 做不到这点。

最典型的坑是"Norway Problem":用 YAML 1.1 写国家代码 NO(挪威),解析出来是布尔值 false。这在处理国际化数据时是真实踩过的坑。1.2 修复了这个问题,NO 就是字符串 "NO"

版本兼容性处理的关键:不要指望声明 %YAML 1.2 就万事大吉——PyYAML、LibYAML 这些主流库至今默认走 1.1 规则。实际做法是写配置时始终用 true/false 表布尔值、用引号包裹可能有歧义的字符串、八进制加 0o 前缀,这样不管解析器用的是哪个版本都不会出问题。

追问

YAML 1.2 具体移除了哪些 YAML 1.1 的类型?

移除了五个类型标签:!!pairs(有序键值对序列)、!!omap(无重复有序映射)、!!set(集合)、!!timestamp(时间戳)、!!binary(二进制数据)。另外 merge key << 和 value key = 这两个特殊映射键也移除了。<< 在 1.1 里用来做锚点合并,很多人依赖它做配置继承,迁移时要改成显式写法。

为什么 PyYAML 还在用 YAML 1.1?

历史包袱太重。PyYAML 基于 LibYAML(C 实现),改动底层类型推断会影响大量现有配置文件的解析结果。社区有 ruamel.yaml 作为 1.2 的替代方案,但 PyYAML 因为存量用户太多不敢贸然切换默认行为。实际项目中如果需要 1.2,用 ruamel.yaml 并指定 version=(1, 2) 即可。

同一份 YAML 文件在 1.1 和 1.2 下解析结果不同,怎么排查?

重点检查三类值:布尔值(yes/no/on/off)、以 0 开头的数字(八进制 vs 十进制)、以及六十进制时间格式。用两个解析器分别加载同一文件,对比输出差异。Python 里可以同时用 PyYAML 和 ruamel.yaml 跑一遍,JavaScript 的 js-yaml 默认走 1.2 规则可以直接对比。

YAML 1.1 的 sexagesimal 格式是什么?

六十进制数字,写成 3:25:45 这种形式,解析为 12345 秒。YAML 1.2 移除了这个格式,同样的写法在 1.2 里就是普通字符串。如果你的配置里用了时间格式如 12:30:00,在 1.1 下会被解析成数字 45000,1.2 下是字符串 "12:30:00"——这也是迁移时容易踩的坑。

标签:YAML