2022.06.17
结构6.1. Indentation Spaces6.2. Separation Spaces6.3. Line Prefixes6.4. Empty Lines6.5. Line Folding6.6. Comments6.7. Separation Lines6.8. Directives6.8.1. “YAML
” Directives6.8.2. “TAG
” Directives6.8.2.1. Tag Handles6.8.2.2. Tag Prefixes6.9. Node Properties6.9.1. Node Tags6.9.2. Node Anchors
本文按照YAML官方文档1.2.2版本翻译总结而成
https://yaml.org/spec/1.2.2/#chapter-6-structural-productions
In YAML block styles, structure is determined by indentation. In general, indentation is defined as a zero or more space characters at the start of a line.
To maintain portability, tab characters must not be used in indentation, since different systems treat tabs differently. Note that most modern editors may be configured so that pressing the tab key results in the insertion of an appropriate number of spaces.
The amount of indentation is a presentation detail and must not be used to convey content information.
[63]
s-indent(0) ::=
<empty>
# When n≥0
s-indent(n+1) ::=
s-space s-indent(n)
A block style construct is terminated when encountering a line which is less indented than the construct. The productions use the notation “s-indent-less-than(n)
” and “s-indent-less-or-equal(n)
” to express this.
[64]
s-indent-less-than(1) ::=
<empty>
# When n≥1
s-indent-less-than(n+1) ::=
s-space s-indent-less-than(n)
| <empty>
[65]
s-indent-less-or-equal(0) ::=
<empty>
# When n≥0
s-indent-less-or-equal(n+1) ::=
s-space s-indent-less-or-equal(n)
| <empty>
Each node must be indented further than its parent node. All sibling nodes must use the exact same indentation level. However the content of each sibling node may be further indented independently.
Example 6.1 Indentation Spaces
··# Leading comment line spaces are ···# neither content nor indentation. ···· Not indented: ·By one space: | ····By four ······spaces ·Flow style: [ # Leading spaces ···By two, # in flow style ··Also by two, # are neither ··→Still by two # content nor ····] # indentation. | { "Not indented": { "By one space": "By four\n spaces\n", "Flow style": [ "By two", "Also by two", "Still by two" ] } } |
---|---|
Legend:
s-indent(n)
Content
Neither content nor indentation
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.
Example 6.2 Indentation Indicators
?·a :·-→b ··-··-→c ·····-·d | { "a": [ "b", [ "c", "d" ] ] } |
---|---|
Legend:
Total Indentation
s-indent(n)
Indicator as indentation
Outside indentation and scalar content, YAML uses white space characters for separation between tokens within a line. Note that such white space may safely include tab characters.
Separation spaces are a presentation detail and must not be used to convey content information.
[66] s-separate-in-line ::=
s-white+
| <start-of-line>
Example 6.3 Separation Spaces
-·foo:→·bar - -·baz -→baz | [ { "foo": "bar" }, [ "baz", "baz" ] ] |
---|---|
Legend:
s-separate-in-line
Inside scalar content, each line begins with a non-content line prefix. This prefix always includes the indentation. For flow scalar styles it additionally includes all leading white space, which may contain tab characters.
Line prefixes are a presentation detail and must not be used to convey content information.
[67]
s-line-prefix(n,BLOCK-OUT) ::= s-block-line-prefix(n)
s-line-prefix(n,BLOCK-IN) ::= s-block-line-prefix(n)
s-line-prefix(n,FLOW-OUT) ::= s-flow-line-prefix(n)
s-line-prefix(n,FLOW-IN) ::= s-flow-line-prefix(n)
[68] s-block-line-prefix(n) ::=
s-indent(n)
[69] s-flow-line-prefix(n) ::=
s-indent(n)
s-separate-in-line?
Example 6.4 Line Prefixes
plain: text ··lines quoted: "text ··→lines" block: | ··text ···→lines | { "plain": "text lines", "quoted": "text lines", "block": "text\n \tlines\n" } |
---|---|
Legend:
s-flow-line-prefix(n)
s-block-line-prefix(n)
s-indent(n)
An empty line line consists of the non-content prefix followed by a line break.
[70] l-empty(n,c) ::=
(
s-line-prefix(n,c)
| s-indent-less-than(n)
)
b-as-line-feed
The semantics of empty lines depend on the scalar style they appear in. This is handled on a case-by-case basis by the relevant productions.
Example 6.5 Empty Lines
Folding: "Empty line ···→ as a line feed" Chomping: | Clipped empty lines · | { "Folding": "Empty line\nas a line feed", "Chomping": "Clipped empty lines\n" } |
---|---|
Legend:
l-empty(n,c)
Line folding allows long lines to be broken for readability, while retaining the semantics of the original long line. If a line break is followed by an empty line, it is trimmed; the first line break is discarded and the rest are retained as content.
[71] b-l-trimmed(n,c) ::=
b-non-content
l-empty(n,c)+
Otherwise (the following line is not empty), the line break is converted to a single space (x20
).
[72] b-as-space ::=
b-break
A folded non-empty line may end with either of the above line breaks.
[73] b-l-folded(n,c) ::=
b-l-trimmed(n,c) | b-as-space
Example 6.6 Line Folding
>- trimmed↓ ··↓ ·↓ ↓ as↓ space | "trimmed\n\n\nas space" |
---|---|
Legend:
b-l-trimmed(n,c)
b-as-space
The above rules are common to both the folded block style and the scalar flow styles. Folding does distinguish between these cases in the following way:
Block Folding
In the folded block style, the final line break and trailing empty lines are subject to chomping and are never folded. In addition, folding does not apply to line breaks surrounding text lines that contain leading white space. Note that such a more-indented line may consist only of such leading white space.
The combined effect of the block line folding rules is that each “paragraph” is interpreted as a line, empty lines are interpreted as a line feed and the formatting of more-indented lines is preserved.
Example 6.7 Block Folding
> ··foo·↓ ·↓ ··→·bar↓ ↓ ··baz↓ | "foo \n\n\t bar\n\nbaz\n" |
---|---|
Legend:
b-l-folded(n,c)
Non-content spaces
Content spaces
Flow Folding
Folding in flow styles provides more relaxed semantics. Flow styles typically depend on explicit indicators rather than indentation to convey structure. Hence spaces preceding or following the text in a line are a presentation detail and must not be used to convey content information. Once all such spaces have been discarded, all line breaks are folded without exception.
The combined effect of the flow line folding rules is that each “paragraph” is interpreted as a line, empty lines are interpreted as line feeds and text can be freely more-indented without affecting the content information.
[74] s-flow-folded(n) ::=
s-separate-in-line?
b-l-folded(n,FLOW-IN)
s-flow-line-prefix(n)
Example 6.8 Flow Folding
"↓ ··foo·↓ ·↓ ··→·bar↓ ↓ ··baz↓ " | " foo\nbar\nbaz " |
---|---|
Legend:
s-flow-folded(n)
Non-content spaces
An explicit comment is marked by a “#
” indicator. Comments are a presentation detail and must not be used to convey content information.
Comments must be separated from other tokens by white space characters.
Note: To ensure JSON compatibility, YAML processors must allow for the omission of the final comment line break of the input stream. However, as this confuses many tools, YAML processors should terminate the stream with an explicit line break on output.
[75] c-nb-comment-text ::=
c-comment # '#'
nb-char*
[76] b-comment ::=
b-non-content
| <end-of-input>
[77] s-b-comment ::=
(
s-separate-in-line
c-nb-comment-text?
)?
b-comment
Example 6.9 Separated Comment
key:····# Comment↓ value*eof* | { "key": "value" } |
---|---|
Legend:
c-nb-comment-text
b-comment
s-b-comment
Outside scalar content, comments may appear on a line of their own, independent of the indentation level. Note that outside scalar content, a line containing only white space characters is taken to be a comment line.
[78] l-comment ::=
s-separate-in-line
c-nb-comment-text?
b-comment
Example 6.10 Comment Lines
··# Comment↓ ···↓ ↓ | # This stream contains no # documents, only comments. |
---|---|
Legend:
s-b-comment
l-comment
In most cases, when a line may end with a comment, YAML allows it to be followed by additional comment lines. The only exception is a comment ending a block scalar header.
[79] s-l-comments ::=
(
s-b-comment
| <start-of-line>
)
l-comment*
Example 6.11 Multi-Line Comments
key:····# Comment↓ ········# lines↓ value↓ ↓ | { "key": "value" } |
---|---|
Legend:
s-b-comment
l-comment
s-l-comments
Implicit keys are restricted to a single line. In all other cases, YAML allows tokens to be separated by multi-line (possibly empty) comments.
Note that structures following multi-line comment separation must be properly indented, even though there is no such restriction on the separation comment lines themselves.
[80]
s-separate(n,BLOCK-OUT) ::= s-separate-lines(n)
s-separate(n,BLOCK-IN) ::= s-separate-lines(n)
s-separate(n,FLOW-OUT) ::= s-separate-lines(n)
s-separate(n,FLOW-IN) ::= s-separate-lines(n)
s-separate(n,BLOCK-KEY) ::= s-separate-in-line
s-separate(n,FLOW-KEY) ::= s-separate-in-line
[81] s-separate-lines(n) ::=
(
s-l-comments
s-flow-line-prefix(n)
)
| s-separate-in-line
Example 6.12 Separation Spaces
{·first:·Sammy,·last:·Sosa·}:↓ # Statistics: ··hr:··# Home runs ·····65 ··avg:·# Average ···0.278 | { { "first": "Sammy", "last": "Sosa" }: { "hr": 65, "avg": 0.278 } } |
---|---|
Legend:
s-separate-in-line
s-separate-lines(n)
s-indent(n)
Directives are instructions to the YAML processor. This specification defines two directives, “YAML
” and “TAG
”, and reserves all other directives for future use. There is no way to define private directives. This is intentional.
Directives are a presentation detail and must not be used to convey content information.
[82] l-directive ::=
c-directive # '%'
(
ns-yaml-directive
| ns-tag-directive
| ns-reserved-directive
)
s-l-comments
Each directive is specified on a separate non-indented line starting with the “%
” indicator, followed by the directive name and a list of parameters. The semantics of these parameters depends on the specific directive. A YAML processor should ignore unknown directives with an appropriate warning.
[83] ns-reserved-directive ::=
ns-directive-name
(
s-separate-in-line
ns-directive-parameter
)*
[84] ns-directive-name ::=
ns-char+
[85] ns-directive-parameter ::=
ns-char+
Example 6.13 Reserved Directives
%FOO bar baz # Should be ignored # with a warning. --- "foo" | "foo" |
---|---|
Legend:
ns-reserved-directive
ns-directive-name
ns-directive-parameter
YAML
” DirectivesThe “YAML
” directive specifies the version of YAML the document conforms to. This specification defines version “1.2
”, including recommendations for YAML 1.1 processing.
A version 1.2 YAML processor must accept documents with an explicit “%YAML 1.2
” directive, as well as documents lacking a “YAML
” directive. Such documents are assumed to conform to the 1.2 version specification. Documents with a “YAML
” directive specifying a higher minor version (e.g. “%YAML 1.3
”) should be processed with an appropriate warning. Documents with a “YAML
” directive specifying a higher major version (e.g. “%YAML 2.0
”) should be rejected with an appropriate error message.
A version 1.2 YAML processor must also accept documents with an explicit “%YAML 1.1
” directive. Note that version 1.2 is mostly a superset of version 1.1, defined for the purpose of ensuring JSON compatibility. Hence a version 1.2 processor should process version 1.1 documents as if they were version 1.2, giving a warning on points of incompatibility (handling of non-ASCII line breaks, as described above).
[86] ns-yaml-directive ::=
"YAML"
s-separate-in-line
ns-yaml-version
[87] ns-yaml-version ::=
ns-dec-digit+
'.'
ns-dec-digit+
Example 6.14 “YAML
” directive
%YAML 1.3 # Attempt parsing # with a warning --- "foo" | "foo" |
---|---|
Legend:
ns-yaml-directive
ns-yaml-version
It is an error to specify more than one “YAML
” directive for the same document, even if both occurrences give the same version number.
Example 6.15 Invalid Repeated YAML directive
%YAML 1.2 %YAML 1.1 foo | ERROR: The YAML directive must only be given at most once per document. |
---|---|
TAG
” DirectivesThe “TAG
” directive establishes a tag shorthand notation for specifying node tags. Each “TAG
” directive associates a handle with a prefix. This allows for compact and readable tag notation.
[88] ns-tag-directive ::=
"TAG"
s-separate-in-line
c-tag-handle
s-separate-in-line
ns-tag-prefix
Example 6.16 “TAG
” directive
%TAG !yaml! tag:yaml.org,2002: --- !yaml!str "foo" | "foo" |
---|---|
Legend:
ns-tag-directive
c-tag-handle
ns-tag-prefix
It is an error to specify more than one “TAG
” directive for the same handle in the same document, even if both occurrences give the same prefix.
Example 6.17 Invalid Repeated TAG directive
%TAG ! !foo %TAG ! !foo bar | ERROR: The TAG directive must only be given at most once per handle in the same document. |
---|---|
The tag handle exactly matches the prefix of the affected tag shorthand. There are three tag handle variants:
[89] c-tag-handle ::=
c-named-tag-handle
| c-secondary-tag-handle
| c-primary-tag-handle
Primary Handle
The primary tag handle is a single “!
” character. This allows using the most compact possible notation for a single “primary” name space. By default, the prefix associated with this handle is “!
”. Thus, by default, shorthands using this handle are interpreted as local tags.
It is possible to override the default behavior by providing an explicit “TAG
” directive, associating a different prefix for this handle. This provides smooth migration from using local tags to using global tags by the simple addition of a single “TAG
” directive.
[90] c-primary-tag-handle ::= '!'
Example 6.18 Primary Tag Handle
# Private !foo "bar" ... # Global %TAG ! tag:example.com,2000:app/ --- !foo "bar" | !<!foo> "bar" --- !<tag:example.com,2000:app/foo> "bar" |
---|---|
Legend:
c-primary-tag-handle
Secondary Handle
The secondary tag handle is written as “!!
”. This allows using a compact notation for a single “secondary” name space. By default, the prefix associated with this handle is “tag:yaml.org,2002:
”.
It is possible to override this default behavior by providing an explicit “TAG
” directive associating a different prefix for this handle.
[91] c-secondary-tag-handle ::= "!!"
Example 6.19 Secondary Tag Handle
%TAG !! tag:example.com,2000:app/ --- !!int 1 - 3 # Interval, not integer | !<tag:example.com,2000:app/int> "1 - 3" |
---|---|
Legend:
c-secondary-tag-handle
Named Handles
A named tag handle surrounds a non-empty name with “!
” characters. A handle name must not be used in a tag shorthand unless an explicit “TAG
” directive has associated some prefix with it.
The name of the handle is a presentation detail and must not be used to convey content information. In particular, the YAML processor need not preserve the handle name once parsing is completed.
[92] c-named-tag-handle ::=
c-tag # '!'
ns-word-char+
c-tag # '!'
Example 6.20 Tag Handles
%TAG !e! tag:example.com,2000:app/ --- !e!foo "bar" | !<tag:example.com,2000:app/foo> "bar" |
---|---|
Legend:
c-named-tag-handle
There are two tag prefix variants:
[93] ns-tag-prefix ::=
c-ns-local-tag-prefix | ns-global-tag-prefix
Local Tag Prefix
If the prefix begins with a “!
” character, shorthands using the handle are expanded to a local tag. Note that such a tag is intentionally not a valid URI and its semantics are specific to the application. In particular, two documents in the same stream may assign different semantics to the same local tag.
[94] c-ns-local-tag-prefix ::=
c-tag # '!'
ns-uri-char*
Example 6.21 Local Tag Prefix
%TAG !m! !my- --- # Bulb here !m!light fluorescent ... %TAG !m! !my- --- # Color here !m!light green | !<!my-light> "fluorescent" --- !<!my-light> "green" |
---|---|
Legend:
c-ns-local-tag-prefix
Global Tag Prefix
If the prefix begins with a character other than “!
”, it must be a valid URI prefix, and should contain at least the scheme. Shorthands using the associated handle are expanded to globally unique URI tags and their semantics is consistent across applications. In particular, every document in every stream must assign the same semantics to the same global tag.
[95] ns-global-tag-prefix ::=
ns-tag-char
ns-uri-char*
Example 6.22 Global Tag Prefix
%TAG !e! tag:example.com,2000:app/ --- - !e!foo "bar" | - !<tag:example.com,2000:app/foo> "bar" |
---|---|
Legend:
ns-global-tag-prefix
Each node may have two optional properties, anchor and tag, in addition to its content. Node properties may be specified in any order before the node’s content. Either or both may be omitted.
[96] c-ns-properties(n,c) ::=
(
c-ns-tag-property
(
s-separate(n,c)
c-ns-anchor-property
)?
)
| (
c-ns-anchor-property
(
s-separate(n,c)
c-ns-tag-property
)?
)
Example 6.23 Node Properties
!!str &a1 "foo": !!str bar &a2 baz : *a1 | { &B1 "foo": "bar", "baz": *B1 } |
---|---|
Legend:
c-ns-properties(n,c)
c-ns-anchor-property
c-ns-tag-property
The tag property identifies the type of the native data structure presented by the node. A tag is denoted by the “!
” indicator.
[97] c-ns-tag-property ::=
c-verbatim-tag
| c-ns-shorthand-tag
| c-non-specific-tag
Verbatim Tags
A tag may be written verbatim by surrounding it with the “<
” and “>
” characters. In this case, the YAML processor must deliver the verbatim tag as-is to the application. In particular, verbatim tags are not subject to tag resolution. A verbatim tag must either begin with a “!
” (a local tag) or be a valid URI (a global tag).
[98] c-verbatim-tag ::=
"!<"
ns-uri-char+
'>'
Example 6.24 Verbatim Tags
!<tag:yaml.org,2002:str> foo : !<!bar> baz | { "foo": !<!bar> "baz" } |
---|---|
Legend:
c-verbatim-tag
Example 6.25 Invalid Verbatim Tags
- !<!> foo - !<$:?> bar | ERROR: - Verbatim tags aren't resolved, so ! is invalid. - The $:? tag is neither a global URI tag nor a local tag starting with '!'. |
---|---|
Tag Shorthands
A tag shorthand consists of a valid tag handle followed by a non-empty suffix. The tag handle must be associated with a prefix, either by default or by using a “TAG
” directive. The resulting parsed tag is the concatenation of the prefix and the suffix and must either begin with “!
” (a local tag) or be a valid URI (a global tag).
The choice of tag handle is a presentation detail and must not be used to convey content information. In particular, the tag handle may be discarded once parsing is completed.
The suffix must not contain any “!
” character. This would cause the tag shorthand to be interpreted as having a named tag handle. In addition, the suffix must not contain the “[
”, “]
”, “{
”, “}
” and “,
” characters. These characters would cause ambiguity with flow collection structures. If the suffix needs to specify any of the above restricted characters, they must be escaped using the “%
” character. This behavior is consistent with the URI character escaping rules (specifically, section 2.3 of URI RFC).
[99] c-ns-shorthand-tag ::=
c-tag-handle
ns-tag-char+
Example 6.26 Tag Shorthands
%TAG !e! tag:example.com,2000:app/ --- - !local foo - !!str bar - !e!tag%21 baz | [ !<!local> "foo", !<tag:yaml.org,2002:str> "bar", !<tag:example.com,2000:app/tag!> "baz" ] |
---|---|
Legend:
c-ns-shorthand-tag
Example 6.27 Invalid Tag Shorthands
%TAG !e! tag:example,2000:app/ --- - !e! foo - !h!bar baz | ERROR: - The !e! handle has no suffix. - The !h! handle wasn't declared. |
---|---|
Non-Specific Tags
If a node has no tag property, it is assigned a non-specific tag that needs to be resolved to a specific one. This non-specific tag is “!
” for non-plain scalars and “?
” for all other nodes. This is the only case where the node style has any effect on the content information.
It is possible for the tag property to be explicitly set to the “!
” non-specific tag. By convention, this “disables” tag resolution, forcing the node to be interpreted as “tag:yaml.org,2002:seq
”, “tag:yaml.org,2002:map
” or “tag:yaml.org,2002:str
”, according to its kind.
There is no way to explicitly specify the “?
” non-specific tag. This is intentional.
[100] c-non-specific-tag ::= '!'
Example 6.28 Non-Specific Tags
# Assuming conventional resolution: - "12" - 12 - ! 12 | [ "12", 12, "12" ] |
---|---|
Legend:
c-non-specific-tag
An anchor is denoted by the “&
” indicator. It marks a node for future reference. An alias node can then be used to indicate additional inclusions of the anchored node. An anchored node need not be referenced by any alias nodes; in particular, it is valid for all nodes to be anchored.
[101] c-ns-anchor-property ::=
c-anchor # '&'
ns-anchor-name
Note that as a serialization detail, the anchor name is preserved in the serialization tree. However, it is not reflected in the representation graph and must not be used to convey content information. In particular, the YAML processor need not preserve the anchor name once the representation is composed.
Anchor names must not contain the “[
”, “]
”, “{
”, “}
” and “,
” characters. These characters would cause ambiguity with flow collection structures.
[102] ns-anchor-char ::=
ns-char - c-flow-indicator
[103] ns-anchor-name ::=
ns-anchor-char+
Example 6.29 Node Anchors
First occurrence: &anchor Value Second occurrence: *anchor | { "First occurrence": &A "Value", "Second occurrence": *A } |
---|---|
Legend:
c-ns-anchor-property
ns-anchor-name