我正在寻找一个工具或流程,可以轻松获取包含锚点,别名和合并键的YAML文件,并展开别名并合并为一个平面YAML文件。仍有许多常用的YAML解析不完全支持合并。
我希望能够利用合并来保持干燥,但有些情况下需要将其构建成更详细的“平坦”。 YAML文件,以便它可以被依赖于不完整的YAML解析器的其他工具使用。
示例来源YAML:
default: &DEFAULT
URL: website.com
mode: production
site_name: Website
some_setting: h2i8yiuhef
some_other_setting: 3600
development:
<<: *DEFAULT
URL: website.local
mode: dev
test:
<<: *DEFAULT
URL: test.website.qa
mode: test
所需的输出YAML:
default:
URL: website.com
mode: production
site_name: Website
some_setting: h2i8yiuhef
some_other_setting: 3600
development:
URL: website.local
mode: dev
site_name: Website
some_setting: h2i8yiuhef
some_other_setting: 3600
test:
URL: test.website.qa
mode: test
site_name: Website
some_setting: h2i8yiuhef
some_other_setting: 3600
答案 0 :(得分:5)
如果您的系统上安装了python,则可以pip install ruamel.yaml.cmd
¹然后执行:
yaml merge-expand input.yaml output.yaml
(将output.yaml
替换为-
以写入stdout)。这实现了合并扩展,保留了关键顺序和注释。
以上实际上是使用ruamel.yaml
¹的几行代码
所以如果你有Python(2.7或3.4+)并使用pip install ruamel.yaml
安装它并将以下内容保存为expand.py
:
import sys
from ruamel.yaml import YAML
yaml = YAML(typ='safe')
yaml.default_flow_style=False
with open(sys.argv[1]) as fp:
data = yaml.load(fp)
with open(sys.argv[2], 'w') as fp:
yaml.dump(data, fp)
你已经可以做了:
python expand.py input.yaml output.yaml
这将使你在语义上等同于你所请求的YAML(在output.yaml
映射的键被排序,在这个程序输出中它们不是)。
以上假设您的YAML中没有任何标签,也不关心保留任何评论。通过使用标准YAML()
实例的修补版本,可以保留大部分内容和密钥排序。修补是必要的,因为标准YAML()
实例也保留了往返的合并,这正是您不想要的:
import sys
from ruamel.yaml import YAML, SafeConstructor
yaml = YAML()
yaml.Constructor.flatten_mapping = SafeConstructor.flatten_mapping
yaml.default_flow_style=False
yaml.allow_duplicate_keys = True
# comment out next line if you want "normal" anchors/aliases in your output
yaml.representer.ignore_aliases = lambda x: True
with open(sys.argv[1]) as fp:
data = yaml.load(fp)
with open(sys.argv[2], 'w') as fp:
yaml.dump(data, fp)
使用此输入:
default: &DEFAULT
URL: website.com
mode: production
site_name: Website
some_setting: h2i8yiuhef
some_other_setting: 3600 # an hour?
development:
<<: *DEFAULT
URL: website.local # local web
mode: dev
test:
<<: *DEFAULT
URL: test.website.qa
mode: test
将提供此输出(请注意,合并的键的注释会重复):
default:
URL: website.com
mode: production
site_name: Website
some_setting: h2i8yiuhef
some_other_setting: 3600 # an hour?
development:
URL: website.local # local web
mode: dev
site_name: Website
some_setting: h2i8yiuhef
some_other_setting: 3600 # an hour?
test:
URL: test.website.qa
mode: test
site_name: Website
some_setting: h2i8yiuhef
some_other_setting: 3600 # an hour?
以上是本答案开头提到的yaml merge-expand
命令。
¹免责声明:我是该套餐的作者。
答案 1 :(得分:2)
ruamel
库。pprint.pformat
并简单地进行加载/转储往返转换。ruamel
库很棒,如果你有权在pyyaml之外安装另一个python库,并且你想要高度控制&#34;往返&#34; YAML转换(例如保存YAML注释)。截至撰写本文时PyYAML
相对于ruamel
库存在限制,涉及YAML v1.1和YAML v1.2的处理
另见
##
import pprint
import yaml
##
myrawyaml = '''
default: &DEFAULT
URL: website.com
mode: production
site_name: Website
some_setting: h2i8yiuhef
some_other_setting: 3600
development:
<<: *DEFAULT
URL: website.local
mode: dev
test:
<<: *DEFAULT
URL: test.website.qa
mode: test
'''
##
pynative = yaml.safe_load(myrawyaml)
vout = pprint.pformat(pynative)
print(vout) ##=> this is non-DRY and just happens to be well-formed YAML syntax
print(yaml.safe_load(vout)) ##=> this proves we have well-formed YAML if it loads without exception
答案 2 :(得分:0)
如果由于某种原因有一个用例,需要将扩展的YAML作为YAML写回到文件中,则可以:
使用@Anthon的答案。如上所述,但是,如果您无法安装软件包,则此方法可能不可行。
使用@dreftymac的答案。看来,这个答案对某些人有用,但对我却不起作用。根据我的理解,pprint.pformat
将参数作为其Python表示形式的字符串返回,并且yaml.safe_load
期望Python表示形式本身。当然,您可以eval
pprint.pformat
返回的字符串,但是即使在受信任的输入上使用eval
也会感到讨厌。 (同样,答案有几个不赞成,所以也许我在这里遗漏了一些东西。)
或者,您可以执行我的操作:
import json
import yaml
def expand_yml(yml):
return yaml.dump(json.loads(json.dumps(yml)))
expand_yml(my_yml_with_aliases)
由于JSON(除了某些例外,例如别名)可以被视为YAML的严格子集,因此这种方法通常应该有效。但是,如果性能是一个问题,或者您要处理的是毛发较大的YAML,则此方法可能不适合您。