本文最后更新于 284 天前 ,文中信息可能已经过时。如有问题请在评论区留言。

YAML (YAML Ain’t Markup Language)是一个可读性高,易于理解,用来表达数据序列化的格式。

语法

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进使用空格,空格数任意,只要相同层级的元素左对齐。不推荐使用 tab,因为在不同系统下 tab 长度可能不一样。
  • 数据结构采用键值对的形式,即 key: value,注意 : 后面要有空格。
  • 字符串一般不使用引号,必要时可使用。使用双引号 " 表示字符串时,会转义字符串中的特殊字符(例如:\n)。使用单引号 ' 时,不会转义字符串中的特殊字符。
  • # 表示注释,可以出现在一行中的任意位置,单行注释
  • 在单一文件中,可使用连续三个连字号 --- 区分多个文件。同时可以使用连续的三个点号 ... 用来表示文件结尾。

数据类型

YAML 支持以下几种数据类型:

  • 纯量(scalars):单个的、不可再分的值
  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes)/ 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence)/ 列表(list)

纯量

纯量是最基本的,不可再分的值,包括:

  • 字符串
  • 布尔值
  • 整数
  • 浮点数
  • Null
  • 时间
  • 日期

示例:

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
boolean:
  - TRUE   # true,True都可以
  - FALSE  # false,False都可以
float:
  - 3.14
  - 6.8523015e+5  # 可以使用科学计数法
int:
  - 123
  - 0b1010_0111_0100_1010_1110    # 二进制表示
null: ~  # 使用 ~ 表示 null
string:
  - 你好YAML
  - 'Hello YAML'  # 可以使用双引号或者单引号包裹特殊字符
  - Hello
    YAML    # 字符串可以拆成多行,每一行会被转化成一个空格
date: 2024-03-23    # 日期必须使用 ISO 8601 格式,即 yyyy-MM-dd
datetime: 2024-03-23T10:41:23+08:00    # 时间使用 ISO 8601 格式,时间和日期之间使用 T 连接,最后使用 + 代表时区

对象

对象键值对使用冒号结构表示:key: value,冒号后面要加一个空格。也可使用 key: {key1: value1, key2: value2, ...}

还可以使用缩进表示层级关系:

yaml
1
2
3
4
5
6
person:
  name: peter
  age: 16

---
person: {name: peter, age: 16}
halo
tips:info
Java 工程中对象属性要添加 <code>get/set 方法</code>,否则无法正确赋值。在 Spring Boot 中也可使用 <code>@ConfigurationProperties</code> 注入对象,效果好于 <code>@Value</code>。

较为复杂的对象格式,可以使用问号加一个空格代表一个复杂的 key,配置一个冒号加一个空格代表一个 value:

yaml
1
2
3
4
5
6
? 
  - complexkey1
  - complexkey2
: 
  - complexvalue1
  - complexvalue2

意思即对象的属性是一个数组 [complexkey1, complexkey2],对应的值也是一个数组 [complexvalue1, complexvalue2]

数组

- 开头的行表示构成一个数组:

yaml
1
2
3
- A
- B
- C

YAML 支持多维数组,可以使用行内表示:

yaml
1
key: [value1, value2, ...]

数据结构的子成员是一个数组,则可以在该项下面缩进一个空格:

yaml
1
2
3
4
-
 - A
 - B
 - C

一个相对复杂的例子:

yaml
1
2
3
4
5
6
7
8
9
books:
  -
    id: 1
    name: 《A》
    price: 20
  -
    id: 2
    name: 《B》
    price: 30

意思是 books 属性是一个数组,每一个数组元素又是由 idnameprice 三个属性构成。

数组也可使用流式(flow)的方式表示:

yaml
1
books: [{id: 1, name: 《A》, price: 20}, {id: 2, name: 《B》, price: 30}]

文本块

如果想引入多行的文本块,可以使用 | 符号,注意在冒号 :| 符号之间要有空格。

yaml
1
2
3
4
person:
  name: |
    Hello YAML!
    Here noob!    

它和加双引号的效果一样,双引号能转义特殊字符:

