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

示例

fruits:
  - apple1: 
      color: red
  - apple2: 
      color: green
  - pear

上面的 YAML 等同于 JSON:

{
  "fruits": [
    {
      "apple1": {
        "color": "red"
      }
    }, 
    {
      "apple2": {
        "color": "green"
      }
    }, 
    "pear"
  ]
}

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

YAML 的基本结构

缩进符

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

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

具体的例子如下:

- apple1:
  color: red
- apple2:
    color: green

对应的 JSON:

[
  {
    "color": "red", 
    "apple1": null
  }, 
  {
    "apple2": {
      "color": "green"
    }
  }
]

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

-
  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:

- on
- On
- no
- No
- n
- N

解析出的 JSON:

[
  true, 
  true, 
  false, 
  false, 
  "n", 
  "N"
]

int

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

float

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

str

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

示例 YAML:

- a b c
- "a\n\x20b"
- 'a\n\x20b'
- "'\""
- '''"'
- 123 # 有歧义,会被解析成 int
- '123'
- yes # 有歧义,会被解析成 bool
- 'yes'
- a: b # 有歧义,会被解析成 map
- 'a: b'

对应 JSON:

[
  "a b c", 
  "a\n b", 
  "a\\n\\x20b", 
  "'\"", 
  "'\"", 
  123, 
  "123", 
  true, 
  "yes", 
  { "a": "b" }, 
  "a: b"
]

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

其它纯量

其它纯量是很不常用的类型,可以自行查阅(官方文档)[ http://yaml.org/type/]。

类型强转

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

- 123
- !!str 123

对应 JSON:

[
  123, 
  "123"
]

字典(Mapping)和数组(Sequence)

基本用法

字典:

a: b
c: d

对应 JSON:

{
  "a": "b", 
  "c": "d"
}

数组:

- a
- b

对应 JSON:

[
  "a", 
  "b"
]

嵌套使用

字典的 value 为数组:

a:
  - b
  - c
d:
  - e
  - f

对应 JSON:

{
  "a": [
    "b", 
    "c"
  ], 
  "d": [
    "e", 
    "f"
  ]
}

数据的元素为字典:

-
  a: b
- d: e

对应 JSON:

[
  {
    "a": "b"
  }, 
  {
    "d": "e"
  }
]

类 JSON 的行内写法

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

[a, b]

对应 JSON:

[
  "a", 
  "b"
]

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

{a: b}

对应 JSON:

{
  "a": "b"
}

引用

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

name: &name Jason
relation:
  - &info
    name: Sara
    age: 23
  - name: *name
    age: 25
    wife: *info

解析出的对应 JSON:

{
  "relation": [
    {
      "age": 23, 
      "name": "Sara"
    }, 
    {
      "age": 25, 
      "name": "Jason", 
      "wife": {
        "age": 23, 
        "name": "Sara"
      }
    }
  ], 
  "name": "Jason"
}

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

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

name: Sara
age: 23

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