YAML
是”Yet Another Markup Language”(另一种标记语言)的缩写。但后来项目的维护者将其重命名成了”YAML Ain‘t Markup Language”(YAML 不止是标记语言),以更加强调其面向数据的特性。所以你看,文章的标题,并不是我想标题党,是我真不知道起啥标题好才拿过来用的~。
一个简单的YAML文件
让我们先来看一个YAML
文件的示例,做一个简要的概述。
---
doe: "a deer, a female deer"
ray: "a drop of golden sun"
pi: 3.14159
xmas: true
french-hens: 3
calling-birds:
- huey
- dewey
- louie
- fred
xmas-fifth-day:
calling-birds: four
french-hens: 3
golden-rings: 5
partridges:
count: 1
location: "a pear tree"
turtle-doves: two
文件以三个短横线开头。这些短横线表示新YAML
文档的开始。YAML
支持在单个文件里存放多个文档,解析器会将每组短横线识别为新文档的开始。
接下来,我们将看到构成大部分典型YAML
文档的常用结构:键-值对。Doe
是一个指向字符串值"a deer, a female deer."
的键。
YAML
支持的不仅仅是字符串值。上面的文件以六个键-值对开始。它们的值有四种不同的数据类型。键doe
和ray
的值都是字符串。pi
是一个浮点数。xmas
是一个布尔值。french-hens
是一个整数。可以用单引号或双引号将字符串括起来,也可以根本不用引号。YAML
将无引号的数字识别为整数或浮点数。
第七项是个数组。calling-birds
有四个元素,每个数组元素都由一个短横线开头。
我用两个空格缩进了calling-birds
中的元素。缩进是YAML
表示嵌套的方式。空格缩进的数量可以因文件而异,相同层级的元素左侧对齐即可,但是不允许使用Tab
制表符。
最后,我们看到xmas-fifth-day
,里面还有五个元素,每个元素都缩进了。我们可以将xmas-fifth-day
视为包含两个字符串、两个整数和另一个字典值的字典。YAML
支持这种键值嵌套和混合类型。
在我们深入研究YAML
之前,让我们先看看这个文档用JSON
表示是什么样子。可以在百度或者Google
上搜一下YAML
转JSON
的网页工具,这类工具有很多。
{
"doe": "a deer, a female deer",
"ray": "a drop of golden sun",
"pi": 3.14159,
"xmas": true,
"french-hens": 3,
"calling-birds": [
"huey",
"dewey",
"louie",
"fred"
],
"xmas-fifth-day": {
"calling-birds": "four",
"french-hens": 3,
"golden-rings": 5,
"partridges": {
"count": 1,
"location": "a pear tree"
},
"turtle-doves": "two"
}
}
缩进和空白符
空白符是YAML
格式的一部分,其中换行符表示字段的结束,缩进用于组织YAML文档的结构,用来表示文档的层级或者叫嵌套关系。不过YAML
值允许使用空格符进行缩进,不允许使用制表符Tab
键,这是因为不同的工具对待制表符的方式不同。缩进的空格数目不重要,只要相同层级的元素左侧对齐即可,比如下面这个文档,因为同级元素未对齐,在解析器里会报错
foo: bar
pleh: help
stuff:
foo: bar
bar: foo
所以总结下来记住下面四点即可:
换行符表示字段的结束。 使用缩进表示层级关系。 缩进时不允许使用制表符Tab键,只允许使用空格。 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。
注释
YAML
中的注释以#
号开头。它们可以出现在字段值之后,也可以占据整行。
___
# This is a full line comment
foo: bar # this is a comment, too
YAML数据类型
键-值对是YAML
的基本构建块。YAML
文档中的每一项都是至少一个字典的成员。键的类型始终是字符串。
YAML
的键-值对中的值是标量。它们的表现行为类似于Javascript
和Python
等语言中的标量类型。通常我们只要记住将字符串括在引号中,数字不加引号就足够了,解析器会自动解析出值的类型。
下面我们就详细看一下YAML
的值都支持哪些数据类型,我们先从数组和字典这两种符合类型说起,然后再逐步拆解看里面的普通类型。一般看完这两种复合类型就可以掌握YAML
的基本用法,上手编写和修改YAML
文档了。
数组
YAML
的数组可以写在一行里
items: [ 1, 2, 3, 4, 5 ]
names: [ "one", "two", "three", "four" ]
也可以写在多行里,每一行指定一个元素
---
items:
- 1
- 2
- 3
- 4
- 5
names:
- "one"
- "two"
- "three"
- "four"
多行格式对于包含复杂对象的列表非常有用。
___
items:
- things:
thing1: huey
things2: dewey
thing3: louie
- other things:
key: value
数组可以包含任何有效的YAML
值。同一个数组中的值不必是同一类型。
字典
与数组一样,可以将字典放入单行内。我们在上面看到了这种格式。类型Python
打印字典的格式:
---
foo: { thing1: huey, thing2: louie, thing3: dewey }
也见过在多行里指定字典元素的格式:
---
foo: bar
bar: foo
当然字典也可以自由嵌套,并且持有任何有效的YAML
值。
---
foo:
bar:
- bar
- rab
- plop
数字类型
YAML
可以识别数字类型。我们在上面看到了浮点和整数。YAML
还支持其他几种数字类型。
整数可以用十进制、十六进制或八进制表示,Ox表示一个值是十六进制的,前导零表示一个八进制值。
foo: 12345
bar: 0x12d4
plop: 023332
转换成JSON
后整数都是十进制表示的
{
"foo": 12345,
"bar": 4820,
"plop": 9946
}
YAML
既支持固定浮点数,也支持指数浮点数。
foo: 1230.15
bar: 12.3015e+05
最后YAML
里也可以表示正负无穷和非数字NaN
(Not a Number的缩写)
foo: .inf
bar: -.Inf
plop: .NAN
字符类型
YAML
的字符串为Unicode
编码。在大多数情况下,不必用引号将它们括起来。
foo: this is a normal string
但是如果我们想要处理转义序列,我们需要使用双引号的字符串。
foo: "this is not a normal string\n"
bar: this is not a normal string\n
YAML
将上面第一个值处理为以回车符和换行符结尾。由于第二个值未加引号,因此YAML
将\n
视为两个普通的字符。
foo: this is not a normal string
bar : this is not a normal string\n
YAML
不会对使用单引号的字符串进行转义,但是单引号可以避免将字符串内容解释为文档格式。
字符串值可以写在多行里。使用大于号,可以指定字符串块。
bar: >
this is not a normal string it
spans more than
one line
see?
但是解析器会把他们解析成单行字符串:
bar : this is not a normal string it spans more than one line see?
如果想让YAML
把上面的字符串也解析成多行的,需要使用管道符 |
bar: |
this is not a normal string it
spans more than
one line
see?
Null
YAML
里用波浪号~
或者不带引号的null
直接表示空值。
foo: ~
bar: null
布尔值
YAML
用关键字True
、On
和Yes
表示真。用False
、Off
或No
表示假。
---
foo: True
bar: False
light: On
TV: Off
高级选项
多文档
YAML
文档以三个短横线开始,以三个英文句号结束。一些YAML
处理程序会强制要求文档以三个短横线开始,结束运算符通常是可选的。例如,Java
的Jackson
不会在没有开始的情况下处理YAML
文档,但是Python
的PyYAML
会。
当一个文件包含多个文档时,通常使用文档结束操作符。比如下面这个例子
---
bar: foo
foo: bar
...
---
one: two
three: four
使用下面的Python
脚本解析这个YAML
文件:
import yaml
if __name__ == '__main__':
stream = open("foo.yaml", 'r')
dictionary = yaml.load_all(stream)
for doc in dictionary:
print("New document:")
for key, value in doc.items():
print(key + " : " + str(value))
if type(value) is list:
print(str(len(value)))
脚本会解析出YMAL
文件里的两个文档对象:
New document:
bar : foo
foo : bar
New document:
one : two
three : four
总结
YAML
是一种功能强大的语言,可用于配置文件、应用程序之间的消息和保存应用程序状态。我们介绍了它最常用的特性,包括如何使用内置数据类型和构造复杂文档。它还支持自定义函数、正则表达式这样的高级功能。