Forum Discussion

Jasper175's avatar
Jasper175
Frequent Contributor
13 years ago

xmlParser

Hi - I'm working with eviware support, but I wanted to open this up to the forum to see if anyone came up with something that works.

I have an XML Response where all the data has the same tag structure, but the values will be different, and multiples in most cases.
Example:
<m:GetRatedEventListResponse xmlns:m="http://*****">
<m:ratedEvents
<m:eventAttributes>
<m:name>Calling Number</m:name>
<m:value>98989897999</m:value>
</m:eventAttributes>
<m:eventAttributes>
<m:name>Additional charge</m:name>
<m:value>0</m:value>
</m:eventAttributes>
<m:eventAttributes>
<m:name>Called number</m:name>
<m:value>12017726873</m:value>
</m:eventAttributes>
...

What I need to do is parse the output so I can pull only the 'Calling Number' and it's value.

The parser part of the code below is logging everything in the m:name -

def records = new XmlParser().parseText(response)
for (record in records)
for (rec in record['m:name'])
log.info rec.text()
...

However I need to find where m:name == 'Calling Number' and returns it's m:value

8 Replies

  • SmartBear_Suppo's avatar
    SmartBear_Suppo
    SmartBear Alumni (Retired)
    Hi!

    hmm.. have you tried an xpath expression in the style of

    //m:eventAttributes[m:name='Called Number']/m:value

    ?

    regards,

    /Ole
    SmartBear Sweden
  • Jasper175's avatar
    Jasper175
    Frequent Contributor
    Hey Ole,
    Where would I use the xpath expression? Looks like what I need.
  • Jasper175's avatar
    Jasper175
    Frequent Contributor
    As always - You're awesome!
    I got it to pull at least the first value I'm looking for. To take this a little further, how can I pull all the values that relate to m:value for "Calling Number"?


    // create groovyUtils
    def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
    //def response = context.expand( '${getRatedEventList-dateRange#Response#declare namespace m=\'http://vonage.com/services/servicelayer\'; //m:GetRatedEventListResponse[1]/m:ratedEvents[1]}' )
    def response = context.expand( '${getRatedEventList-dateRange#Response#declare namespace m=\'http://vonage.com/services/servicelayer\'; //m:GetRatedEventListResponse[1]/m:ratedEvents[1]/m:eventAttributes[m:name="Calling Number"]/m:value[1]}' )
    log.info response
    ...

    The above pulls one of the numbers.
    Vladimir was helping me with using xmlParser which using the portion of your code with his does the same thing.


    // create groovyUtils
    def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
    //def response = context.expand( '${getRatedEventList-dateRange#Response#declare namespace m=\'http://vonage.com/services/servicelayer\'; //m:GetRatedEventListResponse[1]/m:ratedEvents[1]}' )
    def response = context.expand( '${getRatedEventList-dateRange#Response#declare namespace m=\'http://vonage.com/services/servicelayer\'; //m:GetRatedEventListResponse[1]/m:ratedEvents[1]/m:eventAttributes[m:name="Calling Number"]}' )

    // print
    def records = new XmlParser().parseText(response)
    for (record in records['m:value'])
    log.info record.text()

    This also pulls only one of the phone numbers
  • SmartBear_Suppo's avatar
    SmartBear_Suppo
    SmartBear Alumni (Retired)
    Hi!

    How about this?

    def records = new XmlParser().parseText( response )

    valuesOfCallingNumbers = []

    records.each { eventAttributes ->
    if ( eventAttributes['m:name'][0].text() == "Calling Number" )
    valuesOfCallingNumbers.add( eventAttributes['m:value'][0].text() )
    }


    You could probably also use XQuery. XPath cannot be used to fetch multiple elements at once.

    Hope this helps

    Henrik
    SmartBear Stockholm
  • Jasper175's avatar
    Jasper175
    Frequent Contributor
    even defining ( response ) I'm getting error: java.lang.NullPointerException: Cannot invoke method text() on null object
    I'm not sure why it can't resolve the path - unless the code below doesn't recognize the response context while performing the search?

    // create groovyUtils 
    def response = context.expand( '${getRatedEventList-dateRange#Response#declare namespace m=\'http://vonage.com/services/sl\'; //m:GetRatedEventListResponse[1]/m:ratedEvents[1]}' )
    def records = new XmlParser().parseText( response )

    valuesOfCallingNumbers = []

    records.each { eventAttributes ->
    if ( eventAttributes['m:name'][0].text() == "Calling Number" )
    valuesOfCallingNumbers.add( eventAttributes['m:value'][0].text() )
    }
  • SmartBear_Suppo's avatar
    SmartBear_Suppo
    SmartBear Alumni (Retired)
    Hi,

    let's back up a bit here - you say you want to extract all Calling Number values in the document? Maybe you should use GroovyUtils/XmlHolder instead;

    def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
    def holder = groovyUtils.getXmlHolder( "getRatedEventList-dateRange#Response" )

    holder.namespaces( "m", "http://vonage.com/services/sl" )

    for( a in holder.getNodeValues( "//m:eventAttributes[m:name='Calling Number']/m:value" ))
    log.info "Got number [$a]"

    Does that work any better!? If not, can you please attach the entire response you are working with so we can work from that as well.. thanks..

    /Ole
    SmartBear Stockholm
  • Jasper175's avatar
    Jasper175
    Frequent Contributor
    That particular code didn't work.

    groovy.lang.MissingMethodException: No signature of method: com.eviware.soapui.support.XmlHolder.namespaces() is applicable for argument types: (java.lang.String, java.lang.String) values: [m, http://cleveland.vonage.com/services/servicelayer] Possible solutions: getNamespaces()


    Not sure how the script knows where the API "is" - I thought we need a context pointer to the api response?

    Attached is the response for the api.

    Thank you!
    Rob