支持继承的YAML或JSON库 [英] YAML or JSON library that supports inheritance

查看:94
本文介绍了支持继承的YAML或JSON库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We are building a service. It has to read config from a file. We are currently using YAML and Jackson for deserializing the YAML. We have a situation where our YAML file needs to inherit/extend another YAML file(s). E.g., something like:

extends: base.yaml

appName: my-awesome-app

...

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

thus part of the config is stored in base.yaml. Is there any library that has support for this? Bonus points if it allows to inherit from more than one file. We could change to using JSON instead of YAML.

推荐答案

JSON和YAML都不能包含文件.无论您做什么,都将成为预处理步骤,将 base.yaml 和您的实际文件放在一起.

Neither JSON nor YAML have the ability to include files. Whatever you do will be a pre-processing step where you will be putting the base.yaml and your actual file together.

一种粗略的方法是:

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

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

Let this be your file. Upon loading, you first read the first line, and if it starts with #include, you replace it with the content of the included file. You need to do this recursively. This is basically what the C preprocessor does with C files and includes.

缺点是:

  • 即使两个文件都是有效的YAML,结果也可能不是.
  • 如果两个文件都包含指令结束标记或文档结束标记( --- ... ),您将在一个文件中得到两个单独的文档.
  • 您无法替换文件中 base.yaml 中的任何值.
  • even if both files are valid YAML, the result may not.
  • if either files includes a directive end or document end marker (--- or ...), you will end up with two separate documents in one file.
  • you cannot replace any values from base.yaml inside your file.

因此,一种替代方法是实际在YAML结构上进行操作.为此,您需要YAML解析器的API(在您的情况下为SnakeYAML)并以此解析文件.您应该使用compose API:

So an alternative would be to actually operate on the YAML structure. For this, you need the API of the YAML parser (SnakeYAML in your case) and parse your file with that. You should use the 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();
}

此代码将解析包括以下内容:

This code would parse includes like this:

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

我使用了专用标签!include ,以便不会与任何常规映射键发生名称冲突.注意!include 后面的空间.我没有给出合并文件的代码,因为我不知道您要如何处理重复的映射键.不过,它应该不难实现.请注意错误,我尚未测试此代码.

I used the private tag !include so that there will not be name clashes with any normal mapping key. Mind the space behind !include. I didn't give code to merge the included file because I did not know how you want to handle duplicate mapping keys. It should not be hard to implement though. Be aware of bugs, I have not tested this code.

生成的String可以作为Jackson的输入.

The resulting String can be the input to Jackson.

这篇关于支持继承的YAML或JSON库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