问题
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:
- How to correctly compose yaml files so that map nodes appear correctly and not garbage values?
- 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?
- 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