支持继承的 YAML 或 JSON 库



我们正在构建一个服务。它必须从文件中读取配置。我们目前正在使用 YAML 和 Jackson 来反序列化 YAML。我们遇到的情况是,我们的 YAML 文件需要继承/扩展另一个 YAML 文件。例如,像这样:

extends: base.yaml
appName: my-awesome-app
...

因此,部分配置存储在base.yaml中。是否有任何库支持此功能?如果它允许从多个文件继承,则奖励积分。 我们可以更改为使用 JSON 而不是 YAML。

JSON 和 YAML 都无法包含文件。无论您做什么,都将是一个预处理步骤,您将把base.yaml和实际文件放在一起。

一个粗略的方法是:

#include base.yaml
appName: my-awesome-app

让这成为您的文件。加载后,首先读取第一行,如果它以#include开头,则将其替换为包含文件的内容。您需要以递归方式执行此操作。这基本上是 C 预处理器对 C 文件所做的,并包含。

缺点是:

  • 即使两个文件都是有效的 YAML,结果也可能不是。
  • 如果任一文件包含指令结束或文档结束标记(---...),则最终将在一个文件中得到两个单独的文档。
  • 不能替换文件内base.yaml的任何值。

因此,另一种方法是在 YAML 结构上实际操作。为此,您需要 YAML 解析器(在您的例子中为 SnakeYAML)的 API 并使用它解析您的文件。您应该使用撰写 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背后的空间。我没有提供合并包含的文件的代码,因为我不知道您要如何处理重复的映射键。不过,实施起来应该不难。请注意错误,我还没有测试过这段代码。

生成的字符串可以是杰克逊的输入。

可能出于同样的愿望,我创建了这个工具:jq-front。

您可以通过遵循语法并与yq命令结合使用来做到这一点。

extends: [ base.yaml ]
appName: my-awesome-app
...
$ yq -j . your.yaml | jq-front | yq -y .

请注意,您需要将要扩展的文件名放在数组中,因为该工具支持多重继承。

您可能不喜欢的点是

  • 它有点慢。(但是对于配置信息,它可能没问题,因为您可以将其转换为扩展文件一次,之后您将永远不会为您的系统提供原始文件)
  • 数组中的对象无法按预期运行,因为该工具依赖于jq运算符*

最新更新