Javascript is required
错误排查发布于 2026-07-28审校于 2026-08-085 分钟阅读

JSON 转 YAML:yes/no、on/off 与布尔值隐式转换

JSON 只有明确的 true、false 和字符串;YAML 的标量解析却可能根据版本或 schema 把 yes、no、on、off 当成布尔值。相同文本交给不同解析器,得到的 JSON 类型可能不同。本文只讨论 YAML schema 下的布尔解析,不把某个库的默认行为当成 YAML 的统一规则。

JSON to YAMLYAML 1.1YAML 1.2Boolean Coercion

一、问题概述:看起来像单词的值可能变成 boolean

配置中的 enabled: yes 如果按 YAML 1.1 风格解析,可能得到 true;按 YAML 1.2 core schema,通常只有 true/false 形式具有布尔语义。onoff 也必须结合解析器 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 类型。

来源与延伸阅读

技术审校所依据的规范与权威参考资料。

相关文章

继续阅读

可打开关联的浏览器工具,使用自己的样本验证文中的处理流程。

打开关联工具