如何使用 Snake YAML Java 加载多个 yaml 文件?
How do I load multiple yaml files using Snake YAML Java?
我在一个目录中有几个 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 文件。
我不知道 SnakeYAML 的细节,但你不能只连接两个文件 a.yaml
和 b.yaml
,即使它们在根级别都有映射。
这样做你会在你的映射中得到一个重复的键,并且根据 YAML 1.2(和 1.0)规范你不允许有重复的键,1.1 规范规定你应该在重复键和第一个值上得到警告(你表示你想要第二个)。
所以你必须在 Java 中解决这个问题,你可以通过从它们各自的文件加载文档并将从 a.yaml
加载的数据结构更新为来自 [=11] 的数据结构来解决这个问题=].
您也可以将文件连接成一个包含多个文档的文件,但为此必须用指令结束指示符 (---
) 或文档结束指示符 ( ...
)。您通常需要使用特殊的 "load-all" 函数来加载这样的多文档文件,从而生成从映射中加载的数据结构列表(或迭代器),然后您可以合并。
如果您以编程方式制作多文档文件,请确保检查文件是否以换行符结尾,否则附加 ---
并且下一个文件不会提供您期望的多文档流.
详见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 推荐的负载 API,它工作正常。请记下文档结束标记。
这是一个如何使用小递归函数(写在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]
}
}
}
我用它来覆盖和合并两个 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));
}
我在一个目录中有几个 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 文件。
我不知道 SnakeYAML 的细节,但你不能只连接两个文件 a.yaml
和 b.yaml
,即使它们在根级别都有映射。
这样做你会在你的映射中得到一个重复的键,并且根据 YAML 1.2(和 1.0)规范你不允许有重复的键,1.1 规范规定你应该在重复键和第一个值上得到警告(你表示你想要第二个)。
所以你必须在 Java 中解决这个问题,你可以通过从它们各自的文件加载文档并将从 a.yaml
加载的数据结构更新为来自 [=11] 的数据结构来解决这个问题=].
您也可以将文件连接成一个包含多个文档的文件,但为此必须用指令结束指示符 (---
) 或文档结束指示符 ( ...
)。您通常需要使用特殊的 "load-all" 函数来加载这样的多文档文件,从而生成从映射中加载的数据结构列表(或迭代器),然后您可以合并。
如果您以编程方式制作多文档文件,请确保检查文件是否以换行符结尾,否则附加 ---
并且下一个文件不会提供您期望的多文档流.
详见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 推荐的负载 API,它工作正常。请记下文档结束标记。
这是一个如何使用小递归函数(写在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]
}
}
}
我用它来覆盖和合并两个 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));
}