1

I am using XMLParser for the first time to retrieve a response from an xml:

Below is the code:

import groovy.xml.XmlUtil
def response = testRunner.testCase.getTestStepByName("GetTestStep").getProperty("Response").getValue();
def root = new XmlParser().parseText( response )

log.info root

The log.info of root displays the following xml response:

:{http://schemas.xmlsoap.org/soap/envelope/}Envelope[attributes={}; value=[{http://schemas.xmlsoap.org/soap/envelope/}Body[attributes={}; value=[{http://www.xxx}TestHotelResponse[attributes={}; value=[{http://www.xxx}AvailabilityRS[attributes={Url=http://xxx.xxxxxxxx.com }; value=[{http://www.xxx.es/xxxxxx/2007/}

Now I want to be able to retrieve the attribute for AvailabilityRS, However I keep getting a blank [] when I try to retrieve it via this method:

root.AvailabilityRS*.value()*.each { k, v ->
  log.info ("$k.localPart = $v")
}

RAW XML:

<soap:Envelope xmlns:soap="http://schemas.xxx">
   <soap:Body>
      <xxx xmlns="http://www.xxx7/">
         <xxx Url="http://xxx.xxxxxx.com">

How can I retrieve the Url within the attribute for AvailabilityRS?

Thanks,

BruceyBandit
  • 3,978
  • 19
  • 72
  • 144
  • See [here](http://stackoverflow.com/questions/24436173/get-value-of-an-xml-attribute-with-groovy-gpath). Otherwise, can you show the raw xml response please? – Rao Feb 03 '17 at 12:06
  • I have included the RAW XML. I tried the answer you directed me to but it still displays null – BruceyBandit Feb 03 '17 at 12:58
  • Possible duplicate of [Get value of an XML attribute with Groovy (gpath)](http://stackoverflow.com/questions/24436173/get-value-of-an-xml-attribute-with-groovy-gpath) – Gregor Petrin Feb 03 '17 at 13:23
  • @GregorPetrin I have been looking at this answer but it isn't helping me with this issue because of the slight difference in tags and levels – BruceyBandit Feb 03 '17 at 13:42

3 Answers3

3

The following works:

def str='''\
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <HotelAvailResponse xmlns="http://www.xxx/">
       <AvailabilityRS Url="http://xxx.xxxxxx.com" TimeStamp="2017-02-03T11:14:30.5744079+00:00" IntCode="xxx" />
    </HotelAvailResponse>
  </soap:Body>
</soap:Envelope>         
'''
def xml = new XmlParser().parseText(str)
def url = xml.'soap:Body'.HotelAvailResponse[0].AvailabilityRS[0].@Url
println url

note the at @ character prefix for attribute values. If the attribute is hyphenated or otherwise not a valid groovy identifier, you can use a quoted node.'@attribute-name' instead.

Note that the expression xml.'soap:Body'.HotelAvailResponse returns a list of nodes which is why I added a [0] to both expressions. The sentiment is that there could be any number of HotelAvailResponse nodes and groovy therefore returns a list even if there is just one node. Running the above without the [0] indexing will return a list with the url as an element.

Note also that the result of an attribute access via the @ character is a string and not an xml node.

BruceyBandit
  • 3,978
  • 19
  • 72
  • 144
Matias Bjarland
  • 4,124
  • 1
  • 13
  • 21
2

Change your script to below, to retrieve the Url:
Note that @ needs to be used to retrieve attributes.

def response = testRunner.testCase.getTestStepByName("GetHotelAvailability").getProperty("Response").getValue()
def parsedXml = new XmlSlurper().parseText(xml)
def url = parsedXml.'**'.find{ it.name() == 'AvailabilityRS' }.@Url.text()
log.info "Url is :${url}"
Rao
  • 20,781
  • 11
  • 57
  • 77
1

Some experimentation based on the two answers provided so far.

These all provide the same result: [http://stagejuniperws.xxxxxx.com]

// if you know the exact path
println root.'soap:Body'.HotelAvailResponse[0].AvailabilityRS*.@Url

// verbose code
println root.depthFirst().inject([]) {urls, node ->
    if (node.name().localPart == "AvailabilityRS") {
        urls << node.@Url
    }
    urls
}

// more concise
println root.depthFirst().findAll {it.name().localPart == "AvailabilityRS"}*.@Url

// more concise, use the GPath symbol '**'
println root.'**'.findAll {it.name().localPart == "AvailabilityRS"}*.@Url

// more concise, more GPath
println root.'**'.AvailabilityRS*.@Url
glenn jackman
  • 238,783
  • 38
  • 220
  • 352