我需要在python中检查(验证)YAML文件中的数据是否按某些字段的字母顺序排列(参见下面的示例)。 假设我有一些包含YAML格式数据的文件:
-
project: presentations/demo1
description: Some description for demo1 project
owner: John Doe
-
project: templates/template_demo
description: Some template_demo
owner: Sarah Connor
因此,我必须确保此文件中的数据按“项目”名称排序。 实际上,我有一些解决方案基于获取所有项目名称(来自相应的dicts列表),对它们进行排序,然后与原始YAML文件进行比较。但也许有更好的解决方案。
答案 0 :(得分:1)
如果你稍微简化这个问题,它就会变成
检查列表是否按排序顺序
你可以参考很好的方法here
l = [ 4, 2, 3, 7, 8 ]
# this does not have to be sorted, you just have to check that the
# current entry is less than the next one
all(l[i] <= l[i+1] for i in xrange(len(l)-1))
在你的情况下,它变成
data = parse_yaml_file() # parse your yaml data
is_sorted = all(data[i]['project'] <= data[i+1]['project'] for i in xrange(len(data)-1))
答案 1 :(得分:1)
您应该IMO不要假设您的程序名称与您拥有的程序名称一样简单。如果项目名称变长,则转储YAML的程序可能会将project
的标量字符串值包装在多行上。如果名称包含特殊字符(对于YAML),则转储名称的程序将使用标量字符串周围的单引号或双引号。此外,-
可能位于您拥有密钥project
的行上,而密钥project
的值不必位于同一行:
- project:
presentations/demo1
description: Some description for demo1 project
YAML解析器会自动正确地重建这样的标量,除了YAML解析器之外,使用其他任何东西都很难正确。
幸运的是,使用YAML解析器很容易在Python中检查你想要的内容:
import ruamel.yaml
with open('input.yaml') as fp:
data = ruamel.yaml.safe_load(fp)
for idx, d in enumerate(data[:-1]):
assert d['project'] < data[idx+1]['project']
如果您可以使用相同名称的项目,则应使用<=
而不是<
。您必须使用pip install ruamel.yaml
在virtualenv中安装ruamel.yaml(您肯定使用一个用于开发)。
如果你不想只是想检查YAML,而是生成一个正确订购的YAML,你应该使用:
import ruamel.yaml
with open('input.yaml') as fp:
data = ruamel.yaml.round_trip_load(fp)
ordered = True
for idx, d in enumerate(data[:-1]):
if d['project'] > data[idx+1]['project']:
ordered = False
if not ordered:
project_data_map = {}
for d in data:
project_data_map.setdefault(d['project'], []).append(d)
out_data = []
for project_name in sorted(project_data_map):
out_data.extend(project_data_map[project_name])
with open('output.yaml', 'w') as fp:
ruamel.yaml.round_trip_dump(out_data, fp)
这将保留各个映射/ dicts中键的顺序,保留任何注释。
setdefault().append()
处理输入中可能双重/重复的任何项目名称作为单独的条目。因此,即使某些项目的项目名称可能相同,输出中的项目数也会与输入相同。