我有两个YAML文件,“A”和“B”,我希望将A的内容插入到B中,要么拼接到现有的数据结构中,就像数组一样,要么作为元素的子元素,就像某个散列键的值一样。
这可能吗?怎么做?如果不是,是否有指向规范引用的指针?
我有两个YAML文件,“A”和“B”,我希望将A的内容插入到B中,要么拼接到现有的数据结构中,就像数组一样,要么作为元素的子元素,就像某个散列键的值一样。
这可能吗?怎么做?如果不是,是否有指向规范引用的指针?
当前回答
据我所知,YAML中不直接支持include,你必须自己提供一种机制,然而,这通常很容易做到。
我在我的python应用程序中使用YAML作为配置语言,在这种情况下经常定义这样的约定:
>>> main.yml <<<
includes: [ wibble.yml, wobble.yml]
然后在我的(python)代码中:
import yaml
cfg = yaml.load(open("main.yml"))
for inc in cfg.get("includes", []):
cfg.update(yaml.load(open(inc)))
唯一的缺点是include中的变量将总是覆盖main中的变量,并且没有办法通过改变“includes:”语句在main中出现的位置来改变优先级。yml文件。
稍微不同的一点是,YAML不支持include,因为它并不是像基于文件的标记那样专门设计的。如果你在AJAX请求的响应中得到一个包含,它意味着什么?
其他回答
据我所知,YAML中不直接支持include,你必须自己提供一种机制,然而,这通常很容易做到。
我在我的python应用程序中使用YAML作为配置语言,在这种情况下经常定义这样的约定:
>>> main.yml <<<
includes: [ wibble.yml, wobble.yml]
然后在我的(python)代码中:
import yaml
cfg = yaml.load(open("main.yml"))
for inc in cfg.get("includes", []):
cfg.update(yaml.load(open(inc)))
唯一的缺点是include中的变量将总是覆盖main中的变量,并且没有办法通过改变“includes:”语句在main中出现的位置来改变优先级。yml文件。
稍微不同的一点是,YAML不支持include,因为它并不是像基于文件的标记那样专门设计的。如果你在AJAX请求的响应中得到一个包含,它意味着什么?
也许这可以激励你,试着与jbb惯例保持一致:
https://docs.openstack.org/infra/jenkins-job-builder/definition.html#inclusion-tags
-工作: 名称:test-job-include-raw-1 建造者: -壳: !包括生:include-raw001-hello-world.sh
您的问题没有要求使用Python解决方案,但这里有一个使用PyYAML的解决方案。
PyYAML允许您将自定义构造函数(例如!include)附加到YAML加载器。我已经包含了一个可以设置的根目录,以便这个解决方案支持相对和绝对文件引用。
基于类的解决方案
这是一个基于类的解决方案,避免了我原始响应的全局根变量。
请参阅以下要点,了解一个类似的、更健壮的Python 3解决方案,该解决方案使用元类注册自定义构造函数。
import yaml
import os
class Loader(yaml.SafeLoader):
def __init__(self, stream):
self._root = os.path.split(stream.name)[0]
super(Loader, self).__init__(stream)
def include(self, node):
filename = os.path.join(self._root, self.construct_scalar(node))
with open(filename, 'r') as f:
return yaml.load(f, Loader)
Loader.add_constructor('!include', Loader.include)
一个例子:
foo.yaml
a: 1
b:
- 1.43
- 543.55
c: !include bar.yaml
bar.yaml
- 3.6
- [1, 2, 3]
现在可以使用以下方法加载文件:
>>> with open('foo.yaml', 'r') as f:
>>> data = yaml.load(f, Loader)
>>> data
{'a': 1, 'b': [1.43, 543.55], 'c': [3.6, [1, 2, 3]]}
根据之前的帖子:
class SimYamlLoader(yaml.SafeLoader):
'''
Simple custom yaml loader that supports include, e.g:
main.yaml:
- !include file1.yaml
- !include dir/file2.yaml
'''
def __init__(self, stream):
self.root = os.path.split(stream.name)[0]
super().__init__(stream)
def _include(loader, node):
filename = os.path.join(loader.root, loader.construct_scalar(node))
with open(filename, 'r') as f:
return yaml.load(f, SimYamlLoader)
SimYamlLoader.add_constructor('!include', _include)
# example:
with open('main.yaml', 'r') as f:
lists = yaml.load(f, SimYamlLoader)
# if you want to merge the lists
data = functools.reduce(
lambda x, y: x if y is None else {**x, **dict(y)}, lists, {})
# python 3.10+:lambda x, y: x if y is None else x | dict(y), lists, {})
使用Symfony,它对yaml的处理将间接地允许您嵌套yaml文件。诀窍在于使用参数选项。例如:
common.yml
parameters:
yaml_to_repeat:
option: "value"
foo:
- "bar"
- "baz"
config.yml
imports:
- { resource: common.yml }
whatever:
thing: "%yaml_to_repeat%"
other_thing: "%yaml_to_repeat%"
其结果将与:
whatever:
thing:
option: "value"
foo:
- "bar"
- "baz"
other_thing:
option: "value"
foo:
- "bar"
- "baz"