【问题标题】:SnakeYAML low-level API not parsing MapNode correctlySnakeYAML 低级 API 未正确解析 MapNode
【发布时间】:2019-12-11 20:50:59
【问题描述】:

我想对 yml 文件中的值进行一些处理。有人建议我为此目的使用snakeYAML 的low-level API。所以我使用它编写了一些代码,但由于以下原因,我几乎被卡住了。

这是我写的代码:

public static void main(String[] args) throws Exception{
        Yaml yaml = new Yaml();
        FileReader contentFromFile=new FileReader("/Users/prakash.tiwari/Desktop/yamlInput.yml"); 
        for (Node node : yaml.composeAll(contentFromFile)) {
            System.out.println(node);
        }
    }

这是我的yamlInput.yml

Prakash: 
 Lucky:
  Number: 11

Really? :  NotAtAll

这是控制台上打印的内容(它在一行中,我对其进行了格式化并添加了注释以使其可读):

<org.yaml.snakeyaml.nodes.MappingNode 
(
    tag=tag:yaml.org,2002:map, 
    values=
    { 
        key=<org.yaml.snakeyaml.nodes.ScalarNode (tag=tag:yaml.org,2002:str, value=Prakash)>; 
        value=355629945     // Why is this a garbage value?
    }
    { 
        key=<org.yaml.snakeyaml.nodes.ScalarNode (tag=tag:yaml.org,2002:str, value=Really?)>; 
        value=
        <NodeTuple 
            keyNode=<org.yaml.snakeyaml.nodes.ScalarNode (tag=tag:yaml.org,2002:str, value=Really?)>; 
            valueNode=<org.yaml.snakeyaml.nodes.ScalarNode (tag=tag:yaml.org,2002:str, value=NotAtAll)>
        > 
    }
)>

此时我可以通过搜索valueNode=&lt;org.yaml.snakeyaml.nodes.ScalarNode 来提取同样是ScalarNodevalueNode,然后处理该节点中的值。

但问题是我不知道为什么它在组成地图节点时会放置一个垃圾值。所以这是我的问题:

  1. 如何正确编写 yaml 文件,以便地图节点正确显示而不是垃圾值?
  2. 完成处理并成功将值替换为处理后的值后,如何将这些值放回 yaml 文件?
  3. 如果您认为这是一种垃圾方法,请向我推荐一个更好的方法。

【问题讨论】:

    标签: java parsing yaml snakeyaml


    【解决方案1】:

    你得到“垃圾值”的原因是因为MappingValue's toString method中的这个部分:

    if (node.getValueNode() instanceof CollectionNode) {
        // to avoid overflow in case of recursive structures
        buf.append(System.identityHashCode(node.getValueNode()));
    } else {
        buf.append(node.toString());
    }
    

    由于组合图可能包含循环(因为在此解析阶段已解析锚点和别名),toString 不会递归到集合节点(即映射和序列)。

    这意味着您的节点树确实已正确组合,您根本不应该使用toString 来检查它。这回答了你的第一个问题。

    要将其写回 YAML 文件,请使用类似

    Emitter emitter = new Emitter(/* e.g. a FileWriter */ writer, new DumperOptions());
    for (Event event : yaml.serialize(/* the root node */ node)) {
        emitter.emit(event);
    }
    

    回答问题 3:在上一个问题中,您提到要更改(加密)某些值,而其他值保持不变。如果是这种情况,我建议您使用yaml.parse 而不是yaml.compose,因为在处理事件流时丢失的信息比处理组合图时要少(这意味着输出将更类似于输入)。

    然后,您可以检查生成的事件,确定要更改的事件并用更改后的事件替换它们,然后使用上面代码中显示的发射器。

    我用一些 Python 代码 here 展示了如何从字符串列表(一种“YAML 路径”)中识别事件流中的事件,但是该代码在给定路径中插入事件而不是更改它们。 Python 和 Java API 有点相似,所以如果你能读懂 Python,那段代码可能会对你有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-28
      • 1970-01-01
      • 1970-01-01
      • 2016-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多