【问题标题】:How do I load multiple yaml files using Snake YAML Java?如何使用 Snake YAML Java 加载多个 yaml 文件?
【发布时间】:2019-05-16 07:54:25
【问题描述】:

我在一个目录中有几个 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 的内容显式连接成一个字符串,然后加载合并的字符串。我想知道是否可以避免这种情况,只需使用 load() API 依次加载 2 个 yaml 文件。

【问题讨论】:

  • 如果 yaml 文件用 tla 文件分隔符分隔,这是否也适用? (---) 现在我最终打开了多个输入流并将它们与 SequenceInputStream 合并,并且 SnakeYaml 1.23 给出了正确的解析输出。
  • 非常感谢!我没有在示例 sn-p 中包含文件标记,我想我应该包含。如果我加载多个 Yaml 文件的单个流,我如何最终得到多个数据结构?我使用单个序列输入流作为 loadAll API 的参数,它会返回一个 String 到 Object 的 Map 作为响应。至少这是我在测试中看到的。也许那是蛇 yaml 特有的东西?
  • 知道了。谢谢安东!我想如果你把这个讨论总结为一个答案,我们可以结束这个问题。

标签: java yaml snakeyaml


【解决方案1】:

我用它来覆盖和合并两个 yaml 配置,可能会对某人有所帮助:

 public static void update(Map<String,Object> existingMap,Map<String,Object> newMap){
    newMap.forEach((key, value) -> {
        if(value instanceof LinkedHashMap){
            LinkedHashMap<String,Object> newMapValue = (LinkedHashMap<String,Object>)value;
            LinkedHashMap<String,Object> existingMapValue = (LinkedHashMap<String,Object>)existingMap.getOrDefault(key,new LinkedHashMap<String,Object>());
            update(existingMapValue,newMapValue);
        }
        else{
            existingMap.put(key,value);
        }
    });
}

/**
 * Reads application.yaml file and loads it to config.
 */
public static void init() throws Exception {
    Yaml yaml = new Yaml();

    //loading config file 1
    InputStream inputStream = ConnectionUtil.class
                .getClassLoader()
                .getResourceAsStream("application.yaml");
    config = yaml.load(inputStream);

    //loading config file 2
    String configFile = System.getProperty("config");
    if(configFile!=null){
        File file = new File(configFile);
        if(file.exists()){
            InputStream inputStream2 = new FileInputStream(file);
            Map<String,Object> config2 = yaml.load(inputStream2);
            update(config,config2);
        }
        else
        {
            throw new Exception("invalid config file path"); 
        
        }
    }

    System.out.println(yaml.dump(config));

}

【讨论】:

    【解决方案2】:

    这里是一个如何使用小递归函数(用 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]
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      有关详细信息,请参阅 Anthon 的回答。作为对想要工作 sn-p 的人们的仅供参考,这就是我所做的。

      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 推荐的加载 API,它工作正常。请记下文档结束标记。

      【讨论】:

        【解决方案4】:

        我不知道 SnakeYAML 的详细信息,但你不能只连接两个文件 a.yamlb.yaml,即使它们都在根级别有映射。 这样做你会在你的映射中得到一个重复的键,并且根据 YAML 1.2(和 1.0)规范,你不允许有重复的键,并且 1.1 规范指出你应该在重复键和第一个值上收到警告(你表明你想要第二个)。

        所以你必须在 Java 中解决这个问题,你可以通过从它们各自的文件中加载文档并将从 a.yaml 加载的数据结构更新为来自 b.yaml 的数据结构。

        您还可以将文件连接成一个包含多个文档的文件,但为此,这些文档必须由指令结束指示符 (---) 或文档结束指示符 (...) 分隔.您通常需要使用特殊的“load-all”函数来加载这样的多文档文件,从而生成从映射加载的数据结构列表(或迭代器),然后您可以合并。

        如果您以编程方式创建多文档文件,请确保检查文件是否以换行符结尾,否则附加 --- 并且下一个文件不会提供您期望的多文档流。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-03-07
          • 1970-01-01
          • 2014-05-31
          • 2016-10-24
          • 2014-01-20
          • 2020-12-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多