1
votes

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.

2
Your expected result does not match your criteria. You want to sort the nodes by att1, then by year, then by month? In that case I would expect a result of 113 given your data. - thecodesmith_
@thecodesmith_ Thanks, I updated expected result, you're right, I expect to get 113 - lospejos

2 Answers

2
votes

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
1
votes

For now I've found this solution, I'd like to know if there is a more Groovish way to do this.

def 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>'''

def nodes = new XmlSlurper().parseText(xml).level0.level1.findAll {level1 ->
    level1.max {lev1->
        Date.parse('yyyy-MM-dd',[email protected]())
    }
}
.each {level1 ->
    level1.max { lev1 ->
        [email protected]() as int
    }
}.max {level1 ->
    [email protected]() as int
}.collect()

println "${nodes.count {it}}"

nodes.each { n ->
    println "val = ${n.@val}"
}