如何使用Snake YAML Java加载多个Yaml文件?

时间:2018-12-15 06:01:28

标签: yaml snakeyaml

我的目录中有一些Yaml文件。如何将它们全部加载到同一个YAML对象(地图)中?

# a.yaml
a: ValueA
c: ValueC

# b.yaml
a: ValueAA
b: ValueB

我要a.yaml,然后是b.yaml。结果将是:

{ a: ValueAA, b: ValueB, c: ValueC }

我可以这样做的一种方法是将a.yaml和b.yaml的内容显式连接到单个String中,然后加载合并的String。我想知道是否可以避免这种情况,只需使用load()API依次加载2个yaml文件即可。

3 个答案:

答案 0 :(得分:1)

我不知道SnakeYAML的详细信息,但是即使两个文件a.yamlb.yaml在根级别都有映射,您也不能将它们串联在一起。 这样一来,您将在映射中获得重复键,并且根据YAML 1.2(和1.0)规范,您将不具有重复键,而1.1规范指出您应在重复键和第一个值上得到警告(您表示您想拥有第二个)。

因此,您必须使用Java来解决此问题,可以通过从相应文件中加载文档并用a.yaml中的文件更新从b.yaml中加载的数据结构来实现。

您还可以将文件串联到包含多个文档的文件中,但是为此,必须使用指令末尾指示符(---)或文档末尾指示符({{ 1}})。通常,您需要使用特殊的“全部加载”功能来加载这样的多文档文件,从而生成从映射加载的数据结构列表(或迭代器),然后可以合并。

如果您以编程方式制作多文档文件,请确保检查文件是否以换行符结尾,否则请附加...并且下一个文件将无法提供您期望的多文档流。 / p>

答案 1 :(得分:1)

有关详细信息,请参阅Anthon的答案。作为仅供参考的FYI,我就是这样做的。

final Yaml yaml = new Yaml(configConstructor, representer);

try (
    final InputStream defaultYamlStream = new FileInputStream(settingsPath + "/cbench-default.yaml");
    final InputStream customerYamlStream = new FileInputStream(settingsPath + "/" + identifier + ".yaml");
    final InputStream fullYamlStream = new SequenceInputStream(defaultYamlStream, customerYamlStream);
) {
    //try
    parsedConfig = (BenchmarkConfig) yaml.load(fullYamlStream);

} catch (IOException ioe) {
    // ERROR
    System.out.println("Exception parsing the YAML configuration.");
    throw new RuntimeException("Exception parsing the YAML configuration.", ioe);
}

我正在创建级联文件流(在我的情况下为序列流),并按照Anthon的建议使用load API,它工作正常。记下文档结束标记。

答案 2 :(得分:0)

下面是一个使用小型递归函数(用Groovy编写)的示例:

@Grapes(
    @Grab(group='org.yaml', module='snakeyaml', version='1.25')
)

import org.yaml.snakeyaml.Yaml

import static groovy.json.JsonOutput.prettyPrint
import static groovy.json.JsonOutput.toJson

def extension = new Yaml().load(("extension.yml" as File).text)
def original = new Yaml().load(("original.yml" as File).text)

println prettyPrint(toJson(original))
println "#############################"

iterateAndOverrite(extension, original)
extension = original

println prettyPrint(toJson(original))

private void iterateAndOverrite(extension, original){
    extension.each {
        if(it.value instanceof Map && original[it.key] != null){
            iterateAndOverrite(extension[it.key], original[it.key])
        } else {
             original[it.key] = extension[it.key]
        }
    }
}