2013-08-23 17 views
5

Czekam na użycie niestandardowych konstrukcji z SnakeYAML i nie jestem pewien jak zaimplementować zagnieżdżanie. Używam this example jako odniesienia.Zagnieżdżone konstrukcje z SnakeYAML

w połączonej przykład, istotne YAML i Construct jest

- !circle 
    center: {x: 73, y: 129} 
    radius: 7 

private class ConstructCircle extends AbstractConstruct { 
    @SuppressWarnings("unchecked") 
    public Object construct(Node node) { 
     MappingNode mnode = (MappingNode) node; 
     Map<Object, Object> values = constructMapping(mnode); 
     Circle circle = new Circle((Map<String, Integer>) values.get("center"), (Integer) values.get("radius")); 
     return circle; 
    } 
} 

Teraz zmieńmy YAML się,

- !circle 
    center: !point 
    x: 73 
    y: 129 
    radius: 7 

Chciałbym użyć inny AbstractConstruct, aby przeanalizować obiekt !point, ale zrób to w ramach ConstructCircle kontekst. Moje zrozumienie relacji Construct/Node jest dość drżące i nie mam pojęcia, jak używać niestandardowego konstruktora w niestandardowym konstruktorze. Wszelkie myśli lub zasoby?

Odpowiedz

0

Napisałem szybkie i brudne customConstructMapping() do parsowania twoich zagnieżdżonych konstruktów YAML.

public Map<Object, Object> customConstructMapping(MappingNode mnode) { 
    Map<Object, Object> values = new HashMap<Object, Object>(); 
    Map<String, Integer> center = new HashMap<String, Integer>(); 
    List<NodeTuple> tuples = mnode.getValue(); 
    for (NodeTuple tuple : tuples) { 
     ScalarNode knode = (ScalarNode) tuple.getKeyNode(); 
     String key = knode.getValue(); 

     Node vnode = tuple.getValueNode(); 
     if (vnode instanceof MappingNode) { 
      MappingNode nvnode = (MappingNode) vnode; 
      if ("!point".equals(nvnode.getTag().getValue())) { 
       List<NodeTuple> vtuples = nvnode.getValue(); 
       for (NodeTuple vtuple : vtuples) { 
        ScalarNode vknode = (ScalarNode) vtuple.getKeyNode(); 
        ScalarNode vvnode = (ScalarNode) vtuple.getValueNode(); 
        Integer val = Integer.parseInt(vvnode.getValue()); 
        center.put(vknode.getValue(), val); 
       } 
       values.put(key, center); 
      } 
     } else if (vnode instanceof ScalarNode) { 
      Integer val = Integer.parseInt(((ScalarNode) vnode).getValue()); 
      values.put(key, val); 
     } 
    } 
    return values; 
} 
0

Snake Yaml powinien sam zająć się zagnieżdżaniem. Musisz tylko dodać wszystkie swoje AbstractConstructs do pola yamlConstructors wewnątrz Twojego Custom Constructor.

0

W porządku po wykonaniu kilku innych projektów z SnakeYaml. Myślę, że w końcu rozumiem twoje pytanie. Zagnieżdżanie jest obsługiwane automatycznie przez SnakeYaml. Nie musisz się o to martwić. Wszystko, co musisz zrobić, to stworzyć kolejny punkt Construct for! I dodać go do mapy yamlConstructors w swojej klasie konstruktora niestandardowego. Umożliwi to umieszczenie znacznika!! W dowolnym miejscu.

punkt konstrukt może wyglądać mniej więcej tak:

class PointConstruct extends AbstractConstruct{ 
    public Object construct(Node node){ 
     String line = (String)constructScalar((ScalarNode)node); 
     Pattern pointPattern = Pattern.compile("\\((\\d+),(\\d+\\)"); 
     Matcher m = pointPattern.matcher(line); 
     if(m.find()) 
     return new Point(m.group(1),m.group(2)); 
     throw new RuntimeException("Could not parse a point"); 
    } 
} 

Plik yaml będzie wtedy wyglądać tak:

!circle 
center: !point (73,179) 
radius: 7 

myślę, że to wyjście wygląda o wiele ładniej. Jeśli dodasz ImplicitResolver do yaml:

yaml.addImplicitResolver(new Tag("!point"), Pattern.compile("\\((\\d+),(\\d+\\)"),"("); 

Wtedy yaml wyglądałby tak.

!circle 
center: (73,179) 
radius: 7 

Alternatywnie możesz zrezygnować z pisania nowego Construct i po prostu mieć Point podążać za wzorem fasoli i użyć czegoś takiego.

!circle 
center !!package.goes.here.Point 
    x: 73 
    y: 179 
radius: 7 

Tak czy inaczej Mam nadzieję, że ta odpowiedź jest nieco bardziej przejrzysta niż moja ostatnia.