我有两个YAML文件,“A”和“B”,我希望将A的内容插入到B中,要么拼接到现有的数据结构中,就像数组一样,要么作为元素的子元素,就像某个散列键的值一样。
这可能吗?怎么做?如果不是,是否有指向规范引用的指针?
我有两个YAML文件,“A”和“B”,我希望将A的内容插入到B中,要么拼接到现有的数据结构中,就像数组一样,要么作为元素的子元素,就像某个散列键的值一样。
这可能吗?怎么做?如果不是,是否有指向规范引用的指针?
当前回答
使用Yglu,你可以像这样导入其他文件:
A.yaml
foo: !? $import('B.yaml')
B.yaml
bar: Hello
$ yglu A.yaml
foo:
bar: Hello
因为$import是一个函数,你也可以传递一个表达式作为参数:
dep: !- b
foo: !? $import($_.dep.toUpper() + '.yaml')
这将得到与上面相同的输出。
声明:我是Yglu的作者。
其他回答
对于Python用户,可以尝试pyyaml-include。
安装
pip install pyyaml-include
使用
import yaml
from yamlinclude import YamlIncludeConstructor
YamlIncludeConstructor.add_to_loader_class(loader_class=yaml.FullLoader, base_dir='/your/conf/dir')
with open('0.yaml') as f:
data = yaml.load(f, Loader=yaml.FullLoader)
print(data)
假设我们有这样的YAML文件:
├── 0.yaml
└── include.d
├── 1.yaml
└── 2.yaml
1.Yaml的内容:
name: "1"
2.Yaml的内容:
name: "2"
按名称包含文件
顶层: 如果0。yaml是:
!include include.d/1.yaml
我们会得到:
{"name": "1"}
在映射: 如果0。yaml是:
file1: !include include.d/1.yaml
file2: !include include.d/2.yaml
我们会得到:
file1:
name: "1"
file2:
name: "2"
在序列: 如果0。yaml是:
files:
- !include include.d/1.yaml
- !include include.d/2.yaml
我们会得到:
files:
- name: "1"
- name: "2"
ℹ注意: 文件名可以是绝对的(如/usr/conf/1.5/ make .yml)或相对的(如../../cfg/img.yml)。
通过通配符包含文件
文件名可以包含shell样式的通配符。从通配符找到的文件中加载的数据将按顺序设置。
如果0。yaml是:
files: !include include.d/*.yaml
我们会得到:
files:
- name: "1"
- name: "2"
ℹ注意: 对于Python>=3.5,如果递归参数!include YAML标记为真,模式" ** "将匹配任何文件和零个或多个目录和子目录。 在大型目录树中使用“**”模式可能会因为递归搜索而消耗过多的时间。
为了启用递归参数,我们应该在映射或序列模式下编写!include标记:
序列模式参数:
!include [tests/data/include.d/**/*.yaml, true]
映射模式参数说明
!include {pathname: tests/data/include.d/**/*.yaml, recursive: true}
据我所知,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请求的响应中得到一个包含,它意味着什么?
使用Yglu,你可以像这样导入其他文件:
A.yaml
foo: !? $import('B.yaml')
B.yaml
bar: Hello
$ yglu A.yaml
foo:
bar: Hello
因为$import是一个函数,你也可以传递一个表达式作为参数:
dep: !- b
foo: !? $import($_.dep.toUpper() + '.yaml')
这将得到与上面相同的输出。
声明:我是Yglu的作者。
标准YAML 1.2本身不包括这个特性。尽管如此,许多实现提供了一些扩展来实现这一点。
我给出了一种使用Java和snakeyaml:1.24(用于解析/发出YAML文件的Java库)来实现它的方法,它允许创建一个自定义YAML标记来实现以下目标(你会看到我用它来加载在几个YAML文件中定义的测试套件,并且我让它作为一个目标测试:节点的包含列表工作):
# ... yaml prev stuff
tests: !include
- '1.hello-test-suite.yaml'
- '3.foo-test-suite.yaml'
- '2.bar-test-suite.yaml'
# ... more yaml document
下面是允许处理!include标记的单类Java。文件从classpath (Maven资源目录)加载:
/**
* Custom YAML loader. It adds support to the custom !include tag which allows splitting a YAML file across several
* files for a better organization of YAML tests.
*/
@Slf4j // <-- This is a Lombok annotation to auto-generate logger
public class MyYamlLoader {
private static final Constructor CUSTOM_CONSTRUCTOR = new MyYamlConstructor();
private MyYamlLoader() {
}
/**
* Parse the only YAML document in a stream and produce the Java Map. It provides support for the custom !include
* YAML tag to split YAML contents across several files.
*/
public static Map<String, Object> load(InputStream inputStream) {
return new Yaml(CUSTOM_CONSTRUCTOR)
.load(inputStream);
}
/**
* Custom SnakeYAML constructor that registers custom tags.
*/
private static class MyYamlConstructor extends Constructor {
private static final String TAG_INCLUDE = "!include";
MyYamlConstructor() {
// Register custom tags
yamlConstructors.put(new Tag(TAG_INCLUDE), new IncludeConstruct());
}
/**
* The actual include tag construct.
*/
private static class IncludeConstruct implements Construct {
@Override
public Object construct(Node node) {
List<Node> inclusions = castToSequenceNode(node);
return parseInclusions(inclusions);
}
@Override
public void construct2ndStep(Node node, Object object) {
// do nothing
}
private List<Node> castToSequenceNode(Node node) {
try {
return ((SequenceNode) node).getValue();
} catch (ClassCastException e) {
throw new IllegalArgumentException(String.format("The !import value must be a sequence node, but " +
"'%s' found.", node));
}
}
private Object parseInclusions(List<Node> inclusions) {
List<InputStream> inputStreams = inputStreams(inclusions);
try (final SequenceInputStream sequencedInputStream =
new SequenceInputStream(Collections.enumeration(inputStreams))) {
return new Yaml(CUSTOM_CONSTRUCTOR)
.load(sequencedInputStream);
} catch (IOException e) {
log.error("Error closing the stream.", e);
return null;
}
}
private List<InputStream> inputStreams(List<Node> scalarNodes) {
return scalarNodes.stream()
.map(this::inputStream)
.collect(toList());
}
private InputStream inputStream(Node scalarNode) {
String filePath = castToScalarNode(scalarNode).getValue();
final InputStream is = getClass().getClassLoader().getResourceAsStream(filePath);
Assert.notNull(is, String.format("Resource file %s not found.", filePath));
return is;
}
private ScalarNode castToScalarNode(Node scalarNode) {
try {
return ((ScalarNode) scalarNode);
} catch (ClassCastException e) {
throw new IllegalArgumentException(String.format("The value must be a scalar node, but '%s' found" +
".", scalarNode));
}
}
}
}
}
可能在问问题时不支持,但你可以将其他YAML文件导入其中:
imports: [/your_location_to_yaml_file/Util.area.yaml]
虽然我没有任何在线参考资料,但这对我来说很有用。