yaml
1
2
person:
  name: "Hello YAML!\nHere noob!"

显示指定类型

有时需要显式指定某些值的类型,可以使用感叹号 ! 显示指定类型。! 单感叹号通常是自定义类型,!! 双感叹号是内置类型。例如:

yaml
1
2
3
4
5
# 指定为字符串
string: !!str HelloYAML!

# 指定为日期时间类型
datetime: !!timestamp 2024-03-23T13:27:00+08:00

内置类型如下:

内置类型表达式
整数!!int
浮点数!!float
布尔类型!!bool
字符串!!str
日期时间!!timestamp
空值!!null
集合!!set
键值列表或对象列表!!omap!!pairs
序列!!seq
散列表!!map

引用

使用 & 建立锚点,<< 表示合并到当前数据,* 用来引用锚点。

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
defaults: &defaults
  adapter: postgres
  host: localhost

development:
  database: myapp_development
  <<: *defaults

test:
  database: myapp_test
  <<: *defaults

相当于:

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
defaults:
  adapter: postgres
  host: localhost

development:
  database: myapp_development
  adapter: postgres
  host: localhost

test:
  database: myapp_test
  adapter: postgres
  host: localhost

单文件多配置

可以在同一文件中实现多文档分区,即多配置。在 Spring Boot 项目配置文件中,通过 --- 分隔多个不同配置,根据 spring.profiles.active 的值来决定启用哪个配置:

yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 公共配置
spring:
  profiles:
    active: pro  # 指定使用哪个文档块

---
# 开发环境配置
spring:
  profiles: dev  # profiles 属性代表配置的名称

server:
  port: 8080

---
# 生产环境配置
spring:
  profiles: pro

server:
  port: 8081

附录: 完整示例

yaml
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
---  # document start

# Comments in YAML look like this.
# YAML supports single-line comments.

################
# SCALAR TYPES #
################

# Our root object (which continues for the entire document) will be a map,
# which is equivalent to a dictionary, hash or object in other languages.
key: value
another_key: Another value goes here.
a_number_value: 100
scientific_notation: 1e+12
hex_notation: 0x123  # evaluates to 291
octal_notation: 0123 # evaluates to 83

# The number 1 will be interpreted as a number, not a boolean. 
# If you want it to be interpreted as a boolean, use true.
boolean: true
null_value: null
another_null_value: ~
key with spaces: value

# Yes and No (doesn't matter the case) will be evaluated to boolean 
# true and false values respectively.
# To use the actual value use single or double quotes.
no: no            # evaluates to "no": false
yes: No           # evaluates to "yes": false
not_enclosed: yes # evaluates to "not_enclosed": true
enclosed: "yes"   # evaluates to "enclosed": yes

# Notice that strings don't need to be quoted. However, they can be.
however: 'A string, enclosed in quotes.'
'Keys can be quoted too.': "Useful if you want to put a ':' in your key."
single quotes: 'have ''one'' escape pattern'
double quotes: "have many: \", \0, \t, \u263A, \x0d\x0a == \r\n, and more."
# UTF-8/16/32 characters need to be encoded
Superscript two: \u00B2

# Special characters must be enclosed in single or double quotes
special_characters: "[ John ] & { Jane } - <Doe>"

# Multiple-line strings can be written either as a 'literal block' (using |), 
# or a 'folded block' (using '>').
# Literal block turn every newline within the string into a literal newline (\n).
# Folded block removes newlines within the string.
literal_block: |
  This entire block of text will be the value of the 'literal_block' key,
  with line breaks being preserved.

  The literal continues until de-dented, and the leading indentation is
  stripped.

      Any lines that are 'more-indented' keep the rest of their indentation -
      these lines will be indented by 4 spaces.  
folded_style: >
  This entire block of text will be the value of 'folded_style', but this
  time, all newlines will be replaced with a single space.

  Blank lines, like above, are converted to a newline character.

      'More-indented' lines keep their newlines, too -
      this text will appear over two lines.  

# |- and >- removes the trailing blank lines (also called literal/block "strip")
literal_strip: |-
  This entire block of text will be the value of the 'literal_block' key,
  with trailing blank line being stripped.  
