【问题标题】:What valid JSON files are not valid YAML 1.1 files?哪些有效的 JSON 文件不是有效的 YAML 1.1 文件?
【发布时间】:2014-03-02 08:10:31
【问题描述】:

YAML 1.2 是 JSON 的超集(有一个 minor caveat 关于重复键),因此任何有效的 JSON 文件也是有效的 YAML 文件。但是,YAML 1.1 specification(其中library support 最多)没有提到 JSON。大多数有效的 JSON 文件都是有效的 YAML 1.1 文件,但我通过试验 PyYaml 和 Python 的标准 JSON 库发现了至少一个例外:

  • 双精度浮点溢出(例如 12345e999)被 PyYAML 解释为字符串,被 Python 的 JSON 库解释为 IEEE infinity

有没有人有一个完整的差异列表,比通过在特定实现中测试边缘案例更可靠地确定? (也就是说,从规范的比较?)例如,我想生成 JSON 字符串,这些字符串将被 JSON 解析器和 YAML 1.1 解析器以相同的方式解释:我必须对我的字符串设置什么约束?

【问题讨论】:

  • 我说,“有没有人有一个清单...”。我不是要求人们做新的工作,我是问有没有其他人以前遇到过这个问题,以便我们可以分享结果。
  • 我不认为12345e999 示例表明该文件不是有效的 JSON 或 YAML。 1) 两种实现都正确地解释了它(当然,这可能是错误的); 2) AFAIK 无论是 YAML 还是 JSON 规范都没有严格定义实现必须支持的浮点值范围,因此特定于实现的行为是公平的游戏。

标签: json yaml


【解决方案1】:

here(特别是脚注25)。它说:

不兼容的地方如下:JSON 允许扩展字符 设置像 UTF-32 并且具有不兼容的 unicode 字符转义语法 相对于 YAML; YAML 在逗号等分隔符后需要一个空格, 等于和冒号,而 JSON 没有。一些不规范的 JSON 的实现扩展了语法以包含 Javascript 的 /*...*/ cmets.处理这种边缘情况可能需要光 在解析为内联 YAML 之前对 JSON 进行预处理

另见https://metacpan.org/pod/JSON::XS#JSON-and-YAML

相关
What is the difference between YAML and JSON? When to prefer one over the other

【讨论】:

  • 谢谢,这正是我要找的!
【解决方案2】:

正如您所注意到的,一件事是规范所说的另一件事是常用解析器(YAML JSON)的处理过程。因此,您应该考虑几个方面,并使用最小公分母来避免使用 YAML 解析器加载 JSON。

在 JSON 方面,有多种标准和最佳实践。最初,JSON 文本必须在最顶层有一个对象或数组。根据json.org 网站上的fail1.json 文件,情况仍然如此:

"A JSON payload should be an object or array, not a string."

根据RFC7159,任何值都可以在顶层(除了使用字符串,这会导致相当无聊的 JSON 文件):

JSON 文本是一个序列化值。请注意,某些先前的 JSON 规范将 JSON 文本限制为对象或 大批。仅生成对象或数组的实现 要求 JSON 文本将是可互操作的,因为所有 实现将接受这些作为符合 JSON 文本。

由于 JSON 劫持的问题 *通过重新定义旧浏览器中的数组处理)有一些实现只接受顶层对象(即文件的第一个字符必须是 {

在 YAML 方面,与 JSON 相比,竞争标准更少,但由于 YAML 1.1 的持续使用,事情变得混乱,而且如果你在谷歌上搜索“yaml 当前规范”,第一个命中是 yaml 也无济于事.org/spec/current.html 这实际上是旧的 YAML 1.1 工作草案

除了提到的 UTF-32 支持之外,这在几乎完全使用 UTF-8 的世界中基本上不是问题,还有一些事情需要考虑,特别是如果您希望 PyYAML 成为能够解析您的 JSON(PyYAML 仍然只实现 YAML 1.1 的大部分内容,距离 YAML 1.2 规范发布近八年):

  • JSON 中的数字不需要尾数中的点,即使这样的数字有指数:

    Floating-Point Language-Independent Type for YAML™ Version 1.1 确实需要那个点:

    |[-]?0\.([0-9]*[1-9])?e[-+](0|[1-9][0-9]+) (scientific)
           ^--- no ? or * associated with this dot
    

    (在 YAML 1.2 规范中,此正则表达式已更改为:

    -? [1-9] ( \. [0-9]* [1-9] )? ( e [-+] [1-9] [0-9]* )?.
    

    即使存在e(并且没有E)和指数,也允许点消失。

    这是您的 12345e999 被 JSON(溢出)和 PyYAML(字符串)处理不同的原因。在 YAML 1.1 中,这只能解释为字符串,因此不需要引号,可以是纯标量。

  • 在 YAML 1.1 中有转义序列,但这不是 JSON 支持的超集。正斜杠 (/) 可以在 JSON 中转义,但不能在 YAML 1.1 中转义(可以在 YAML 1.2 中,规则 53)

  • 在 JSON 以及 YAML 1.1 中,您可以使用 \uNNNN 来指示 16 位 unicode 代码点。尽管 YAML 1.1 规范(和 YAML 1.2)提到了代理对与使用 UTF-16 的结合,但没有提到转义序列("\uD834\uDD1E")这样的代理对。此字符串序列在 RFC 7159 中明确提及,表示 G 谱号字符 (U+1D11E)。我不知道任何支持此功能的 YAML 解析器,PyYAML 会抛出:

    yaml.reader.ReaderError: unacceptable character #xd834: special characters are not allowed

所以只要你写你的 JSON

  • 作为 UTF-8
  • 顶层是一个对象
  • 科学数字总是带点
  • 没有\/转义序列
  • \uD7FF\uE000 之间没有\uNNNN 字符(不包括),也不是\uFFFE,也不是\uFFFF

JSON 和 YAML (1.1) 解析器都应该没问题。


¹ ruamel.yaml 我是其作者的 YAML 1.2 解析器中,\/ 和不带点的科学数字得到正确处理:您的 12345e999 加载为 float 类型并打印为 @987654349 @.

【讨论】:

    猜你喜欢
    • 2020-05-29
    • 1970-01-01
    • 2012-07-29
    • 2019-01-04
    • 2022-12-22
    • 2020-01-22
    • 2021-03-22
    • 2017-11-18
    • 1970-01-01
    相关资源
    最近更新 更多