一、简介
YAML 是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 格式方便。
基本语法规则如下:
- 大小写敏感
- 使用缩进表示层级关系
- 缩进时不允许使用Tab键,只允许使用空格。
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
#
表示注释
YAML 支持的数据结构有三种。
- 对象:
键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
- 数组:
一组按次序排列的值,又称为序列(sequence) / 列表(list)
- 纯量(scalars):
单个的、不可再分的值
二、对象
对象的一组键值对,使用冒号结构表示。
1 2
| animal: pets hash: { name: Steve, foo: bar }
|
转为JavaScript :
1 2
| { animal: 'pets' } { hash: { name: 'Steve', foo: 'bar' } }
|
三、数组
一组连词线开头的行,构成一个数组。
转为 JavaScript
1
| [ 'Cat', 'Dog', 'Goldfish' ]
|
嵌套数组,则在该项下面缩进一个空格。
1 2 3 4
| - - Cat - Dog - Goldfish
|
转为JS :
1
| [ [ 'Cat', 'Dog', 'Goldfish' ] ]
|
数组也可以采用行内表示法。
转为 JavaScript
1
| { animal: [ 'Cat', 'Dog' ] }
|
四、复合结构
对象和数组可以结合使用,形成复合结构。
1 2 3 4 5 6 7 8 9
| languages: - Ruby - Perl - Python websites: YAML: yaml.org Ruby: ruby-lang.org Python: python.org Perl: use.perl.org
|
转为 JavaScript 如下。
1 2 3 4 5 6
| { languages: [ 'Ruby', 'Perl', 'Python' ], websites: { YAML: 'yaml.org', Ruby: 'ruby-lang.org', Python: 'python.org', Perl: 'use.perl.org' } }
|
五、纯量
纯量是最基本的、不可再分的值。以下数据类型都属于 JavaScript 的纯量。
- 字符串
- 布尔值
- 整数
- 浮点数
- Null
- 时间
- 日期
表示如下:
- 数值直接以字面量的形式表示。
- 布尔值用
true
和false
表示。
null
用~
表示。
- 时间采用 ISO8601 格式。
- 日期采用复合 iso8601 格式的年、月、日表示。
- YAML 允许使用两个感叹号,强制转换数据类型。
1 2 3 4 5 6 7 8 9 10 11 12
| number: 12.30
isSet: true
parent: ~
iso8601: 2001-12-14t21:59:43.10-05:00
date: 1976-07-31
e: !!str 123
|
对应的js
1 2 3 4 5 6
| { number: 12.30 } { isSet: true } { parent: null } { iso8601: new Date('2001-12-14t21:59:43.10-05:00') } { date: new Date('1976-07-31') } { e: '123'}
|
六、字符串
- 字符串默认不使用引号表示
- 如果字符串之中包含空格或特殊字符,需要放在引号之中
- 单引号和双引号都可以使用,双引号不会对特殊字符转义。
- 单引号之中如果还有单引号,必须连续使用两个单引号转义。
- 字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格。
- 多行字符串可以使用
|
保留换行符,也可以使用>
折叠换行。
+
表示保留文字块末尾的换行,-
表示删除字符串末尾的换行。
- 字符串之中可以插入 HTML 标记。
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
| str: 这是一行字符串
str: '内容: 字符串'
s1: '内容\n字符串' s2: "内容\n字符串"
str: 'labor''s day'
str: 这是一段 多行 字符串
this: | Foo Bar that: > Foo Bar
s1: | Foo
s2: |+ Foo
s3: |- Foo
message: |
<p style="color: red"> 段落 </p>
|
转为 JavaScript 如下。
1 2 3 4 5 6 7 8
| { str: '这是一行字符串' } { str: '内容: 字符串' } { s1: '内容\\n字符串', s2: '内容\n字符串' } { str: 'labor\'s day' } { str: '这是一段 多行 字符串' } { this: 'Foo\nBar\n', that: 'Foo Bar\n' } { s1: 'Foo\n', s2: 'Foo\n\n\n', s3: 'Foo' } { message: '\n<p style="color: red">\n 段落\n</p>\n' }
|
七、引用
锚点&
和别名*
,可以用来引用
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
|
等同于下面的代码。
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
|
&
用来建立锚点(defaults
),<<
表示合并到当前数据,*
用来引用锚点。
1 2 3 4 5
| - &showell Steve - Clark - Brian - Oren - *showell
|
转为 JavaScript 代码如下。
1
| [ 'Steve', 'Clark', 'Brian', 'Oren', 'Steve' ]
|
八、分段
在同一个yaml文件中,可以用 — 来分段,这样可以将多个文档写在一个文件中
1 2 3 4 5 6
| --- name: James age: 20 --- name: Lily age: 19
|
和python交互
PyYaml
load() :返回一个对象
1 2 3 4 5 6 7 8 9 10 11
| name: Tom Smith age: 37 spouse: name: Jane Smith age: 25 children: - name: Jimmy Smith age: 15 - name1: Jenny Smith age1: 12
|
1 2 3 4 5 6
| import yaml f = open('config.yaml') y = yaml.load(f) print(y)
|
load_all()生成一个迭代器
如果string或文件包含几块yaml文档,你可以使用yaml.load_all来解析全部的文档。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import yaml
f = ''' --- name: James age: 20 --- name: Lily age: 19 '''
y = yaml.load_all(f) for data in y: print(data)
|
yaml.dump 将一个python对象生成为yaml文档
1 2 3 4 5 6 7 8 9 10 11
| import yaml
aproject = {'name': 'Silenthand Olleander', 'race': 'Human', 'traits': ['ONE_HAND', 'ONE_EYE'] }
print(yaml.dump(aproject,))
|
yaml.dump接收的第二个参数一定要是一个打开的文本文件或二进制文件,yaml.dump会把生成的yaml文档写到文件里
1 2 3 4 5 6 7 8
| import yaml
aproject = {'name': 'Silenthand Olleander', 'race': 'Human', 'traits': ['ONE_HAND', 'ONE_EYE'] } f = open('config.yaml','w') print(yaml.dump(aproject,f))
|
yaml.dump_all()将多个段输出到一个文件中
1 2 3 4 5 6 7
| import yaml
obj1 = {"name": "James", "age": 20} obj2 = ["Lily", 19]
with open('config.yaml', 'w') as f: yaml.dump_all([obj1, obj2], f)
|
构造器、表示器、解析器
构造器(constructors)、表示器(representers)、解析器(resolvers )
1、yaml.YAMLObject
yaml.YAMLObject用元类来注册一个构造器(也就是代码里的 init() 方法),让你把yaml节点转为Python对象实例,用表示器(也就是代码里的 repr() 函数)来让你把Python对象转为yaml节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import yaml
class Person(yaml.YAMLObject): yaml_tag = '!person'
def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return '%s(name=%s, age=%d)' % (self.__class__.__name__, self.name, self.age)
james = Person('James', 20) print(yaml.dump(james))
lily = yaml.load('!person {name: Lily, age: 19}') print(lily)
|
2、yaml.add_constructor 和 yaml.add_representer
你可能在使用过程中并不想通过上面这种元类的方式,而是想定义正常的类,那么,可以用这两种方法
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
| import yaml
class Person(object): def __init__(self, name, age): self.name = name self.age = age
def __repr__(self): return 'Person(%s, %s)' % (self.name, self.age)
james = Person('James', 20) print (yaml.dump(james))
def person_repr(dumper, data): return dumper.represent_mapping(u'!person', {"name": data.name, "age": data.age})
yaml.add_representer(Person, person_repr) print (yaml.dump(james))
def person_cons(loader, node): value = loader.construct_mapping(node) name = value['name'] age = value['age'] return Person(name, age)
yaml.add_constructor(u'!person', person_cons) lily = yaml.load('!person {name: Lily, age: 19}') print (lily)
|