哪些有效的JSON文件不是有效的YAML 1.1文件?

Jim*_*ski 7 json yaml

YAML 1.2是(关于重复键的一个小警告)JSON的超集,因此任何有效的JSON文件也是有效的YAML文件.但是,YAML 1.1规范(具有最多库支持)并未提及JSON.大多数有效的JSON文件都是有效的YAML 1.1文件,但我通过试验PyYaml和Python的标准JSON库发现了至少一个异常:

  • 双精度浮点溢出,如12345e999被解释为PyYAML字符串和IEEE无穷大的Python的JSON库.

有没有人有一个完整的差异列表,比在特定实现中测试边缘情况更有力地确定?(也就是说,从规范的比较中?)例如,我想生成JSON字符串,它们将由JSON解析器和YAML 1.1解析器以相同的方式解释:我必须在字符串上放置哪些约束?

Rob*_*vey 9

这里(特别是脚注25).它说:

不兼容性如下:JSON允许扩展字符集,如UTF-32,并且相对于YAML具有不兼容的unicode字符转义语法; YAML在逗号,等号和冒号之后的分隔符之间需要一个空格,而JSON则不需要.一些非标准的JSON实现扩展了语法,包括Javascript的/*...*/ comments.在解析为内联YAML之前,处理此类边缘情况可能需要对JSON进行轻度预处理

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

相关
YAML和JSON有什么区别?什么时候比较喜欢一个


Ant*_*hon 7

正如您所注意到的,一方面是规范所说的另一方面是常用的解析器(YAMLJSON)处理的内容。因此,您应该考虑多个方面并使用最小公分母,以免无法使用 YAML 解析器加载您的 JSON。

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

"A JSON payload should be an object or array, not a string."
Run Code Online (Sandbox Code Playgroud)

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

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

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

在 YAML 方面,竞争标准比 JSON 少,但是 YAML 1.1 的持续使用使事情变得混乱,并且如果您在 google 上搜索“yaml current spec”,第一个命中是 yaml.org/ spec/current.html 这实际上是YAML 1.1的旧工作草案

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

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

    在此处输入图片说明

    但是YAML™ 1.1 版Floating-Point Language-Independent Type确实需要那个点:

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

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

    -? [1-9] ( \. [0-9]* [1-9] )? ( e [-+] [1-9] [0-9]* )?.
    
    Run Code Online (Sandbox Code Playgroud)

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

    这就是12345e999JSON(溢出)和 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: 不可接受的字符 #xd834: 不允许使用特殊字符

所以只要你写你的JSON

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

您应该对 JSON 和 YAML (1.1) 解析器都适用。


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