YAML 全名 YAML Ain’t Markup Language,主要设计目标是对人类可读性高。YAML 1.2 是 JSON 的超集,也就是说合法的 JSON 扔给 YAML 1.2 解析器是可以被完美解析的。YAML 集 JSON 和 XML 等各种标记语言之长,进行了扩展强化,功能全面也很易读,很多的系统采用它作为配置文件的格式。

示例

1
2
3
4
5
6
fruits:
- apple1:
color: red
- apple2:
color: green
- pear

上面的 YAML 等同于 JSON:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"fruits": [
{
"apple1": {
"color": "red"
}
},
{
"apple2": {
"color": "green"
}
},
"pear"
]
}

是不是看上去简洁了很多,也更容易阅读很多?

YAML 的基本结构

缩进符

YAML 的缩进只能用空格而不能用 tab,一个主要的原因是不同的系统对 tab 的处理不完全一致(比如有的系统把 tab 处理成 4 个空格,有的系统把 tab 处理成 8 个空格)。好在现代的文本编辑器基本都支持把 tab 转换成指定数量的空格。

YAML 里的元素都是用缩进来匹配层级关系的,简单说就是缩进相同的都是同级元素,缩进比上一个元素长就是上一个元素的子元素。

具体的例子如下:

1
2
3
4
- apple1:
color: red
- apple2:
color: green

对应的 JSON:

1
2
3
4
5
6
7
8
9
10
11
[
{
"color": "red",
"apple1": null
},
{
"apple2": {
"color": "green"
}
}
]

请自行体会,我就不展开了。为了方便理解说一下前面的 YAML 等同于:

1
2
3
4
5
6
-
apple1:
color: red
-
apple2:
color: green

分隔符

只要不是行首的缩进符,其它地方的词法分隔符是可以用各种 white space 字符的。但是要注意这是 YAML 1.2 的规则,在 YAML 1.1 里还是严禁用 tab 作分隔符的。我认为 YAML 1.2 做出这样的更改主要也是为了兼容 JSON。目前解析 YAML 的大部分库还是仅支持 YAML 1.1,所以为了兼容性,分隔符最好还是不要用 tab

注释

YAML 使用 “#” 来进行注释,”#” 及在其之后的当行内容将被忽略。注意 “#” 如果跟在别的元素后面,和元素之间需要用 white space 字符隔开。

多行文本的种种

说起来会絮絮叨叨的,懒得说了……请自行看官网文档

YAML 的纯量(Scalar)

这就是大部分语言里的基础类型,YAML 里常用的纯量有以下类型:

null

~ / null / Null / NULL 还有空字符都被解析成 null 类型,最标准的写法是 ~

bool

最新标准里 y / Y / yes / Yes / YES / n / N / no / No / NO / true / True / TRUE / false / False / FALSE / on / On / ON / off / Off / OFF 全部都会被解析成正确的 bool 类型,为了兼容性比较好建议用 truefalse

举个例子,我使用的在线解析器解析如下 YAML:

1
2
3
4
5
6
- on
- On
- no
- No
- n
- N

解析出的 JSON:

1
2
3
4
5
6
7
8
[
true,
true,
false,
false,
"n",
"N"
]

int

很常规就不多介绍了,YAML 支持 8 进制和 16 进制格式的数据,甚至 2 进制和 60 进制。

float

支持常规的浮点数,支持科学计数法,还支持无穷大和 NaN。详情可以参考 tag:yaml.org,2002:float

str

大部分情况下,YAML 里的字串是不需要带引号的,某些容易引起解析歧义的字串可以用引号括起来。

示例 YAML:

1
2
3
4
5
6
7
8
9
10
11
- a b c
- "a b c"
- 'a b c'
- "'\""
- '''"'
- 123 # 有歧义,会被解析成 int
- '123'
- yes # 有歧义,会被解析成 bool
- 'yes'
- a: b # 有歧义,会被解析成 map
- 'a: b'

对应 JSON:

1
2
3
4
5
6
7
8
9
10
11
12
13
[
"a b c",
"a b c",
"a b c",
"'\"",
"'\"",
123,
"123",
true,
"yes",
{ "a": "b" },
"a: b"
]

顺带说明下双引号会对转义符进行操作,而单引号不会。双引号内包含双引号可以用 \" 来表示,单引号内包含单引号可以用 '' 来表示。

其它纯量

其它纯量是很不常用的类型,可以自行查阅官方文档

类型强转

另外要提一点,YAML 支持类型强转:

1
2
- 123
- !!str 123

对应 JSON:

1
2
3
4
[
123,
"123"
]

字典(Mapping)和数组(Sequence)

基本用法

字典:

1
2
a: b
c: d

对应 JSON:

1
2
3
4
{
"a": "b",
"c": "d"
}

数组:

1
2
- a
- b

对应 JSON:

1
2
3
4
[
"a",
"b"
]

嵌套使用

字典的 value 为数组:

1
2
3
4
5
6
a:
- b
- c
d:
- e
- f

对应 JSON:

1
2
3
4
5
6
7
8
9
10
{
"a": [
"b",
"c"
],
"d": [
"e",
"f"
]
}

数据的元素为字典:

1
2
3
-
a: b
- d: e

对应 JSON:

1
2
3
4
5
6
7
8
[
{
"a": "b"
},
{
"d": "e"
}
]

类 JSON 的行内写法

数组有一种类似 JSON 的写法,可以完成行内数组的功能,当然和 JSON 一样写成多行的也可以:

1
[a, b]

对应 JSON:

1
2
3
4
[
"a",
"b"
]

字典也可以用类似 JSON 的方法写成行内的:

1
{a: b}

对应 JSON:

1
2
3
{
"a": "b"
}

引用

引用是 YAML 的一个很方便的高级语法,示例如下:

1
2
3
4
5
6
7
8
name: &name Jason
relation:
- &info
name: Sara
age: 23
- name: *name
age: 25
wife: *info

解析出的对应 JSON:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"relation": [
{
"age": 23,
"name": "Sara"
},
{
"age": 25,
"name": "Jason",
"wife": {
"age": 23,
"name": "Sara"
}
}
],
"name": "Jason"
}

可以看到基本的规则就是用 & 声明一个引用,然后在其他地方用 * 进行展开,有点像 c 语言的指针操作。

引用的部分就是在 & 之后的整个子元素,上面例子里 &name 引用的是 Jason,而 &info 引用的是:

1
2
name: Sara
age: 23

在后面使用对应的名称展开后就得到了最终的 JSON 内容。

总结

到此 YAML 的基本语法就介绍得差不多了,更多的内容可以参考以下内容来继续深入阅读:

YAML 官方网站:http://yaml.org/

阮一峰 - 《YAML 语言教程》:http://www.ruanyifeng.com/blog/2016/07/yaml.html

YAML 在线解析:http://yaml-online-parser.appspot.com/

YAML 合法性校验:http://www.yamllint.com/