lospejos lospejos - 3 months ago 40
Groovy Question

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
    int
    s.



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.

Answer

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', it.@att1.toString()) }
def year = { it.@year.toString() }
def month = { it.@month.toString() }

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
Comments