2015-02-16 8 views
6

Ich möchte ein YAML-Dokument zu einer Karte von benutzerdefinierten Objekten (anstelle von Karten, die snakeYaml standardmäßig tut) lesen. So folgt aus:Parsing eines YAML-Dokuments mit einer Karte im Stamm mithilfe von snakeYaml

19: 
    typeID: 2 
    limit: 300 
20: 
    typeID: 8 
    limit: 100 

Würde auf eine Karte geladen werden, die wie folgt aussieht:

Map<Integer, Item> 

wo Artikel sind:

class Item { 
    private Integer typeId; 
    private Integer limit; 
} 

ich keine Möglichkeit, dies zu tun mit SnakeYAML finden konnte, und ich konnte auch keine bessere Bibliothek für diese Aufgabe finden.

Die Dokumentation nur Beispiele mit Karten/Sammlungen verschachtelt innerhalb anderer Objekte hat, so dass Sie Folgendes tun können:

TypeDescription typeDescription = new TypeDescription(ClassContainingAMap.class); 
    typeDescription.putMapPropertyType("propertyNameOfNestedMap", Integer.class, Item.class); 
    Constructor constructor = new Constructor(typeDescription); 
    Yaml yaml = new Yaml(constructor); 
    /* creating an input stream (is) */ 
    ClassContainingAMap obj = (ClassContainingAMap) yaml.load(is); 

Aber wie gehe ich über das Kartenformat definieren, wenn es an der Wurzel ist das Dokument?

Antwort

2

Sie müssen eine benutzerdefinierte Constructor hinzufügen. In Ihrem Fall möchten Sie jedoch kein "item" - oder "item-list" -Tag registrieren.

Eigentlich möchten Sie Duck Typing auf Ihre Yaml anwenden. Es ist nicht super effizient, aber es gibt einen relativ einfachen Weg, dies zu tun.

+6

Wow, ist YAML-Unterstützung in Java Apalling. Während diese Lösung funktioniert, wäre es ein Kopfzerbrechen, wenn man sich mit verschachtelten Strukturen befassen müsste. Ich denke, ich werde einfach alles in JSON konvertieren und Jackson zum Parsen verwenden. – Justas

+0

Ja. Yaml Parsing in Java (/ scala) * ist * schrecklich. Kommt von Python, wo es "frei" ist. – javadba

3

Hier ist, was ich für eine sehr ähnliche Situation getan habe. Ich habe nur meine gesamte YML-Datei über einen Tab mit Tabs versehen und oben einen map: -Tag hinzugefügt. Also für Ihren Fall wäre es.

map: 
    19: 
    typeID: 2 
    limit: 300 
    20: 
    typeID: 8 
    limit: 100 

Und dann erstellen Sie eine statische Klasse in Ihrer Klasse, die diese Datei wie folgt liest.

Und dann, um Ihre Karte einfach zu lesen.

Yaml yaml = new Yaml(new Constructor(Items)); 
Items items = (Items) yaml.load(<file>); 
Map<Integer, Item> itemMap = items.map; 

UPDATE:

Wenn Sie nicht wollen oder können Ihre yml Datei nicht bearbeiten können Sie einfach nicht in Code die oben verwandeln, während die Datei mit so etwas wie dieses zu lesen.

try (BufferedReader br = new BufferedReader(new FileReader(new File("example.yml")))) { 
    StringBuilder builder = new StringBuilder("map:\n"); 
    String line; 
    while ((line = br.readLine()) != null) { 
     builder.append(" ").append(line).append("\n"); 
    } 

    Yaml yaml = new Yaml(new Constructor(Items)); 
    Items items = (Items) yaml.load(builder.toString()); 
    Map<Integer, Item> itemMap = items.map; 
} 
+0

Dies ist wirklich sehr schlau, wenn Sie Ihre eigenen Dateien ändern oder erstellen können. – Justas

+0

Siehe Update oben für wie Sie den gleichen Trick ziehen, ohne die zugrunde liegende Datei ändern zu müssen. – crowmagnumb

+0

Das ist so ziemlich ein Hack. Aber es schlägt * alles andere *, das ich gesehen habe, um yaml mit Java zu sclappen (scala eigentlich in meinem Fall!). Upvoted. – javadba