Forum Discussion

vijaydi's avatar
vijaydi
Contributor
12 years ago

capture values under similiar XPath in an array with groovy

In soapUI, using groovy, I have the following piece of code to capture the value of a XPath. There are 23 of these values under similiar XPath in an array like structure (ns5:search-result[1], ns5:search-result[2]...and so on ns5:search-result[23])

  def matchindicator = context.expand( '${IDM_Modified#Response#declare namespace ns5=\'http://vedaxml.com/vxml2/idmatrix-v2-0.xsd\'; //ns5:response[1]/ns5:search-results[1]/ns5:search-result[1]/@match-indicator}' )

def matchindicator2 = context.expand( '${IDM_Modified#Response#declare namespace ns5=\'http://vedaxml.com/vxml2/idmatrix-v2-0.xsd\'; //ns5:response[1]/ns5:search-results[1]/ns5:search-result[2]/@match-indicator}' )



I wanted to capture all the values in an arrray and datasink them to an excel. I tried to give ns5:search-result[all] (see below linwe of code), and defined matchindicator as an array but did not work.

    matchindicator = context.expand( '${IDM_Modified#Response#declare namespace ns5=\'http://vedaxml.com/vxml2/idmatrix-v2-0.xsd\'; //ns5:response[1]/ns5:search-results[1]/ns5:search-result[all]/@match-indicator}' )**strong text**


Would like to get your thoughts as to how best we can capture these values in an array.

Thank you

9 Replies

  • jmistrik's avatar
    jmistrik
    Occasional Contributor
    Dont know if understand the paths correctly from desc, what you wanna do.. but try (if you like it):

    def contract = context.expand('${IDM_Modified#ResponseAsXml}')
    Node xml = new XmlParser(false, false).parseText(contract)

    java.util.List<String> list = new java.util.ArrayList<String>();
    xml."ns5:response"[0]."ns5:search-results"[0]."ns5:search-result".each{
    list.add(it.@match-indicator)
    }


    J)
  • Much appreciate your response jmistrik.

    I tried the code suggested, and when trying to print the array list I get null as the outcome. Please advice. I have attached the resposne hereiwth, which we are trying to parse.

    def contract = context.expand('${IDM_Modified#Response}')
    Node xml = new XmlParser(false, false).parseText(contract)

    log.info xml

    java.util.List<String> list = new java.util.ArrayList<String>();
    xml."ns5:response[0]"."ns5:search-results[0]"."ns5:search-result".each
    {
    list.add(it.@match-indicator)

    }

    log.info list [0]
  • M_McDonald's avatar
    M_McDonald
    Super Contributor
    How's this?

    def gu = new com.eviware.soapui.support.GroovyUtils( context )
    def contract = context.expand('${IDM_Modified#Response}')
    def holder = gu.getXmlHolder(contract)
    def indicators = []
    holder.getDomNodes('//ns5:search-result').each {
    indicators << it.getAttribute('match-indicator')
    }
    log.info indicators
    return indicators
  • Thank you tons McDonald. It worked for me :-)

    Below is the code. Could you please look into it and provide your suggestions on if it could be written better. (I have also captured attributes searchname and matchscore which are also under the same xpath in different array variable----Question - is thr a way that we could capture it in a multi dimentional array instead of different arrays)

    Also, could you suggest how to get the count of the array list.


    def holder = grUtils.getXmlHolder("IDM_Modified#Response")

    def indicators = []
    holder.getDomNodes('//ns5:search-result').each {
    indicators << it.getAttribute('match-indicator')
    }

    def searchname = []
    holder.getDomNodes('//ns5:search-result').each {
    searchname << it.getAttribute('search-name')
    }

    def matchscore = []
    holder.getDomNodes('//ns5:search-result').each {
    matchscore << it.getAttribute('match-score')
    }

    for (i in 0..22)
    {
    def output = "SR" + i
    def searchresult = indicators[i] + "_" + searchname[i] + "_" + matchscore [i]
    testRunner.testCase.getTestStepByName("DataSink").setPropertyValue(output, searchresult)
    }
  • M_McDonald's avatar
    M_McDonald
    Super Contributor
    Certainly you can get the values in a multidimensional array:

    def indicators = []
    holder.getDomNodes('//ns5:search-result').each {
    def attrs = []
    attrs << it.getAttribute('match-indicator') << it.getAttribute('search-name') << it.getAttribute('match-score')
    indicators << attrs
    }


    But if you are going to concatenate them anyway why not just do so right away?

    def indicators = []
    holder.getDomNodes('//ns5:search-result').each {
    indicators << it.getAttribute('match-indicator') + "_" + it.getAttribute('search-name') + "_" + it.getAttribute('match-score')
    }


    It looks to me like you will get each result in a separate column in your worksheet - is that what you intended? If you actually wanted each result in a separate row I think the whole thing could be done with a DataSource-DataSink-DataSource Loop setup. No coding necessary.
  • Thank you tons McDonald.

    Much appreciate your response. Sure, I totally agree. But the requirement is to get them in seperate columns as you have mentioned.

    Thank again :-)
  • Hi McDonald,

    The below code for capturing values under similiar XPath in an array works well. In the case below, the value to capture are in attributes.

    def indicators = []
    holder.getDomNodes('//ns5:search-result').each {
    def attrs = []
    attrs << it.getAttribute('match-indicator') << it.getAttribute('search-name') << it.getAttribute('match-score')
    indicators << attrs
    }


    However, the same when trying to capture the values in a node, ends ups with the follwing exception (groovy.lang.MissingMethodException: No signature of method: org.apache.xmlbeans.impl.store.Xobj$ElementXobj.getNodeValue() is applicable for argument types: (java.lang.String) values: [thf:code])

    The below code is what I am using to capture the node value. Please help.

    def indicators = []
    holder.getDomNodes('//cth:companyTradingHistoryResponse[1]/cth:companyTradingHistoryReport[1]/thf:faults[1]/thf:fault').each {
    indicators << it.getNodeValue('thf:code') + "_" + it.getNodeValue('thf:faultString')
    }


    The part of the reposne file that I am trying to capture.

    <thf:faults>
    <thf:fault>
    <thf:code>033</thf:code>
    <thf:faultString>PPSR Unavailable</thf:faultString>
    </thf:fault>
    <thf:fault>
    <thf:code>031</thf:code>
    <thf:faultString>ATO Unavailable</thf:faultString>
    </thf:fault>

    </thf:faults>
    </cth:companyTradingHistoryReport>
    </cth:companyTradingHistoryResponse>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
  • M_McDonald's avatar
    M_McDonald
    Super Contributor
    [tt:1zk7u0pu]holder.getDomNodes[/tt:1zk7u0pu] returns an array of DomNodes, not another holder object so you can't use XPath on it. An alternative would be to get the count of fault nodes and modify the XPath to access values for each one.

    def indicators = []
    def faultsPath = "//cth:companyTradingHistoryResponse[1]/cth:companyTradingHistoryReport[1]/thf:faults[1]" // convenience
    for (n in 1..holder.getDomNodes(faultsPath + "/thf:fault").size()) {
    indicators << holder.getNodeValue(faultsPath + "/thf:fault[$n]/thf:code/text()") + "_" + holder.getNodeValue(faultsPath + "/thf:fault[$n]/thf:faultString/text()")
    }
  • Thank you tons McDonald.

    Much appreciate your help. Will give it a try and give you a shout if I have any issues :-)

    Thanks again.