Properly iterating through XML with namespaces in Groovy

maschwenk picture maschwenk · Jul 23, 2012 · Viewed 8.1k times · Source

I have the following xml code:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <cms:RelatedConfigurationItemList xmlns:cms="some namespace">
         <ConfigurationItem>
            <name>data</name>
            <id>data</id>
            <type>data</type>
            <relationship>IS CHILD OF</relationship>
            <ConfigurationItemList>
               <ConfigurationItem>
                  <name>data</name>
                  <id>data</id>
                  <type>data</type>
                  <relationship>IS CHILD OF</relationship>
                  <ConfigurationItemList/>
               </ConfigurationItem>
               <ConfigurationItem>
                  <name>data</name>
                  <id>data</id>
                  <type>data</type>
                  <relationship>IS CHILD OF</relationship>
                  <ConfigurationItemList/>
               </ConfigurationItem>
            </ConfigurationItemList>
         </ConfigurationItem>
     <ConfigurationItem>
            <name>other data</name>
            <id>other data</id>
            <type>other data</type>
            <relationship>IS CHILD OF</relationship>
            <ConfigurationItemList>
               <ConfigurationItem>
                  <name>other data</name>
                  <id>other data</id>
                  <type>other data</type>
                  <relationship>IS CHILD OF</relationship>
                  <ConfigurationItemList/>
               </ConfigurationItem>
               <ConfigurationItem>
                  <name>other data</name>
                  <id>other data</id>
                  <type>other data</type>
                  <relationship>IS CHILD OF</relationship>
                  <ConfigurationItemList/>
               </ConfigurationItem>
            </ConfigurationItemList>
         </ConfigurationItem>
      </cms:RelatedConfigurationItemList>
   </soapenv:Body>
</soapenv:Envelope>

That I want to validate in Groovy using the following psuedo-code:

def request = testRunner.testCase.getTestStepByName( "relationship_request" )
def resp = new File('H://test_xml.xml')
def cms_ns = new groovy.xml.Namespace("namespace for cms",'cms')
def soap_ns = new groovy.xml.Namespace("http://schemas.xmlsoap.org/soap/envelope/",'soapenv')
def root = new XmlSlurper().parse(resp)


def config_item = root[soap_ns.Envelope][soap_ns.Body][cms_ns.RelatedConfigurationItemList][ConfigurationItem]

config_item.each{
    it.name.each{
        it == corresponding value in db?
        else
        die
    }
}

But I can't seem to get the syntax, logic right for trying to validate values defined (such as name) against a database response. If the config_item declaration is correct, then maybe I have a poor understanding of Groovy closures. Also, I'm not sure if XML slurper or parser is more appropiate and can't quite nail down what exactly the differences are. Hope this is an adequate description of the problem.

Answer

Vamsi Emani picture Vamsi Emani · Jul 24, 2012

XmlSlurper works on on-demand basis and is less memory intensive. When you need to access many nodes of the xml, you generally use an XmlParser. Or in case if you just want to read one or two nodes of an xml, you use Slurper.

This example should help you understand how XMLParser works.

In your case the config item declaration and namespace usage is syntactically correct but it might be ideal to use XmlParser as you might be validating many or all components of your xml. You might be getting confused regarding access of elements using closures. Here is your example without namespaces to help you understand.

   xml = '''<Envelope>
   <Body>
      <RelatedConfigurationItemList>
         <ConfigurationItem>
            <name>Top level name1</name>
            <id>Top level id1</id>
            <type>Top level type1</type>
            <relationship>IS CHILD OF</relationship>
            <ConfigurationItemList>
               <ConfigurationItem>
                  <name>data1</name>
                  <id>data1</id>
                  <type>data1</type>
                  <relationship>IS CHILD OF</relationship>
                  <ConfigurationItemList/>
               </ConfigurationItem>
               <ConfigurationItem>
                  <name>data2</name>
                  <id>data2</id>
                  <type>data2</type>
                  <relationship>IS CHILD OF</relationship>
                  <ConfigurationItemList/>
               </ConfigurationItem>
            </ConfigurationItemList>
         </ConfigurationItem>
     <ConfigurationItem>
            <name>Top level name2</name>
            <id>Top level id2</id>
            <type>Top level type2</type>
            <relationship>IS CHILD OF</relationship>
            <ConfigurationItemList>
               <ConfigurationItem>
                  <name>other data</name>
                  <id>other data</id>
                  <type>other data</type>
                  <relationship>IS CHILD OF</relationship>
                  <ConfigurationItemList/>
               </ConfigurationItem>
               <ConfigurationItem>
                  <name>other data</name>
                  <id>other data</id>
                  <type>other data</type>
                  <relationship>IS CHILD OF</relationship>
                  <ConfigurationItemList/>
               </ConfigurationItem>
            </ConfigurationItemList>
         </ConfigurationItem>
      </RelatedConfigurationItemList>
   </Body>
</Envelope>'''



def Envelope = new XmlParser().parseText(xml)

//For accessing top level top level Configuration Item
Envelope.Body.RelatedConfigurationItemList.ConfigurationItem.each{
 //Put your check conditions here.. == or any other
 assert it.name.text().contains("Top level name")
 assert it.id.text().contains("Top level id")
 assert it.type.text().contains("Top level type")
 //Inner children configuration items
 it.ConfigurationItemList.ConfigurationItem.each{
     assert it.name.text().contains("data")
     assert it.id.text().contains("data")
     assert it.type.text().contains("data")
 }       
}