最近使用PyYAML处理YAML文件,做个记录。
关于Node
在PyYAML中,Node作为YAML信息模型的实体,有三种类型:
- 标量
ScalarNode(tag, value, style, start_mark, end_mark)
- 序列
SequenceNode(tag, value, flow_style, start_mark, end_mark)
- 映射
MappingNode(tag, value, flow_style, start_mark, end_mark)
node由Composer产生,通过Serializer可将其序列化为YAML流。
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
content = """
title: 这是一个标题
categories:
- 分类1
tags:
- 标签1
- 标签2
"""
node = yaml.compose(content)
print(node)
print('')
stream = yaml.serialize(node)
print(stream)
|
输出:
1
2
3
4
5
6
7
8
|
MappingNode(tag='tag:yaml.org,2002:map', value=[(ScalarNode(tag='tag:yaml.org,2002:str', value='title'), ScalarNode(tag='tag:yaml.org,2002:str', value='这是一个标题')), (ScalarNode(tag='tag:yaml.org,2002:str', value='categories'), SequenceNode(tag='tag:yaml.org,2002:seq', value=[ScalarNode(tag='tag:yaml.org,2002:str', value='分类1')])), (ScalarNode(tag='tag:yaml.org,2002:str', value='tags'), SequenceNode(tag='tag:yaml.org,2002:seq', value=[ScalarNode(tag='tag:yaml.org,2002:str', value='标签1'), ScalarNode(tag='tag:yaml.org,2002:str', value='标签2')]))])
title: "\u8FD9\u662F\u4E00\u4E2A\u6807\u9898"
categories:
- "\u5206\u7C7B1"
tags:
- "\u6807\u7B7E1"
- "\u6807\u7B7E2"
|
关于constructor和representer
constructor之于Loading,representer之于Dumping,二者功能相反。
constructor
用于将一个YAML节点转换为Python对象。
yaml.add_constructor(tag, constructor, Loader=Loader)
为目标tag指定constructor;constructor的参数包括一个Loader实例和一个YAML节点,返回值是一个Python对象。
Loader提供了获取YAML节点值的方法(该值用于构造Python对象):
-
Loader.construct_scalar(node)
验证目标YAML节点是标量节点并返回其值
-
Loader.construct_sequence(node)
验证目标YAML节点是序列节点并返回其值
-
Loader.construct_mapping(node)
验证目标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
|
class Post(object):
def __init__(self, title, categories, tags):
self.title = title
self.categories = categories
self.tags = tags
def post_constructor(loader, node):
mapping_value = loader.construct_mapping(node)
return Post(mapping_value['title'], mapping_value['categories'], mapping_value['tags'])
yaml.add_constructor(u'!Post', post_constructor)
res = yaml.load("""
!Post
title: 这是一个标题
categories:
- 分类1
tags:
- 标签1
- 标签2
""")
print(type(res))
print(res.title)
print(res.categories)
print(res.tags)
|
输出:
1
2
3
4
|
<class '__main__.Post'>
这是一个标题
['分类1']
['标签1', '标签2']
|
representer
用于将一个Python对象转换为YAML节点。
yaml.add_representer(data_type, representer, Dumper=Dumper)
为指定类型的对象指定representer;representer的参数包含一个Dumper实例和一个Python对象,返回值是一个YAML节点。
Dumper提供了构造YAML节点的方法:
-
Dumper.represent_scalar(tag, value, style=None)
返回具有指定tag和value的标量节点
-
Dumper.represent_sequence(tag, sequence, flow_style=None)
返回具有指定tag和value的序列节点
-
Dumper.represent_mapping(tag, mapping, flow_style=None)
返回具有指定tag和value的映射节点
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Post(object):
def __init__(self, title, categories, tags):
self.title = title
self.categories = categories
self.tags = tags
def post_representer(dumper, post):
attrs = []
attrs.append(('title', post.title))
attrs.append(('categories', post.categories))
attrs.append(('tags', post.tags))
return dumper.represent_mapping(u'!Post', attrs)
post = Post('这是一个标题', ['分类1'], ['标签1', '标签2'])
yaml.add_representer(Post, post_representer)
res = yaml.dump(post, allow_unicode=True)
print(res)
|
输出:
1
2
3
4
5
6
7
|
!Post
title: 这是一个标题
categories:
- 分类1
tags:
- 标签1
- 标签2
|
可以看到输出内容带有类型tag,如果希望不附带tag,需使用YAML标准类型,在本例中dumper.represent_mapping(u'tag:yaml.org,2002:map', attrs)
。
YAML标准类型tag可以参考 https://yaml.org/type/index.html 。
关于yaml.dump()参数
1
2
3
4
5
6
7
8
9
10
11
12
13
|
dump(data, stream=None, Dumper=Dumper,
default_style=None,
default_flow_style=None,
encoding='utf-8', # encoding=None (Python 3)
explicit_start=None,
explicit_end=None,
version=None,
tags=None,
canonical=None,
indent=None,
width=None,
allow_unicode=None,
line_break=None)
|
已知参数用法:
-
allow_unicode=True
正常显示Unicode字符,比如中文
-
default_flow_style=True
紧凑输出为一行
-
canonical=True
以Canonical Form格式输出
关于Tag
YAML使用tag标识数据类型,全局tag采用tag:
起始的URL格式,本地tag采用!
起始的格式,格式说明参考下面官方文档:
1
2
3
4
5
6
7
|
Tag property: # Usually unspecified.
none : Unspecified tag (automatically resolved by application).
'!' : Non-specific tag (by default, "!!map"/"!!seq"/"!!str").
'!foo' : Primary (by convention, means a local "!foo" tag).
'!!foo' : Secondary (by convention, means "tag:yaml.org,2002:foo").
'!h!foo': Requires "%TAG !h! <prefix>" (and then means "<prefix>foo").
'!<foo>': Verbatim tag (always means "foo")
|
其中,!!
是tag:yaml.org,2002:
的缩写,dump内容所包含的tag采用缩写格式。
参考文档