Kumar
Kumar

Reputation: 23

How to loop over XML child nodes using groovy script

I have an XML response as below:

<ns:Envelope xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/">
 <ns:Body>
    <ns:response xmlns:svc="http://...serviceNameSpace" 
                xmlns:ent="http://....entitiesNameSpace">
        <ns:customer>
            <ns:contact>
                <ns:type>firstclass</ns:type>
                <ns:email>[email protected]</ns:email>
                <ns:details>
                    <ns:name>Kevin</ns:name>
                    <ns:area>Networking</ns:area>
                </ns:details>
                <ns:address>
                    <ns:code>39343</ns:code>
                    <ns:country>US</ns:country>
                </ns:address>
             </ns:contact>
            <ns:contact>
                <ns:type>secondclass</ns:type>
                <ns:email>[email protected]</ns:email>
                <ns:details>
                    <ns:name>John</ns:name>
                    <ns:area>Development</ns:area>
                <ns:address>
                    <ns:code>23445</ns:code>
                    <ns:country>US</ns:country>
             </ns:contact>                 
        </ns:customer>
    </ns:response >
</ns:Body>

I am trying this to iterate childnodes details and address to validate the response with the request properties. But I could assert email but couldn't go into details (name and area) and address (code and country). Below is the code I am using

import groovy.xml.*

def envelope = new XmlSlurper().parseText(messageExchange.responseContentAsXml)
def type = 'secondclass'
def emailAddress= ${properties#emailAddress}

envelope.'**'
.findAll { it.name() == 'contact' }
.findAll { it.type.text().contains(type) }
.each {
        assert emailAddress== it.emailAddress.text()
    }

Please help me in iterating the nodes details(name and area) and address (code and country) for assertion

Upvotes: 2

Views: 11309

Answers (2)

Pines Tran
Pines Tran

Reputation: 679

Firstly, get the 'contact' node by filter type = "secondclass". Secondly, based on the results of step 1, make a test on each item.

Your groovy script will be changed like this:

    import groovy.xml.*
    
    def envelope = new XmlSlurper().parseText(messageExchange.responseContentAsXml);
    def type = 'secondclass';
    def emailAddress= ${properties#emailAddress};
    
    envelope.Body.response.customer.contact
         .findAll {contactNode -> contactNode.type.text() == type}
         .each{ currentNode -> assert emailAddress== currentNode.emailAddress.text()};

Upvotes: 0

Matias Bjarland
Matias Bjarland

Reputation: 4482

First of all, it seems that your xml is slightly broken with missing closing tags. I took the liberty of fixing that in the example below.

Conceptually, when you are navigating through the xml with expressions like xml.Envelope.Body.response you are navigating through xml nodes. Note the distinction here between xml nodes (i.e. elements) and the actual data or text within the nodes.

The xml nodes returned from XmlSlurper are represented as descendants of the groovy GPathResult class. These descendants include NodeChild, NodeChildren, NoChildren, and Attribute, all of which can be returned by an xml.Envelope.Body.Response type of query depending on how the query and the xml looks. To retrieve the actual text data within a node you need to call node.text().

With the xml fixed and the above in mind, the following code:

def str = '''\
<ns:Envelope xmlns:ns="http://schemas.xmlsoap.org/soap/envelope/">
<ns:Body>
    <ns:response xmlns:svc="http://...serviceNameSpace" xmlns:ent="http://....entitiesNameSpace">
        <ns:customer>
            <ns:contact>
                <ns:type>firstclass</ns:type>
                <ns:email>[email protected]</ns:email>
                <ns:details>
                    <ns:name>Kevin</ns:name>
                    <ns:area>Networking</ns:area>
                </ns:details>
                <ns:address>
                    <ns:code>39343</ns:code>
                    <ns:country>US</ns:country>
                </ns:address>
             </ns:contact>
            <ns:contact>
                <ns:type>secondclass</ns:type>
                <ns:email>[email protected]</ns:email>
                <ns:details>
                    <ns:name>John</ns:name>
                    <ns:area>Development</ns:area>
                </ns:details>
                <ns:address>
                    <ns:code>23445</ns:code>
                    <ns:country>US</ns:country>
                </ns:address>
             </ns:contact>                 
        </ns:customer>
    </ns:response >
</ns:Body>
</ns:Envelope>
'''

def xml = new XmlSlurper(false, true).parseText(str)

def contactNodes = xml.Body.response.customer.contact

assert contactNodes.first().email               == '[email protected]'
assert contactNodes.first().details.name.text() == "Kevin"
assert contactNodes.first().details.area.text() == "Networking"

assert contactNodes.last().email               == '[email protected]'
assert contactNodes.last().details.name.text() == "John"
assert contactNodes.last().details.area.text() == "Development"

runs and all the assertions succeed.

The contactNodes variable is a groovy NodeChildren object and can for all intents and purposes be treated as a List of nodes (i.e. you can call methods like .each {}, .every {}, .any {}, ... on it).

edit in response to comment: To iterate only over contact nodes with specific properties, you can do:

xml.Body.response.customer.contact.findAll { contactNode ->
    contactNode.type.text() == 'firstclass' 
}.each { firstClassContactNode -> 
    assert firstClassContactNode.email.text() == "[email protected]"
}

Upvotes: 2

Related Questions