我们正在建立一项服务。它必须从文件中读取配置。我们目前正在使用YAML和Jackson对YAML进行反序列化。我们的YAML文件需要继承/扩展另一个YAML文件。例如:
extends: base.yaml
appName: my-awesome-app
...
因此部分配置存储在base.yaml
中。有没有图书馆支持这个?如果允许从多个文件继承,则奖励积分。我们可以改为使用JSON而不是YAML。
答案 0 :(得分:1)
JSON和YAML都无法包含文件。无论你做什么都将是一个预处理步骤,你将把base.yaml
和你的实际文件放在一起。
这样做的粗略方法是:
#include base.yaml
appName: my-awesome-app
让这成为你的档案。加载后,您首先阅读第一行,如果它以#include
开头,则将其替换为所包含文件的内容。你需要递归地做这件事。这基本上是C预处理器对C文件的处理和包含。
缺点是:
---
或...
),您将在一个文件中最终得到两个单独的文档。base.yaml
的任何值。所以另一种方法是实际操作YAML结构。为此,您需要YAML解析器的API(在您的情况下为SnakeYAML)并使用它解析您的文件。您应该使用compose API:
private Node preprocess(final Reader myInput) {
final Yaml yaml = new Yaml();
final Node node = yaml.compose(myInput);
processIncludes(node);
return node;
}
private void processIncludes(final Node node) {
if (node instanceof MappingNode) {
final List<NodeTuple> values = ((MappingNode) node).getValue();
for (final NodeTuple tuple: values) {
if ("!include".equals(tuple.getKeyNode().getTag().getValue())) {
final String includedFilePath =
((ScalarNode) tuple.getValueNode()).getValue();
final Node content = preprocess(new FileReader(includedFilePath));
// now merge the content in your preferred way into the values list.
// that will change the content of the node.
}
}
}
}
public String executePreprocessor(final Reader source) {
final Node node = preprocess(source);
final StringWriter writer = new StringWriter();
final DumperOptions dOptions = new DumperOptions()
Serializer ser = new Serializer(new Emitter(writer, dOptions),
new Resolver(), dOptions, null);
ser.open();
ser.serialize(node);
ser.close();
return writer.toString();
}
此代码将解析包含如下:
!include : base.yaml
appName: my-awesome-app
我使用了私有标记!include
,因此不存在与任何普通映射关键字的名称冲突。注意!include
背后的空间。我没有给代码合并包含的文件,因为我不知道你想如何处理重复的映射键。但实施起来应该不难。注意错误,我还没有测试过这段代码。
结果字符串可以作为杰克逊的输入。
答案 1 :(得分:0)
可能出于相同的愿望,我创建了此工具:jq-front。
您可以按照以下语法并与yq
命令结合使用。
extends: [ base.yaml ]
appName: my-awesome-app
...
$ yq -j . your.yaml | jq-front | yq -y .
请注意,由于该工具支持多重继承,因此您需要将文件名放在数组中进行扩展。
您可能不喜欢的要点
*
的{{1}}运算符,因此数组内的对象无法按预期方式运行。