Groovy GPath在许多条件下查找节点

时间:2016-08-11 19:29:03

标签: groovy xml-parsing xmlslurper gpath

假设有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>

我必须按条件找到level1节点(假设我们可以有很多level0个兄弟姐妹):

  1. 为每个level0找到所有“level1”节点,这些节点具有最大att1值(在yyyy-mm-dd中解释为Date
  2. level1个节点中找到一个在年和月属性中具有最大值的节点,解释为int s。
  3. 对于给定的示例,我希望找到val =“113”值的节点。 由于我不是 GPath 的专家,请帮助找到正确的Groovish解决方案。感谢。

2 个答案:

答案 0 :(得分:2)

预期的行为有点不清楚,请参阅我对帖子的评论。但是,我假设您希望按att1,然后按year,然后按month对数据进行排序,并找到最大值。

要以Groovy方式执行此操作,我将提取一些帮助程序方法,以便您可以看到正在发生的事情:

def date = { Date.parse('yyyy-MM-dd', it.@att1.toString()) }
def year = { it.@year.toString() }
def month = { it.@month.toString() }

然后你可以使用&#34; space-ship&#34;对节点进行排序。运营商<=>进行比较,并使用&#34; elvis&#34;如果第一个返回0(在比较相同时发生),则运算符?:执行下一级别比较:

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 :(得分:1)

目前我已经找到了这个解决方案,我想知道是否有更多Groovish方法可以做到这一点。

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',lev1.@att1.toString())
    }
}
.each {level1 ->
    level1.max { lev1 ->
        lev1.@year.toString() as int
    }
}.max {level1 ->
    level1.@month.toString() as int
}.collect()

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

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