block_strip: >-
  This entire block of text will be the value of 'folded_style', but this
  time, all newlines will be replaced with a single space and 
  trailing blank line being stripped.  

# |+ and >+ keeps trailing blank lines (also called literal/block "keep")
literal_keep: |+
  This entire block of text will be the value of the 'literal_block' key,
  with trailing blank line being kept.  

block_keep: >+
  This entire block of text will be the value of 'folded_style', but this
  time, all newlines will be replaced with a single space and 
  trailing blank line being kept.  

####################
# COLLECTION TYPES #
####################

# Nesting uses indentation. 2 space indent is preferred (but not required).
a_nested_map:
  key: value
  another_key: Another Value
  another_nested_map:
    hello: hello

# Maps don't have to have string keys.
0.25: a float key

# Keys can also be complex, like multi-line objects
# We use ? followed by a space to indicate the start of a complex key.
? |
  This is a key
  that has multiple lines  
: and this is its value

# YAML also allows mapping between sequences with the complex key syntax
# Some language parsers might complain
# An example
? - Manchester United
  - Real Madrid
: [ 2001-01-01, 2002-02-02 ]

# Sequences (equivalent to lists or arrays) look like this
# (note that the '-' counts as indentation):
a_sequence:
  - Item 1
  - Item 2
  - 0.5  # sequences can contain disparate types.
  - Item 4
  - key: value
    another_key: another_value
  - - This is a sequence
    - inside another sequence
  - - - Nested sequence indicators
      - can be collapsed

# Since YAML is a superset of JSON, you can also write JSON-style maps and
# sequences:
json_map: { "key": "value" }
json_seq: [ 3, 2, 1, "takeoff" ]
and quotes are optional: { key: [ 3, 2, 1, takeoff ] }

#######################
# EXTRA YAML FEATURES #
#######################

# YAML also has a handy feature called 'anchors', which let you easily duplicate
# content across your document.
# Anchors identified by & character which define the value.
# Aliases identified by * character which acts as "see above" command.
# Both of these keys will have the same value:
anchored_content: &anchor_name This string will appear as the value of two keys.
other_anchor: *anchor_name

# Anchors can be used to duplicate/inherit properties
base: &base
  name: Everyone has same name

# The regexp << is called 'Merge Key Language-Independent Type'. It is used to
# indicate that all the keys of one or more specified maps should be inserted
# into the current map.
# NOTE: If key already exists alias will not be merged
foo:
  <<: *base # doesn't merge the anchor
  age: 10
  name: John
bar:
  <<: *base # base anchor will be merged
  age: 20

# foo and bar would also have name: Everyone has same name

# YAML also has tags, which you can use to explicitly declare types.
# Syntax: !![typeName] [value]
explicit_boolean: !!bool true
explicit_integer: !!int 42
explicit_float: !!float -42.24
explicit_string: !!str 0.5
explicit_datetime: !!timestamp 2022-11-17 12:34:56.78 +9
explicit_null: !!null null

# Some parsers implement language specific tags, like this one for Python's
# complex number type.
python_complex_number: !!python/complex 1+2j

# We can also use yaml complex keys with language specific tags
? !!python/tuple [ 5, 7 ]
: Fifty Seven
# Would be {(5, 7): 'Fifty Seven'} in Python

####################
# EXTRA YAML TYPES #
####################

# Strings and numbers aren't the only scalars that YAML can understand.
# ISO-formatted date and datetime literals are also parsed.
datetime_canonical: 2001-12-15T02:59:43.1Z
datetime_space_separated_with_time_zone: 2001-12-14 21:59:43.10 -5
date_implicit: 2002-12-14
date_explicit: !!timestamp 2002-12-14

# The !!binary tag indicates that a string is actually a base64-encoded
# representation of a binary blob.
gif_file: !!binary |
  R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
  OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+
  +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC
  AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=  

# YAML also has a set type, which looks like this:
set:
  ? item1
  ? item2
  ? item3
or: { item1, item2, item3 }

# Sets are just maps with null values; the above is equivalent to:
set2:
  item1: null
  item2: null
  item3: null

...  # document end

参考