为什么两个间隔的 YAML 不像四个间隔的 YAML 那样被解析?

Why isn't two-spaced YAML parsed like four-spaced YAML?

我在解析使用两个 space 缩进创建的 YAML(使用 Ruby 2.5/Psych)时看到奇怪的行为。同一个文件,每行缩进四个 spaces - 在我看来 - 正如预期的那样。

两个space:

windows:
  - shell:
    panes:
      - echo hello

产生以下散列:

{"windows"=>[{"shell"=>nil, "panes"=>["echo hello"]}]}

而使用四个 space 缩进:

windows:
    - shell:
        panes:
            - echo hello

结果:

{"windows"=>[{"shell"=>{"panes"=>["echo hello"]}}]}

我只是浏览了一下 the spec,没有看到任何与此问题相关的内容。

这种行为是预期的吗?如果是这样,我将非常感谢指向解释原因的资源的链接。

问题是你不能简单地将每两个空格替换为四个空格。那是因为在这一对行中:

  - shell:
    panes:

第二行这两个空格:

    panes:
  ^^

是上一行中“-”的缩写。如果第二行没有缩写,那么这对行将是:

  - shell:
  - panes:

所以当加倍缩进时,这些行中的第二行应该只加倍其第一对空格,而不是第二行。这将为该对产生正确的缩进:

    - shell:
      panes:

因此,如果您只扩展 "panes:" 行中的第一对空格,您将得到:

windows:
    - shell:
      panes:
          - git status

正确解析为预期结果。

虽然 Wayne 的解决方案是正确的,但解释似乎有点不对劲,所以我会加入我的:

在 YAML 中,块序列项的 -(如块映射的 ?:)被视为 缩进 spec):

The “-”, “?” and “:” characters used to denote block collection entries are perceived by people to be part of the indentation. This is handled on a case-by-case basis by the relevant productions.

此外,所有块集合(序列和映射)都从第一项开始缩进(因为没有明确的起始指示符)。所以在- shell:行中,-定义了新启动序列的缩进级别,同时shell:定义了新启动映射的缩进级别,即序列项的内容。请注意如何将 - 视为定义映射缩进级别的缩进。

现在,重温您的第一个示例:

windows:
  - shell:
    panes:
      - echo hello

panes:shell:处于同一水平。这意味着 YAML 将其解析为由 shell: 开始的映射的 key,这意味着键 shell 具有空值。隐式键的映射值,如果不在同一行,则必须始终比相应的映射键 (spec):

缩进更多

The block node’s properties may span across several lines. In this case, they must be indented by at least one more space than the block collection, regardless of the indentation of the block collection entries.

OTOH,在第二个例子中:

windows:
    - shell:
        panes:
            - echo hello
shell: 相比,

panes: 的缩进级别更深。这意味着它被解析为键 shellvalue,从而开始一个新的嵌套块映射。

最后,请注意,由于 - 被视为缩进的一部分,因此 “缩进两个空格” 也可能意味着:

windows:
- shell:
    panes:
    - echo hello

请注意 - 的缩进并不比它们的映射键多。这是有效的,因为 spec 说:

Since people perceive the “-” indicator as indentation, nested block sequences may be indented by one less space to compensate, except, of course, if nested inside another block sequence (block-out context vs. block-in context).