Search code examples
groovyxml-parsingxmlslurpergpath

Groovy GPath find nodes by many conditions


Suppose having XML:

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <level0 id="2" t="1">
        <level1 id="lev1id21" att1="2015-05-12" val="121" status="0" year="2015" month="05" />
        <level1 id="lev1id22" att1="2015-06-13" val="132" status="0" year="2015" month="06" />
        <level1 id="lev1id23" att1="2015-07-11" val="113" status="0" year="2015" month="08" />
        <level1 id="lev1id23" att1="2015-07-11" val="114" status="0" year="2015" month="07" />
    </level0>
</data>

I have to find level1 node by conditions (assuming we could have many level0 siblings):

  1. For each level0 find all 'level1' nodes which have maximal att1 value (interpreted as Date in yyyy-mm-dd)
  2. Among those level1 nodes find one that has maximal value in year and month attributes, interpreted as ints.

For given example, I expect node with val="113" value to be found. Since I'm not an expert in GPath, please help to find a correct and Groovish solution. Thanks.


Solution

  • The expected behavior is a bit unclear, see my comment on the post. However, I'm working off the assumption you want to sort the data by att1, then by year, then by month, and find the max value.

    To do it in a Groovy way, I'd extract some helper methods so you can see what is going on:

    def date = { Date.parse('yyyy-MM-dd', [email protected]()) }
    def year = { [email protected]() }
    def month = { [email protected]() }
    

    Then you can sort the nodes using the "space-ship" operator <=> to do comparison, and using the "elvis" operator ?: to do the next level comparison if the first returns 0 (which happens when the comparison is equal):

    def nodes = new XmlSlurper().parseText(xml).level0.level1
    
    def max = nodes.sort { a, b ->
        date(a) <=> date(b) ?:
                year(a) <=> year(b) ?:
                        month(a) <=> month(b)
    } .collect { it.@val } .last()
    
    println max  
    // Prints "113", given your data above