在YAML中,引用的标量是否必须由解析器解释为字符串?

时间:2018-04-18 00:39:23

标签: yaml snakeyaml

我已经在互联网上看过如果你想要将YAML标量值作为字符串处理的建议,你应该引用它:

foo : "2018-04-17"

在上面的示例中,此建议旨在告诉我,任何给定的YAML解析器都会将值2018-04-17作为其本机语言的字符串类型进行处理。例如,SnakeYAML如果此建议为真,则将其解释为java.lang.String,而不是java.util.Date。 (碰巧的是,SnakeYAML将其解释为java.util.Date,引用与否,这就是我提出这个问题的原因。)

但是,虽然这个建议可能发生与任何给定的解析器一起工作,但我无法看到YAML 1.2. specification这个建议可能来自何处。我能找到的最接近的是the following sentence

  

YAML允许以多种格式呈现标量。例如,整数“11”也可能写为“0xB”。标签必须指定一种机制,用于将格式化内容转换为规范形式,以便在相等性测试中使用。与节点样式一样,格式是表示细节,不会反映在序列化树和表示图中。

this one

  

标量样式是演示文稿的详细信息,不得用于传达内容信息,除了为标记解析目的而区分普通标量。

this one

  

请注意,解决方案不得考虑演示详细信息,例如注释,缩进和节点样式。

尽管如此,我看到很多YAML文档依赖于双引号 - 值 - 意味着它将被解析为一个字符串的建议,这让我觉得我误读了一些东西。是否有关于这个问题的争论?

1 个答案:

答案 0 :(得分:1)

YAML 1.1规范中的相关部分(注意SnakeYaml是YAML 1.1,因此1.2规范不一定适用):

  

不要求在字符流中明确指定完整表示的所有标记。在解析期间,省略标记的节点将被赋予非特定标记:“?”表示普通标量,“!”表示所有其他节点。 [...]

     

建议将具有“!”非特定标记的节点解析为“tag:yaml.org,2002:seq”,“tag:yaml.org,2002:map”或“tag:yaml。 org,2002:str“取决于节点的类型。此约定允许YAML字符流的作者对标记解析过程施加一些控制。通过显式指定普通标量具有“!”非特定标记,该节点将被解析为字符串,就好像它是以块样式引用或写入一样。但请注意,每个应用程序都可能会覆盖此行为。例如,应用程序可以自动检测源代码中使用的编程语言类型,并将其作为非普通标量显示,并相应地进行解析。

总而言之,YAML处理器不是必需的来将引用的标量解析为字符串,而YAML也没有规定哪个本机类型tag:yaml.org,2002:str映射到。事实上,大多数YAML实现只遵循该建议的部分内容。例如,如果使用SnakeYaml将YAML反序列化为POJO / JavaBean,则通常不在YAML中使用任何显式标记,但是映射将解析为根类结构中的相应Java类,而不是泛型{{ 1}这是这个建议所暗示的(因为所有没有显式标签的映射都会得到Map非特定标签)。

请注意,这已在YAML 1.2中更改:

  

在解析过程中,缺少明确标记的节点会被赋予非特定标记:“!”表示非普通标量,“?”表示所有其他节点。

这更接近大多数实现,但是,例如,如果您反序列化为类!,虽然class Foo { String bar; }不是字符串,但是字段名称仍然会加载:

bar

因此,使用YAML的建议是在应用程序端指定所需的结构 - 在SnakeYaml中,您将设置根类类型,然后每个值将映射到层次结构中其所需的类型,如只要它能够在那里映射,无论它是引用还是不引用。通常,应用程序更有意义指定它在整个层次结构中期望的值,而不是YAML作者通过引用来指定它。这也符合YAML规范,即

  

解析节点的标记必须仅依赖于以下三个参数:(1)节点的非特定标记,(2)从根节点到节点的路径,以及(3)内容(因而节点的类型。

解析标记是用于确定目标类型的YAML术语。并且允许基于其在层次结构中的位置来确定目标类型:根类型由元素是YAML文档的根的事实确定,并且在SnakeYaml的情况下,可以通过API馈送。所有其他类型都取决于它们是根类型的后代。

最后注意事项:如果你真的想要一个字符串,"bar": some value 会做,因为它为节点设置了一个特定的标签。