Dump anchors that is not used by any alias

Issue #481 resolved
Takafumi Ohtake created an issue

Summary

It must be that there are some equaled objects to dump anchors.

But to dump anchors that is not used by any alias would be useful.
Because it is easy to edit dumped yaml with featured editor like IntelliJ if yaml contains anchors that would be used repeatedly.

Proposal

org.yaml.snakeyaml.nodes.Node class has anchor property.

If the property is set to a node, org.yaml.snakeyaml.serializer.AnchorGenerator#nextAnchor shuld be called and the anchor as returned value of the method is written for the node.

Environment

  • java

    • 1.8
  • snakeyaml

    • 1.26

Comments (14)

  1. Andrey Somov

    I am sorry, I did my best to understand it. But I do not.

    Is it a proposal to enhance the current implementation ? Add anchors to equal nodes even though it was not explicitly specified ?

  2. Takafumi Ohtake reporter

    Thank you for trying to understand what I mean.

    In my use case, this is very enhancement.
    I want to define some configuration pattern to make entire yaml file.

    For example:

    If dumped yaml has define section using anchor like this:

    defines:
      serverPattern1: &server_HighPerformance
        type: t3
        strage: 500
      serverPattern2: &server_LowPerformance
        type: t2
        strage: 250
      lbPattern1: &lb_Public
        name: lbForPublic
        vpc: vpc1
      lbPattern2: &lb_Internal
        name: lbForInternal
        vpc: vpc1
    
    current:
      assenbled1:
        server: *server_HighPerformance
        lb: *lb_Public
    

    To edit dumped yaml by choosing defined anchor is easier. Additionally IDE complements anchor names when I enter alias like this.

    Actually in my case, there are hundreds of defined anchors. So this feature is very useful.

    Currently snakeyaml doesn’t have any way to dump anchors that does not have any aliases.
    In above example, no way to dump &server_LowPerformance and &lb_Internal anchors.

    So, I propose that if the property is set to a node explicitly, org.yaml.snakeyaml.serializer.AnchorGenerator#nextAnchor shuld be called and the anchor as returned value of the method is written for the node.

    Would this comment help you understand what I mean?

  3. Alan Wang

    @Andrey Somov hi Andrey, I try to solve this issue, but foud that if we load the yaml string as an object first, then we will lose the anchor information, further dump the object as a YAML string, we do not know which nodes are unused anchors.

    My thought is to load the original YAML as a Node object and then add a method to dump the Node object as a YAML string. Because the Node object records the anchor attribute, we can obtain an unused anchor when dumping the Node object.

    what do you think?

    Node node = yaml.compose(new StringReader(str)); // transfer the yaml to Node object, which records the anchor information
    String result = yaml.dump(node); // overload this function, handle the node properly
    System.out.println(result);
    

  4. Alexander Maslov

    I still don’t get this issue, sorry. load->dump process is losing anchor information and not going to dump any not used anchors (if I remember correctly). IMHO, we don’t even have easy mechanism to provide something like AnchorNameResolver to be used to generate some specific names for anchors.

    If you manipulate Node(s) directly you can use serializer.serialize() method directly. Same way as it it used in Yaml.dampAll method.

  5. Alan Wang

    hi Alexander, thanks your reply, snakeyaml automatically generates anchor names(like id001, id002…) by matching the same node, even restoring the real anchor name is not an easy stuff.

    I think I should skip this issue for a while 😅

  6. Takafumi Ohtake reporter

    In Serializer#anchorNode, anchors map’s value is always null when there is no equaled node.

    So following code might resolve it. But I don’t know this way is the best implementation.

            } else {
                this.anchors.put(node, node.getAnchor() != null ? this.anchorGenerator.nextAnchor(node) : null);
                switch (node.getNodeId()) {
    

    https://bitbucket.org/asomov/snakeyaml/src/08d8cf9c222c44e1af7f2f8a29842943aaea3bb7/src/main/java/org/yaml/snakeyaml/serializer/Serializer.java#lines-131

  7. Alan Wang

    thanks your suggestion! after adding a new function of dump(Node node, Writer output) , then get the node through yaml.compose(new StringReader(str))`, we could dump the anchors which are not used by any alias.

    this is my fork repo: https://github.com/Alanscut/snakeyaml/commits/dump-anchor, If this is what you want, then I will submit a PR 😀

    /**
      * Serialize a YAML node into a YAML stream.
      *
      * @param node   YAML node to be serialized to YAML
      * @param output stream to write to
      */
    public void dump(Node node, Writer output) {
        Serializer serializer = new Serializer(new Emitter(output, dumperOptions), resolver,
                dumperOptions, null);
        try {
            serializer.open();
            serializer.serialize(node);
            serializer.close();
        } catch (IOException e) {
            throw new YAMLException(e);
        }
    }
    

  8. Takafumi Ohtake reporter

    Thank you for implementing it.

    I have reviewed your code. I think your code works.
    Awesome!!

    But It would be better that AnchorGenerator in DumperOption is arranged like below in test code.
    This would get output yaml be same as input yaml.

        options.setAnchorGenerator(Node::getAnchor);
    

  9. Log in to comment