user3390259
user3390259

Reputation: 21

XML Parsing using groovy

How can I parse following XML file using Groovy

<Person>
    <name>a</name>
    <age>1</age>
</person>
<account>
    <number>4242</number>
    <bank>S</bank>
</account>
<account>
    <number>4242</number>
    <bank>T</bank>
</account>
<Person>
    <name>b</name>
    <age>1</age>
</person>
<account>
    <number>4242</number>
    <bank>S</bank>
</account>
<account>
    <number>4242</number>
    <bank>T</bank>
</account>

In this case person can have multiple accounts.How can I parse this xml?

Person A - finding all of bank accounts using groovy

Upvotes: 0

Views: 891

Answers (2)

Will
Will

Reputation: 14559

This is pretty ugly, but if there is no way to change the XML being received, you can iterate it using old school index manipulation.

The XML and some fixing:

def xml = '''
<Person>
    <name>a</name>
    <age>1</age>
</person>
<account>
    <number>4242</number>
    <bank>S</bank>
</account>
<account>
    <number>4242</number>
    <bank>T</bank>
</account>
<Person>
    <name>b</name>
    <age>1</age>
</person>
<account>
    <number>4242</number>
    <bank>S</bank>
</account>
<account>
    <number>4242</number>
    <bank>T</bank>
</account>'''

fixedXml = "<root>${xml.replaceAll('<Person>', '<person>')}</root>"

And the processing:

def root = new XmlParser().parseText fixedXml

def people = [:]

for (int i = 0; i < root.children().size(); i++) {
  def child = root.children()[i]

  if (child.name() == 'person') {

    people[child] = []

    while(true) {
      def nextChild = root.children()[i + 1]
      if (nextChild?.name() == 'account') {
        people[child] << nextChild
        i++
      } else {
        break
      }
    }

  }
}

assert people.size() == 2
assert people*.value*.size == [2, 2]
assert people['a'][0].bank.text() == "S"
assert people['b'][1].number.text() == "4242"

If the XML is worst than that, consider using neko to clean it.

Upvotes: 0

ludo_rj
ludo_rj

Reputation: 3954

Mark is right, first you need a well formated xml document. Then, you can use XmlSlurper (or XmlParser), both return an implementation of GPath.

Here I've added <root> and <accounts> tags to make the document xml valid:

 def doc = """
    <root>
        <person>
            <name>a</name>
            <age>1</age>
            <accounts>
                <account>
                    <number>4242</number>
                    <bank>S</bank>
                </account>
                <account>
                    <number>5252</number>
                    <bank>T</bank>
                </account>
            </accounts>
        </person>
        <person>    
            <name>b</name>
            <age>1</age>
            <accounts>
                <account>
                    <number>4242</number>
                    <bank>S</bank>
                </account>
                <account>
                    <number>4242</number>
                    <bank>T</bank>        
                </account>
            </accounts>
        </person>
    </root>
    """

then it's pretty easy to parse it with GPath:

def parser = new XmlSlurper().parseText(doc)
parser.person.findAll { p -> p.name == 'a' }
    .accounts.account.number.each {  v -> println "Account number[$v]" }

which renders:

Account number[4242]

Account number[5252]

Upvotes: 2

Related Questions