SnakeYAML low-level API not parsing MapNode correctly

こ雲淡風輕ζ 提交于 2019-12-24 06:31:08

问题


I wanted to do some processing on values in yml file. Someone suggested me to use snakeYAML's low-level API for this purpose. So I've written some code using that but I'm pretty much stuck due to the following reasons.

Here's the code I've wrote:

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

Here is my yamlInput.yml:

Prakash: 
 Lucky:
  Number: 11

Really? :  NotAtAll

Here's what was printed on console(It was in a single line, I formatted it and added a comment to make it readable):

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

At this point I can extract the valueNode which are also ScalarNode by searching for valueNode=<org.yaml.snakeyaml.nodes.ScalarNode and then process the value in this node .

But the issue is that I don't know why it puts a garbage value while composing map nodes. So here are my questions:

  1. How to correctly compose yaml files so that map nodes appear correctly and not garbage values?
  2. After I'm done processing and have successfully replaced the values with the processed ones, how do I put these back to a yaml file?
  3. If you think this is a rubbish method to start with, please suggest me a better one.

回答1:


The reason you get the „garbage value“ is because of this section in 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());
}

Since the composed graph may contain cycles (because anchors & aliases have been resolved at this stage of parsing), toString will not recurse into Collection nodes (i.e. Mappings and Sequences).

This means that your node tree has indeed be composed correctly and you simply should not use toString to inspect it. That answers your first question.

To write that back to a YAML file, use something like

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

To answer question 3: In the previous question, you mentioned that you want to change (encrypt) certain values and leave the others untouched. If that is the case, I suggest you use yaml.parse instead of yaml.compose because you lose fewer information when working on the event stream than when working on the composed graph (meaning that the output will be more similar to the input).

You can then go through the generated events, identify the events you want to alter and replace them with the altered events, and then use an Emitter like I showed in the code above.

I showed with some Python code here how to identify events in an event stream from a list of strings (kind-a „YAML-path“), however that code inserts events at the given path instead of altering them. The Python and Java API are somewhat similar, so if you can read Python, that code may help you.



来源:https://stackoverflow.com/questions/57339814/snakeyaml-low-level-api-not-parsing-mapnode-correctly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!