xmlgroovysoapuiassertionxmlslurper

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>kevin@....com</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>john@...com</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


Solution

  • 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>kevin@....com</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>john@...com</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               == 'kevin@....com'
    assert contactNodes.first().details.name.text() == "Kevin"
    assert contactNodes.first().details.area.text() == "Networking"
    
    assert contactNodes.last().email               == 'john@...com'
    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() == "kevin@....com"
    }