嵌套构造与SnakeYAML

时间:2013-08-23 22:17:08

标签: java yaml snakeyaml

我正在考虑使用SnakeYAML的自定义构造,并且不确定如何实现嵌套。我使用this example作为参考。

在链接示例中,相关的YAML和Construct是,

- !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;
    }
}

现在,让我们将YAML更改为,

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

我想使用另一个AbstractConstruct来解析!point个对象,但是在ConstructCircle上下文中执行此操作。我对Construct/Node关系的理解非常不稳定,我对如何在自定义构造函数中使用自定义构造函数感到茫然。有什么想法或资源吗?

3 个答案:

答案 0 :(得分:1)

在与SnakeYaml合作完成更多项目之后还好。我想我终于理解了你的问题。嵌套由SnakeYaml自动处理。你不必担心这一点。您需要做的就是创建另一个Construct for!point,并将其添加到自定义构造函数类中的映射yamlConstructors。这将在任何地方启用!point标记。

点构造可能看起来像这样:

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

您的Yaml文件将如下所示:

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

我认为这个输出看起来好多了。如果您向yaml添加ImplicitResolver:

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

然后yaml看起来像这样。

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

或者你可以放弃编写一个新的Construct,让Point跟随bean模式并使用类似的东西。

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

无论如何希望这个答案比我上一个答案更明确。

答案 1 :(得分:0)

我写了一个快速而脏的customConstructMapping()来解析你的嵌套构造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;
}

答案 2 :(得分:0)

Snake Yaml应该自己动手筑巢。您只需确保将所有AbstractConstructs添加到Custom Constructor中的yamlConstructors字段。