Groovy XMLSlurper - searching sepecific node

十年热恋 提交于 2019-12-11 08:44:30

问题


I need to find a specific node with Groovy's XMLSlurper. The condition should be that the text/value of the children nodes have to match. In the following example I want to search for a book node where the year is '2003' and the price is '39.95'.

<bookstore name="Store A">
  <employee>
      <id>546343</id>
      <name>Dustin Brown</name>
  </employee>
  <employee>
      <id>547547</id>
      <name>Lisa Danton</name>
  </employee>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
  <book category="children">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
  <book category="web">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>
<bookstore name="Store B">
...
</bookstore>

回答1:


Given:

def xml = '''<stores>
  <bookstore name="Store A">
      <employee>
          <id>546343</id>
          <name>Dustin Brown</name>
      </employee>
      <employee>
          <id>547547</id>
          <name>Lisa Danton</name>
      </employee>
      <book category="cooking">
        <title lang="en">Everyday Italian</title>
        <author>Giada De Laurentiis</author>
        <year>2005</year>
        <price>30.00</price>
      </book>
      <book category="children">
        <title lang="en">Harry Potter</title>
        <author>J K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
      </book>
      <book category="web">
        <title lang="en">Learning XML</title>
        <author>Erik T. Ray</author>
        <year>2003</year>
        <price>39.95</price>
      </book>
  </bookstore>
  <bookstore name="Store B">
  </bookstore>
</stores>'''

Then

new XmlSlurper().parseText(xml).bookstore.book.findAll { it.year == '2003' && it.price == '39.95' }



回答2:


Here is another way to achieve the same.

Note that user can easily change / add the additional and condition(s) easily by adding as shown below

def queryData = [[<element>, <operator>, <element value>], [<element>, <operator>, <element value>], ...]

Operator can be one the below:

  • EQ for equals to
  • LE for less than or equals to
  • GE for greater than or equals to
  • GT for greater than
  • LT for less than
  • NE for not equals to

For example:

def queryData = [['year','EQ', '2003'], ['price', 'LE', '39.95']]

Basically it creates a closure based on the queryData and pass it to findAll.

getQuery closure builds the query to the above list of condition as

{ it -> it.year.text() == '2003' && it.price.text() <= '39.95' }

I felt that it would be easier for some new folks trying groovy to use above list instead of closure as above which is built dynamically.

Here is the script:

​def xml = """<stores>  <bookstore name="Store A">
      <employee>
          <id>546343</id>
          <name>Dustin Brown</name>
      </employee>
      <employee>
          <id>547547</id>
          <name>Lisa Danton</name>
      </employee>
      <book category="cooking">
        <title lang="en">Everyday Italian</title>
        <author>Giada De Laurentiis</author>
        <year>2005</year>
        <price>30.00</price>
      </book>
      <book category="children">
        <title lang="en">Harry Potter</title>
        <author>J K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
      </book>
      <book category="web">
        <title lang="en">Learning XML</title>
        <author>Erik T. Ray</author>
        <year>2003</year>
        <price>39.95</price>
      </book>
  </bookstore>
  <bookstore name="Store B">
  </bookstore>
</stores>"""

//You may just add additional conditions into below list
def queryData = [['year','EQ', '2003'], ['price', 'LE', '39.95']]

enum Operator {
  EQ('=='), LE('<='), GE('>='), GT('>'), LT('<'), NE('!=')
  def value
  Operator(String value){
    this.value = value
  }

  def getValue(){
    value
  }
}

def getQuery = { list ->
  def sb = new StringBuffer('{ it -> ') 
  list.eachWithIndex { sublist, index ->
   index == 0 ?: sb.append(' && ')
   Operator operator = sublist[1]
   sb.append("it.${sublist[0]}.text() ${operator.value} '${sublist[2]}'")
  }
  def query = sb.append(' }').toString()
  println "Query formed is : ${query}"
  def sh = new GroovyShell()
  sh.evaluate(query)
}

def getBooks = { stores, closure ->
  stores.'**'.findAll { closure(it) } ?: 'Could not find matching book'
}

def stores = new XmlSlurper().parseText(xml)

def result = getBooks(stores, getQuery(queryData))
println result

You may quickly try Demo

Also note that it is currently does only and of conditions, does not support or.



来源:https://stackoverflow.com/questions/42222531/groovy-xmlslurper-searching-sepecific-node

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!