![](/img/trans.png)
[英]Java and YAML: how to parse multiple yaml documents and merge them to a single YAML representation?
[英]Parse a single POJO from multiple YAML documents representing different classes
我想使用一個包含多個不同對象的 YAML 文件 - 用於不同的應用程序。 I need to fetch one object to get an instance of MyClass1, ignoring the rest of docs for MyClass2, MyClass3, etc. Some sort of selective de-serializing: now this class, then that one... The structure of MyClass2, MyClass3 is使用 MyClass1 的應用程序完全不知道。 當然,該文件始終是有效的 YAML。
YAML 可以是我們實現這種多類容器所需的任何結構。 首選的解析工具是snakeyaml。
明智嗎? 我怎樣才能忽略除一個 object 之外的所有內容?
UPD:將所有“文檔”替換為“對象”。 我認為我們必須談論包含多個不同結構對象的單個 YAML 文檔。 更多的是,解析器只知道 1 個結構,並想忽略 rest。
UDP2:我認為使用snakeyaml 是不可能的。 無論如何,我們必須讀取所有對象 - select 是稍后需要的。 但也許我錯了。
UPD2:示例配置文件
---
-
exportConfiguration781:
attachmentFieldName: "name"
baseSftpInboxPath: /home/user/somedir/
somebool: false
days: 9999
expected:
- ABC w/o quotes
- "Cat ABC"
- "Some string"
dateFormat: yyyy-MMdd-HHmm
user: someuser
-
anotherConfiguration:
k1: v1
k2:
- v21
- v22
使用 SnakeYAML 絕對可以做到這一點,盡管這不是微不足道的。 這是您需要做的一般綱要:
首先,讓我們看看使用 SnakeYAML 進行加載的作用。 這是YAML
class 的重要部分:
private Object loadFromReader(StreamReader sreader, Class<?> type) {
Composer composer = new Composer(new ParserImpl(sreader), resolver, loadingConfig);
constructor.setComposer(composer);
return constructor.getSingleData(type);
}
作曲家將 YAML 輸入解析為Nodes 。 為此,它不需要任何關於類結構的知識,因為每個節點都是 ScalarNode、SequenceNode 或 MappingNode,它們只代表 YAML 結構。
構造函數獲取composer生成的根節點並從中生成本地 POJO。 因此,您要做的是在節點圖的某些部分到達構造函數之前丟棄它們。
最簡單的方法可能是從Composer
派生並覆蓋兩個這樣的方法:
public class MyComposer extends Composer {
private final int objIndex;
public MyComposer(Parser parser, Resolver resolver, int objIndex) {
super(parser, resolver);
this.objIndex = objIndex;
}
public MyComposer(Parser parser, Resolver resolver, LoaderOptions loadingConfig, int objIndex) {
super(parser, resolver, loadingConfig);
this.objIndex = objIndex;
}
@Override
public Node getNode() {
return strip(super.getNode());
}
private Node strip(Node input) {
return ((SequenceNode)input).getValue().get(objIndex);
}
}
strip
實現只是一個例子。 在這種情況下,我假設您的 YAML 看起來像這樣(對象內容是任意的):
- {first: obj}
- {second: obj}
- {third: obj}
而您只需 select 和 object 您實際上想要按序列中的索引反序列化。 但是你也可以有更復雜的東西,比如搜索算法。
現在你有了自己的作曲家,你可以做
Constructor constructor = new Constructor();
// assuming we want to get the object at index 1 (i.e. second object)
Composer composer = new MyComposer(new ParserImpl(sreader), new Resolver(), 1);
constructor.setComposer(composer);
MyObject result = (MyObject)constructor.getSingleData(MyObject.class);
@flyx 的答案對我很有幫助,通過覆蓋一些方法打開了解決庫(在我們的例子中是snakeyaml)限制的方法。 非常感謝。 很有可能有一個最終的解決方案——但不是現在,此外。 下面的簡單解決方案是健壯的,即使我們找到了完整的庫入侵解決方案,也應該考慮。
我決定通過雙重蒸餾來解決這個任務,抱歉,處理配置文件。 想象后者由幾個部分組成,每個部分都由唯一的標記分隔符標記。 為了保持 YAML-likenes,它可能是
---
#this is a unique key for the configuration A
<some YAML document>
---
#this is another key for the configuration B
<some YAML document
第一遍是預處理。 對於給定的字符串文件字符串和字符串鍵(例如,DELIMITER = "\n---\n"。)我們 select 和 substring 與鍵定義的配置:
int begIndex;
do {
begIndex= fileString.indexOf(DELIMITER);
if (begIndex == -1) {
break;
}
if (fileString.startsWith(DELIMITER + key, begIndex)) {
fileString = fileString.substring(begIndex + DELIMITER.length() + key.length());
break;
}
// spoil alien delimiter and repeat search
fileString = fileString.replaceFirst(DELIMITER, " ");
} while (true);
int endIndex = fileString.indexOf(DELIMITER);
if (endIndex != -1) {
fileString = fileString.substring(0, endIndex);
}
現在我們將 fileString 提供給簡單的 YAML 解析
ExportConfiguration configuration = new Yaml(new Constructor(ExportConfiguration.class))
.loadAs(fileString, ExportConfiguration.class);
這次我們有一個文檔必須共同響應 ExportConfiguration class。
注 1:配置文件 rest 的結構甚至內容完全沒有作用。 這是主要思想,在單個文件中獲取獨立配置
注 2:配置的 rest 可能是 JSON 或 XML 或其他。 我們有一個方法預處理器,它返回一個字符串配置——下一個處理器會正確解析它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.