groovygroovy-console

Create a Map with Lists looping XML


I have a requirement which i am not able to solve.

My XML looks like the below

<root>
<node1>
<value1>AA</value1>
<value2>123</value2>
</node1>
<node1>
<node2>
<value1>AA</value1>
<value2>999</value2>
</node2>
<node3>
<value1>AB</value1>
<value2>456</value2>
</node3>
<node4>
<value1>AB</value1>
<value2>888</value2>
</node4>
</root>

My requirement is to create a Map with all the value2's in it.

Output should look like the below [AA:[123,999]] [AB:[456,888]]

i am unable to approach this problem and need help or pointers please.I will need to check if the value1 field is different in the next iteration to the next node and store.

please help here.


Solution

  • What @injecteer said.

    Another way involves two steps but might be easier to comprehend:

    import groovy.xml.*
    
    def data = '''
    <root>
    <node1>
    <value1>AA</value1>
    <value2>123</value2>
    </node1>
    <node2>
    <value1>AA</value1>
    <value2>999</value2>
    </node2>
    <node3>
    <value1>AB</value1>
    <value2>456</value2>
    </node3>
    <node4>
    <value1>AB</value1>
    <value2>888</value2>
    </node4>
    </root>'''
    
    def xml = new XmlSlurper().parseText(data)
    
    def result = xml.'*'.groupBy { 
      it.value1 
    }.collectEntries { k, v -> 
      [k, v.value2]
    }
    
    println result
    

    which, when executed, prints:

    ā”€āž¤ groovy solution.groovy
    [AA:[123, 999], AB:[456, 888]]
    

    where the first groupBy creates a Map<String, List<xml node>> where the keys are the AA, AB strings and the values are the xml nodes. The second collectEntries operation pulls out value2 from the nodes leaving the result variable as a Map<String, List<String>>.

    << edit >>

    I realized this solution actually uses a really weird groovy "feature" where if you call list.someProperty and someProperty does not exist on the list class (like java.util.ArrayList), groovy will return a list with all the someProperty values from the list elements.

    If we want to change this to not use that weirdness we can do:

    def result = xml.'*'.groupBy { 
      it.value1 
    }.collectEntries { k, v -> 
      [k, v*.value2]
    }
    
    

    instead which uses the groovy spread operator instead of the undocumented weirdness.