2015-02-16 11 views
6

Chcę przeczytać dokument YAML na mapie obiektów niestandardowych (zamiast map, które domyślnie snakeYaml ma). Więc tak:Parsowanie dokumentu YAML z mapą w katalogu głównym przy użyciu snakeYaml

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

Lepiej być załadowany do mapy, która wygląda tak:

Map<Integer, Item> 

gdzie pozycja jest:

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

nie mogłem znaleźć sposób, aby to zrobić z snakeYaml i nie mogłem znaleźć lepszej biblioteki do tego zadania.

Dokumentacja ma tylko przykłady z mapami/Kolekcje zagnieżdżonych wewnątrz innych obiektów, dzięki czemu można wykonać następujące czynności:

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); 

Ale jak mam iść na temat definiowania formatu Mapa kiedy jest u podstaw dokument?

Odpowiedz

2

Musisz dodać niestandardowy Constructor. Jednak w twoim przypadku nie chcesz rejestrować tagu "item" lub "item-list".

W efekcie, chcesz zastosować Duck Typing do swojego Yaml. To nie jest super wydajne, ale jest stosunkowo łatwy sposób to zrobić.

class YamlConstructor extends Constructor { 
    @Override 
    protected Object constructObject(Node node) { 

    if (node.getTag() == Tag.MAP) { 
     LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>) super 
       .constructObject(node); 
     // If the map has the typeId and limit attributes 
     // return a new Item object using the values from the map 
     ... 
    } 
    // In all other cases, use the default constructObject. 
    return super.constructObject(node); 
+6

Wow, obsługa YAML w Javie jest apelująca. Chociaż to rozwiązanie działa, byłoby to bolesne, gdy trzeba sobie poradzić ze strukturami zagnieżdżonymi. Chyba po prostu skonwertuję wszystko na JSON i użyję Jacksona do analizy. – Justas

+0

Tak. Yaml parsowanie w java (/ scala) * jest * okropne. Pochodzący z Pythona, gdzie jest "wolny". – javadba

3

Oto, co zrobiłem w bardzo podobnej sytuacji. Po prostu zakasowałem cały plik yml na jednej karcie i dodałem tag map: do góry. Tak więc w twoim przypadku byłoby.

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

Następnie utwórz klasę statyczną w klasie, która odczyta ten plik w następujący sposób.

static class Items { 
    public Map<Integer, Item> map; 
} 

A następnie, aby przeczytać mapę po prostu użyj.

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

UPDATE:

Jeśli nie chcą lub nie mogą edytować plik yml można po prostu zrobić powyższe przekształcenia w kodzie podczas czytania pliku z czymś takim.

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

To jest naprawdę sprytne, jeśli możesz modyfikować lub tworzyć własne pliki. – Justas

+0

Zobacz wyżej powyżej, jak wyciągnąć tę samą sztuczkę, bez konieczności modyfikowania pliku bazowego. – crowmagnumb

+0

To jest prawie hack. Ale to bije * wszystko inne * Widziałem dla parsowania yaml przez java (scala faktycznie w moim przypadku!). Rewizja. – javadba