YAML or JSON library that supports inheritance

点点圈 提交于 2021-01-28 11:04:42

问题


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

...

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.


回答1:


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.

A crude way of doing this would be:

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

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.

Drawbacks are:

  • 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.

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

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.

The resulting String can be the input to Jackson.




回答2:


Probably for the same desire, I have created this tool: jq-front.

You can do it by following syntax and combinating with yq command.

extends: [ base.yaml ]

appName: my-awesome-app

...
$ yq -j . your.yaml | jq-front | yq -y .

Note that you need to place file names to be extended in an array since the tool supports multiple inheritance.

Points potentially you don't like are

  • It's quite a bit slow. (But for configuration information, it might be ok since you can convert it to an expanded file once and you will never not the original one after that for your system)
  • Objects inside an array cannot behave as expected since the tool relies on * operator of jq.


来源:https://stackoverflow.com/questions/42937386/yaml-or-json-library-that-supports-inheritance

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!