lospejos lospejos - 1 year ago 100
Groovy Question

Groovy GPath find nodes by many conditions

Suppose having XML:

<?xml version="1.0" encoding="UTF-8"?>
<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" />

I have to find
node by conditions (assuming we could have many

  1. For each
    find all 'level1' nodes which have maximal
    value (interpreted as
    in yyyy-mm-dd)

  2. Among those
    nodes find one that has maximal value in year and month attributes, interpreted as

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

Answer Source

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