2022.06.17
块风格8.1. Block Scalar Styles8.1.1. Block Scalar Headers8.1.1.1. Block Indentation Indicator8.1.1.2. Block Chomping Indicator8.1.2. Literal Style8.1.3. Folded Style8.2. Block Collection Styles8.2.1. Block Sequences8.2.2. Block Mappings8.2.3. Block Nodes
本文按照YAML官方文档1.2.2版本翻译总结而成
https://yaml.org/spec/1.2.2/#chapter-8-block-style-productions
YAML’s block styles employ indentation rather than indicators to denote structure. This results in a more human readable (though less compact) notation.
YAML provides two block scalar styles, literal and folded. Each provides a different trade-off between readability and expressive power.
Block scalars are controlled by a few indicators given in a header preceding the content itself. This header is followed by a non-content line break with an optional comment. This is the only case where a comment must not be followed by additional comment lines.
Note: See Production Parameters for the definition of the
t
variable.
[162] c-b-block-header(t) ::=
(
(
c-indentation-indicator
c-chomping-indicator(t)
)
| (
c-chomping-indicator(t)
c-indentation-indicator
)
)
s-b-comment
Example 8.1 Block Scalar Header
- | # Empty header↓ literal - >1 # Indentation indicator↓ ·folded - |+ # Chomping indicator↓ keep - >1- # Both indicators↓ ·strip | [ "literal\n", " folded\n", "keep\n\n", " strip" ] |
---|---|
Legend:
c-b-block-header(t)
Every block scalar has a content indentation level. The content of the block scalar excludes a number of leading spaces on each line up to the content indentation level.
If a block scalar has an indentation indicator, then the content indentation level of the block scalar is equal to the indentation level of the block scalar plus the integer value of the indentation indicator character.
If no indentation indicator is given, then the content indentation level is equal to the number of leading spaces on the first non-empty line of the contents. If there is no non-empty line then the content indentation level is equal to the number of spaces on the longest line.
It is an error if any non-empty line does not begin with a number of spaces greater than or equal to the content indentation level.
It is an error for any of the leading empty lines to contain more spaces than the first non-empty line.
A YAML processor should only emit an explicit indentation indicator for cases where detection will fail.
[163] c-indentation-indicator ::=
[x31-x39] # 1-9
Example 8.2 Block Indentation Indicator
- |° ·detected - >° · ·· ··# detected - |1 ··explicit - >° ·→ ·detected | [ "detected\n", "\n\n# detected\n", " explicit\n", "\t\ndetected\n" ] |
---|---|
Legend:
c-indentation-indicator
s-indent(n)
Example 8.3 Invalid Block Scalar Indentation Indicators
- | ·· ·text - > ··text ·text - |2 ·text | ERROR: - A leading all-space line must not have too many spaces. - A following text line must not be less indented. - The text is less indented than the indicated level. |
---|---|
Chomping controls how final line breaks and trailing empty lines are interpreted. YAML provides three chomping methods:
Strip
Stripping is specified by the “-
” chomping indicator. In this case, the final line break and any trailing empty lines are excluded from the scalar’s content.
Clip
Clipping is the default behavior used if no explicit chomping indicator is specified. In this case, the final line break character is preserved in the scalar’s content. However, any trailing empty lines are excluded from the scalar’s content.
Keep
Keeping is specified by the “+
” chomping indicator. In this case, the final line break and any trailing empty lines are considered to be part of the scalar’s content. These additional lines are not subject to folding.
The chomping method used is a presentation detail and must not be used to convey content information.
[164]
c-chomping-indicator(STRIP) ::= '-'
c-chomping-indicator(KEEP) ::= '+'
c-chomping-indicator(CLIP) ::= ""
The interpretation of the final line break of a block scalar is controlled by the chomping indicator specified in the block scalar header.
[165]
b-chomped-last(STRIP) ::= b-non-content | <end-of-input>
b-chomped-last(CLIP) ::= b-as-line-feed | <end-of-input>
b-chomped-last(KEEP) ::= b-as-line-feed | <end-of-input>
Example 8.4 Chomping Final Line Break
strip: |- text↓ clip: | text↓ keep: |+ text↓ | { "strip": "text", "clip": "text\n", "keep": "text\n" } |
---|---|
Legend:
b-non-content
b-as-line-feed
The interpretation of the trailing empty lines following a block scalar is also controlled by the chomping indicator specified in the block scalar header.
[166]
l-chomped-empty(n,STRIP) ::= l-strip-empty(n)
l-chomped-empty(n,CLIP) ::= l-strip-empty(n)
l-chomped-empty(n,KEEP) ::= l-keep-empty(n)
[167] l-strip-empty(n) ::=
(
s-indent-less-or-equal(n)
b-non-content
)*
l-trail-comments(n)?
[168] l-keep-empty(n) ::=
l-empty(n,BLOCK-IN)*
l-trail-comments(n)?
Explicit comment lines may follow the trailing empty lines. To prevent ambiguity, the first such comment line must be less indented than the block scalar content. Additional comment lines, if any, are not so restricted. This is the only case where the indentation of comment lines is constrained.
[169] l-trail-comments(n) ::=
s-indent-less-than(n)
c-nb-comment-text
b-comment
l-comment*
Example 8.5 Chomping Trailing Lines
# Strip # Comments: strip: |- # text↓ ··⇓ ·# Clip ··# comments: ↓ clip: | # text↓ ·↓ ·# Keep ··# comments: ↓ keep: |+ # text↓ ↓ ·# Trail ··# comments. | { "strip": "# text", "clip": "# text\n", "keep": "# text\n\n" } |
---|---|
Legend:
l-strip-empty(n)
l-keep-empty(n)
l-trail-comments(n)
If a block scalar consists only of empty lines, then these lines are considered as trailing lines and hence are affected by chomping.
Example 8.6 Empty Scalar Chomping
strip: >- ↓ clip: > ↓ keep: |+ ↓ | { "strip": "", "clip": "", "keep": "\n" } |
---|---|
Legend:
l-strip-empty(n)
l-keep-empty(n)
The literal style is denoted by the “|
” indicator. It is the simplest, most restricted and most readable scalar style.
[170] c-l+literal(n) ::=
c-literal # '|'
c-b-block-header(t)
l-literal-content(n+m,t)
Example 8.7 Literal Scalar
|↓ ·literal↓ ·→text↓ ↓ | "literal\n\ttext\n" |
---|---|
Legend:
c-l+literal(n)
Inside literal scalars, all (indented) characters are considered to be content, including white space characters. Note that all line break characters are normalized. In addition, empty lines are not folded, though final line breaks and trailing empty lines are chomped.
There is no way to escape characters inside literal scalars. This restricts them to printable characters. In addition, there is no way to break a long literal line.
[171] l-nb-literal-text(n) ::=
l-empty(n,BLOCK-IN)*
s-indent(n) nb-char+
[172] b-nb-literal-next(n) ::=
b-as-line-feed
l-nb-literal-text(n)
[173] l-literal-content(n,t) ::=
(
l-nb-literal-text(n)
b-nb-literal-next(n)*
b-chomped-last(t)
)?
l-chomped-empty(n,t)
Example 8.8 Literal Content
| · ·· ··literal↓ ···↓ ·· ··text↓ ↓ ·# Comment | "\n\nliteral\n·\n\ntext\n" |
---|---|
Legend:
l-nb-literal-text(n)
b-nb-literal-next(n)
b-chomped-last(t)
l-chomped-empty(n,t)
The folded style is denoted by the “>
” indicator. It is similar to the literal style; however, folded scalars are subject to line folding.
[174] c-l+folded(n) ::=
c-folded # '>'
c-b-block-header(t)
l-folded-content(n+m,t)
Example 8.9 Folded Scalar
>↓ ·folded↓ ·text↓ ↓ | "folded text\n" |
---|---|
Legend:
c-l+folded(n)
Folding allows long lines to be broken anywhere a single space character separates two non-space characters.
[175] s-nb-folded-text(n) ::=
s-indent(n)
ns-char
nb-char*
[176] l-nb-folded-lines(n) ::=
s-nb-folded-text(n)
(
b-l-folded(n,BLOCK-IN)
s-nb-folded-text(n)
)*
Example 8.10 Folded Lines
> ·folded↓ ·line↓ ↓ ·next ·line↓ * bullet * list * lines ·last↓ ·line↓ # Comment | "\nfolded line\nnext line\n \ * bullet\n \n * list\n \ * lines\n\nlast line\n" |
---|---|
Legend:
l-nb-folded-lines(n)
s-nb-folded-text(n)
(The following three examples duplicate this example, each highlighting different productions.)
Lines starting with white space characters (more-indented lines) are not folded.
[177] s-nb-spaced-text(n) ::=
s-indent(n)
s-white
nb-char*
[178] b-l-spaced(n) ::=
b-as-line-feed
l-empty(n,BLOCK-IN)*
[179] l-nb-spaced-lines(n) ::=
s-nb-spaced-text(n)
(
b-l-spaced(n)
s-nb-spaced-text(n)
)*
Example 8.11 More Indented Lines
> folded line next line ···* bullet↓ ↓ ···* list↓ ···* lines↓ last line # Comment | "\nfolded line\nnext line\n \ * bullet\n \n * list\n \ * lines\n\nlast line\n" |
---|---|
Legend:
l-nb-spaced-lines(n)
s-nb-spaced-text(n)
Line breaks and empty lines separating folded and more-indented lines are also not folded.
[180] l-nb-same-lines(n) ::=
l-empty(n,BLOCK-IN)*
(
l-nb-folded-lines(n)
| l-nb-spaced-lines(n)
)
[181] l-nb-diff-lines(n) ::=
l-nb-same-lines(n)
(
b-as-line-feed
l-nb-same-lines(n)
)*
Example 8.12 Empty Separation Lines
> ↓ folded line↓ ↓ next line↓ * bullet * list * lines↓ ↓ last line # Comment | "\nfolded line\nnext line\n \ * bullet\n \n * list\n \ * lines\n\nlast line\n" |
---|---|
Legend:
b-as-line-feed
(separation) l-empty(n,c)
The final line break and trailing empty lines if any, are subject to chomping and are never folded.
[182] l-folded-content(n,t) ::=
(
l-nb-diff-lines(n)
b-chomped-last(t)
)?
l-chomped-empty(n,t)
Example 8.13 Final Empty Lines
> folded line next line * bullet * list * lines last line↓ ↓ # Comment | "\nfolded line\nnext line\n \ * bullet\n \n * list\n \ * lines\n\nlast line\n" |
---|---|
Legend:
b-chomped-last(t)
l-chomped-empty(n,t)
For readability, block collections styles are not denoted by any indicator. Instead, YAML uses a lookahead method, where a block collection is distinguished from a plain scalar only when a key/value pair or a sequence entry is seen.
A block sequence is simply a series of nodes, each denoted by a leading “-
” indicator. The “-
” indicator must be separated from the node by white space. This allows “-
” to be used as the first character in a plain scalar if followed by a non-space character (e.g. “-42
”).
[183] l+block-sequence(n) ::=
(
s-indent(n+1+m)
c-l-block-seq-entry(n+1+m)
)+
[184] c-l-block-seq-entry(n) ::=
c-sequence-entry # '-'
[ lookahead ≠ ns-char ]
s-l+block-indented(n,BLOCK-IN)
Example 8.14 Block Sequence
block sequence: ··- one↓ - two : three↓ | { "block sequence": [ "one", { "two": "three" } ] } |
---|---|
Legend:
c-l-block-seq-entry(n)
auto-detected s-indent(n)
The entry node may be either completely empty, be a nested block node or use a compact in-line notation. The compact notation may be used when the entry is itself a nested block collection. In this case, both the “-
” indicator and the following spaces are considered to be part of the indentation of the nested collection. Note that it is not possible to specify node properties for such a collection.
[185] s-l+block-indented(n,c) ::=
(
s-indent(m)
(
ns-l-compact-sequence(n+1+m)
| ns-l-compact-mapping(n+1+m)
)
)
| s-l+block-node(n,c)
| (
e-node # ""
s-l-comments
)
[186] ns-l-compact-sequence(n) ::=
c-l-block-seq-entry(n)
(
s-indent(n)
c-l-block-seq-entry(n)
)*
Example 8.15 Block Sequence Entry Types
-° # Empty - | block node -·- one # Compact ··- two # sequence - one: two # Compact mapping | [ null, "block node\n", [ "one", "two" ], { "one": "two" } ] |
---|---|
Legend:
Empty
s-l+block-node(n,c)
ns-l-compact-sequence(n)
ns-l-compact-mapping(n)
A Block mapping is a series of entries, each presenting a key/value pair.
[187] l+block-mapping(n) ::=
(
s-indent(n+1+m)
ns-l-block-map-entry(n+1+m)
)+
Example 8.16 Block Mappings
block mapping: ·key: value↓ | { "block mapping": { "key": "value" } } |
---|---|
Legend:
ns-l-block-map-entry(n)
auto-detected s-indent(n)
If the “?
” indicator is specified, the optional value node must be specified on a separate line, denoted by the “:
” indicator. Note that YAML allows here the same compact in-line notation described above for block sequence entries.
[188] ns-l-block-map-entry(n) ::=
c-l-block-map-explicit-entry(n)
| ns-l-block-map-implicit-entry(n)
[189] c-l-block-map-explicit-entry(n) ::=
c-l-block-map-explicit-key(n)
(
l-block-map-explicit-value(n)
| e-node # ""
)
[190] c-l-block-map-explicit-key(n) ::=
c-mapping-key # '?' (not followed by non-ws char)
s-l+block-indented(n,BLOCK-OUT)
[191] l-block-map-explicit-value(n) ::=
s-indent(n)
c-mapping-value # ':' (not followed by non-ws char)
s-l+block-indented(n,BLOCK-OUT)
Example 8.17 Explicit Block Mapping Entries
? explicit key # Empty value↓° ? | block key↓ :·- one # Explicit compact ··- two # block value↓ | { "explicit key": null, "block key\n": [ "one", "two" ] } |
---|---|
Legend:
c-l-block-map-explicit-key(n)
l-block-map-explicit-value(n)
e-node
If the “?
” indicator is omitted, parsing needs to see past the implicit key, in the same way as in the single key/value pair flow mapping. Hence, such keys are subject to the same restrictions; they are limited to a single line and must not span more than 1024 Unicode characters.
[192] ns-l-block-map-implicit-entry(n) ::=
(
ns-s-block-map-implicit-key
| e-node # ""
)
c-l-block-map-implicit-value(n)
[193] ns-s-block-map-implicit-key ::=
c-s-implicit-json-key(BLOCK-KEY)
| ns-s-implicit-yaml-key(BLOCK-KEY)
In this case, the value may be specified on the same line as the implicit key. Note however that in block mappings the value must never be adjacent to the “:
”, as this greatly reduces readability and is not required for JSON compatibility (unlike the case in flow mappings).
There is no compact notation for in-line values. Also, while both the implicit key and the value following it may be empty, the “:
” indicator is mandatory. This prevents a potential ambiguity with multi-line plain scalars.
[194] c-l-block-map-implicit-value(n) ::=
c-mapping-value # ':' (not followed by non-ws char)
(
s-l+block-node(n,BLOCK-OUT)
| (
e-node # ""
s-l-comments
)
)
Example 8.18 Implicit Block Mapping Entries
plain key: in-line value °:° # Both empty "quoted key": - entry | { "plain key": "in-line value", null: null, "quoted key": [ "entry" ] } |
---|---|
Legend:
ns-s-block-map-implicit-key
c-l-block-map-implicit-value(n)
A compact in-line notation is also available. This compact notation may be nested inside block sequences and explicit block mapping entries. Note that it is not possible to specify node properties for such a nested mapping.
[195] ns-l-compact-mapping(n) ::=
ns-l-block-map-entry(n)
(
s-indent(n)
ns-l-block-map-entry(n)
)*
Example 8.19 Compact Block Mappings
- sun: yellow↓ - ? earth: blue↓ : moon: white↓ | [ { "sun": "yellow" }, { { "earth": "blue" }: { "moon": "white" } } ] |
---|---|
Legend:
ns-l-compact-mapping(n)
YAML allows flow nodes to be embedded inside block collections (but not vice-versa). Flow nodes must be indented by at least one more space than the parent block collection. Note that flow nodes may begin on a following line.
It is at this point that parsing needs to distinguish between a plain scalar and an implicit key starting a nested block mapping.
[196] s-l+block-node(n,c) ::=
s-l+block-in-block(n,c)
| s-l+flow-in-block(n)
[197] s-l+flow-in-block(n) ::=
s-separate(n+1,FLOW-OUT)
ns-flow-node(n+1,FLOW-OUT)
s-l-comments
Example 8.20 Block Node Types
-↓ ··"flow in block"↓ -·> Block scalar↓ -·!!map # Block collection foo : bar↓ | [ "flow in block", "Block scalar\n", { "foo": "bar" } ] |
---|---|
Legend:
s-l+flow-in-block(n)
s-l+block-in-block(n,c)
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.
[198] s-l+block-in-block(n,c) ::=
s-l+block-scalar(n,c)
| s-l+block-collection(n,c)
[199] s-l+block-scalar(n,c) ::=
s-separate(n+1,c)
(
c-ns-properties(n+1,c)
s-separate(n+1,c)
)?
(
c-l+literal(n)
| c-l+folded(n)
)
Example 8.21 Block Scalar Nodes
literal: |2 ··value folded:↓ ···!foo ··>1 ·value | { "literal": "value", "folded": !<!foo> "value" } |
---|---|
Legend:
c-l+literal(n)
c-l+folded(n)
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] versus [BLOCK-IN
context]).
[200] s-l+block-collection(n,c) ::=
(
s-separate(n+1,c)
c-ns-properties(n+1,c)
)?
s-l-comments
(
seq-space(n,c)
| l+block-mapping(n)
)
[201] seq-space(n,BLOCK-OUT) ::= l+block-sequence(n-1)
seq-space(n,BLOCK-IN) ::= l+block-sequence(n)
Example 8.22 Block Collection Nodes
sequence: !!seq - entry - !!seq - nested mapping: !!map foo: bar | { "sequence": [ "entry", [ "nested" ] ], "mapping": { "foo": "bar" } } |
---|---|
Legend:
s-l+block-collection(n,c)
l+block-sequence(n)
l+block-mapping(n)