SnakeYAML 低级 API 没有正确解析 MapNode

SnakeYAML low-level API not parsing MapNode correctly

我想对 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=<org.yaml.snakeyaml.nodes.ScalarNode提取valueNode也是ScalarNode,然后处理这个节点中的值。

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

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

你得到“垃圾值”的原因是因为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 不会递归到 Collection 节点(即映射和序列)。

这意味着您的节点树确实已正确组成,您根本不应该使用 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 代码 如何从字符串列表(一种“YAML 路径”)中识别事件流中的事件,但是该代码将事件插入到给定的路径而不是改变它们。 Python 和 Java API 有点相似,所以如果你能阅读 Python,该代码可能会对你有所帮助。