JSON 转 YAML:yes/no、on/off 与布尔值隐式转换
JSON 只有明确的 true、false 和字符串;YAML 的标量解析却可能根据版本或 schema 把 yes、no、on、off 当成布尔值。相同文本交给不同解析器,得到的 JSON 类型可能不同。本文只讨论 YAML schema 下的布尔解析,不把某个库的默认行为当成 YAML 的统一规则。
一、问题概述:看起来像单词的值可能变成 boolean
配置中的 enabled: yes 如果按 YAML 1.1 风格解析,可能得到 true;按 YAML 1.2 core schema,通常只有 true/false 形式具有布尔语义。on、off 也必须结合解析器 schema 判断,不能在 JSON→YAML 转换后凭肉眼推断类型。
二、最小复现:同一标量对应不同 schema 结果
下面的纯函数只模拟常见 schema 规则,用来展示条件;实际结果仍取决于所选 YAML parser 和它启用的 schema。引号会让 token 保持字符串。
type YamlSchema = "yaml-1.1" | "yaml-1.2-core" | "string-only";
function resolveScalar(token: string, schema: YamlSchema): boolean | string {
const value = token.toLowerCase();
if (schema === "string-only") return token;
if (schema === "yaml-1.1" && ["yes", "true", "on"].includes(value)) return true;
if (schema === "yaml-1.1" && ["no", "false", "off"].includes(value)) return false;
if (schema === "yaml-1.2-core" && ["true"].includes(value)) return true;
if (schema === "yaml-1.2-core" && ["false"].includes(value)) return false;
return token;
}
console.log(resolveScalar("yes", "yaml-1.1")); // true
console.log(resolveScalar("yes", "yaml-1.2-core")); // "yes"
console.log(resolveScalar("yes", "string-only")); // "yes"三、根因:YAML 版本与 parser schema 不是一回事
YAML 1.1、YAML 1.2 core schema 以及库自定义 schema 的标量集合不同;同一个库也可能提供多个 schema 选项。错误往往发生在读取阶段,而不是 JSON.stringify 阶段:一旦 yes 已被解析成 true,后续代码无法知道原文本是否带引号。
四、推荐方案:先确定 schema,再决定是否加引号
配置文件需要字符串语义时,对 yes/no、on/off 等有歧义的值显式加引号,并在读取端固定 schema。生成器应记录目标 parser/schema,而不是声称输出 YAML 后所有工具都会得到同一类型。对布尔字段,优先输出 true/false;对业务单词,保留字符串。
五、完整代码:按目标 schema 选择标量写法
以下代码只负责决定是否需要引号,不替代 YAML serializer。它把可能被 YAML 1.1 解释成布尔的业务单词加引号,明确 true/false 则保持布尔字面量。
type YamlSchema = "yaml-1.1" | "yaml-1.2-core" | "string-only";
function yamlScalar(value: string | boolean, target: YamlSchema): string {
if (typeof value === "boolean") return value ? "true" : "false";
const ambiguous = ["yes", "no", "on", "off"];
const needsQuotes = target === "yaml-1.1" && ambiguous.includes(value.toLowerCase());
return needsQuotes ? JSON.stringify(value) : value;
}
console.log(yamlScalar("on", "yaml-1.1")); // "on"
console.log(yamlScalar("on", "yaml-1.2-core")); // on
console.log(yamlScalar(false, "yaml-1.1")); // false六、常见错误方案
只在前端把字符串转换成 boolean 会掩盖配置文件的 schema 差异;把所有 yes/no 替换成 true/false 会破坏本来需要字符串的选项;只依据一个解析器的默认值写兼容逻辑,也可能在升级或更换库后改变结果。
七、边界条件:大小写、引号与显式标签
不同 schema 对大小写变体、显式 !!str/!!bool 标签和引号的支持方式需要查阅目标 parser 文档。单引号和双引号会影响解析语义;不要把字符串中的 "true" 当成布尔值,也不要假设所有解析器都实现相同的 YAML 1.1 扩展。
八、如何验证转换结果
使用目标 parser/schema 分别读取 yes、no、on、off、true、false、带引号值和显式标签。断言 JavaScript 类型和值,再将结果序列化回 YAML/JSON 比较;记录 parser 名称与 schema 选项,避免把一次默认配置的结果当成标准答案。
九、FAQ
问:YAML 1.2 一定把 yes 当字符串吗?答:要结合所用 parser 的 schema 实现确认,版本名称不能替代库配置。
问:给所有字符串加引号可以吗?答:可以提高类型保守性,但会改变可读性和已有输出契约,应按字段需求决定。
问:为什么解析后无法恢复原始引号?答:普通对象只保留值和类型,不保留标量原文的表示方式。
十、总结
yes/no、on/off 是否是布尔值,取决于 YAML 版本语义与具体 parser schema。生成时确定目标 schema,对歧义业务单词显式加引号,读取时记录 parser/schema,并用边界标量验证实际 JavaScript 类型。
来源与延伸阅读
技术审校所依据的规范与权威参考资料。
- YAML 1.2.2 Specification
YAML Language Development Team
- RFC 8259 — The JavaScript Object Notation (JSON) Data Interchange Format
RFC Editor
相关文章
JSON 转 YAML:空格缩进、Tab 与 ScannerError 边界
解释 YAML 缩进必须使用一致的空格、Tab 为什么会触发解析错误,并说明 PyYAML、js-yaml 等解析器的错误类型和文案可能不同。
最佳实践JSON/YAML 转换:Kubernetes 与 Docker Compose 的语义保留
区分 JSON↔YAML 的语法转换与 Kubernetes、Docker Compose 配置语义,分别检查顶层结构、类型、端口、环境变量和目标 schema。
错误排查JSON 对象键顺序不同为何 Diff:结构化比较方法
解释 JSON 文本比较与结构化比较的区别,演示如何递归规范化对象键且保留数组顺序,并列出数字、重复键和数组语义等边界条件。
继续阅读
可打开关联的浏览器工具,使用自己的样本验证文中的处理流程。
打开关联工具