lospejos lospejos - 1 year ago 90
Groovy Question

Groovy find nodes using gpath with certian child count and expression

Suppose I have an XML:

<?xml version="1.0" encoding="UTF-8"?>
<level0 id="1" t="0">
<level1 id="lev1id01" att1="2015-05-12" val="12" status="0"/>
<level1 id="lev1id02" att1="2015-06-13" val="13" status="0"/>
<level1 id="lev1id03" att1="2015-07-10" val="13" status="0"/>

<level0 id="2" t="0">
<level1 id="lev1id11" att1="2015-05-12" val="121" status="0"/>
<level1 id="lev1id12" att1="2015-06-13" val="132" status="0"/>
<level1 id="lev1id13" att1="2015-07-11" val="113" status="0"/>

<level0 id="2" t="1">
<level1 id="lev1id21" att1="2015-05-12" val="121" status="0"/>
<level1 id="lev1id22" att1="2015-06-13" val="132" status="0"/>
<level1 id="lev1id23" att1="2015-07-11" val="113" status="0"/>
<level1 id="lev1id23" att1="2015-07-11" val="113" status="0"/>

I want to get all
nodes (using GPath) which are:

  1. If
    then select this node (level0) only if all its
    children has

  2. If
    then select this node (level0) only if the last
    child has
    . When I say last I mean the
    node with maximum value in
    contains date in

With XPath I would use functions like max() and count(), but I can't get how it could be done using GPath.


Answer Source

The max() and count() functions defined by Groovy on Iterable can be used within GPath expressions in place of their XPath equivalents.

// This closure is for level0[t=0] elements.
// It selects the level0 if the count of its level1[status=0] children is 0.
def t0Select = { level0 -> 
    level0.level1.count { level1 -> level1.@status != '0' } == 0 

// This closure is for level1[t=1] elements.
// It selects the level0 if its level1 element with the maximum date has a status of "0" 
def t1Select = { level0 -> 
    level0.level1.max { level1 -> Date.parse('yyyy-MM-dd', level1.@att1.toString()) }?.@status == '0' 

// Parse the XML and delegate to the appropriate closure above as per the t attribute
def selected = new XmlSlurper().parseText(xml).level0.findAll { level0 -> 
    level0.@t == '0' ? t0Select(level0) : t1Select(level0)