Find an element in XML using XML Slurper - groovy

"I have a code that is working as expected but now I have to find the element in different format. Example is below
<car-load>
<car-model model="i10">
<model-year>
<year.make>
<name>corolla</name>
</year.make>
</model-year>
</car-model>
</car-load>
I have to find the value of "corolla" from this XML. Please reply.

You can run this in the Groovy console
def text = '''
<car-load>
<car-model model="i10">
<model-year>
<year.make>
<name>corolla</name>
</year.make>
</model-year>
</car-model>
</car-load>'''
def records = new XmlSlurper().parseText(text)
// a quick and dirty solution
assert 'corolla' == records.toString()
// a more verbose, but more robust solution that specifies the complete path
// to the node of interest
assert 'corolla' == records.'car-model'.'model-year'.'year.make'.name.text()

Related

How to get data from xml file using groovy?

Following groovy script is not working as expected.
def xml="<Collection><CustomerQuote><ID>99988877766</ID><TypeCode>2059</TypeCode><ApprovalStatusCode>4</ApprovalStatusCode></CustomerQuote><CustomerQuote><ID>99988877755</ID><TypeCode>2059</TypeCode><ApprovalStatusCode>4</ApprovalStatusCode></CustomerQuote></Collection>"
def completeXml= new XmlSlurper().parseText(xml);
def IDs = completeXml.Collection.CustomerQuote.findAll{node-> node.name() == 'ID' }*.text();
I am trying to copy all the ID value in xml in the IDs
Output
IDs[]
Expected Output
IDs[99988877766,99988877755]
I am not sure what i am doing wrong here.
Can anyone guide.
Thank you
Regards
Prat
The root node has to be omitted when using XmlSlurper, and you don't need to use findAll for this.
def xml="<Collection><CustomerQuote><ID>99988877766</ID><TypeCode>2059</TypeCode><ApprovalStatusCode>4</ApprovalStatusCode></CustomerQuote><CustomerQuote><ID>99988877755</ID><TypeCode>2059</TypeCode><ApprovalStatusCode>4</ApprovalStatusCode></CustomerQuote></Collection>"
def completeXml= new XmlSlurper().parseText(xml);
def IDs = completeXml.CustomerQuote.ID*.text();
Will output:
[
"99988877766",
"99988877755"
]
Try it in the Groovy Web Console

Cannot replace string text in Groovy script

I am trying to replace a test in pom.xml using a groovy script. These are my two approaches. The text should be replaced is {env.AM_$environment.toUpperCase()_SERVER_CREDS_USR}
Approach one
File mainPomXml = new File(rootDir,'/pom.xml')
mainPomXml.text.replace('{env.AM_$environment.toUpperCase()_SERVER_CREDS_USR}','${env.AM_$environment.toUpperCase()_SERVER_CREDS_USR}');
Approach two
def mainPomXml = new File(rootDir,'/pom.xml')
def mainPom = mainPomXml.text.replace('{env.AM_$environment.toUpperCase()_SERVER_CREDS_USR}','${env.AM_$environment.toUpperCase()_SERVER_CREDS_USR}');
mainPomXml.write(mainPom);
But none of these approaches work. That means both executes but the test is not get replaced. How to fix this issue?
Change the mainPom part as below.
def mainPomXml = new File(rootDir, '/pom.xml')
def mainPom = mainPomXml.text.replace('AM_SERVER_CREDS_USR', '${env.AM_'+ env.toUpperCase() +'_SERVER_CREDS_USR}')
mainPomXml.write(mainPom)

using an assert with a contains in groovy

I am trying to run an assert with contains but am encountering an issue. I have written the code below using groovy in SOAPUI Pro
def pieceid = context.expand( '${OneDX#ResponseAsXml#//Results[1]/ResultSet[1]/Row[1]/PIECEID[1]}' )
def TrackingNumber = context.expand( '${OneDX#ResponseAsXml#//Results[1]/ResultSet[1]/Row[1]/TRACKINGNUMBER[1]}' )
assert {!TrackingNumber.contains(Pieceid)}
The tracking number is 907598985733 and Pieceid is 1820480....therefore the Pieceid is not in the tracking number. However when I run the script it passes. do you know what i'm doing wrong
Looks like a trivial issue in this case.
Changes:
replace ResponseAsXml with Response
removed { .. } in the assert statement, and introduced ( .. )
looks, you used incorrect variable i.e., Pieceid which is also not available - incorrect case.
Here is you go with the changed groovy script snippet:
def pieceid = context.expand( '${OneDX#Response#//Results[1]/ResultSet[1]/Row[1]/PIECEID[1]}' )
def trackingNumber = context.expand( '${OneDX#Response#//Results[1]/ResultSet[1]/Row[1]/TRACKINGNUMBER[1]}' )
log.info "Tracking number is $trackingNumber and Piece Id is $pieceid"
assert (!trackingNumber.contains(pieceid)), "Tracking number contains Pieceid"
You should be able to see the data of both variables in the log as well.
I would also like to recommend you not to use indexes in the xpath. Understand that might be auto generated by the tool. The reason being that if nodes come in different order, that will break your existing assertions for later test executions.

Unexpected results with groovy.util.slurpersupport.NodeChild.appendNode() (Groovy 2.2.1)

I think what I am trying to do is simple: Add child nodes dynamically to a node (without even knowing the name of the node to be added - developing some framework) using XmlSlurper.
For ease of explaining, something like this:
def colorsNode = new XmlSlurper().parseText("""
<colors>
<color>red</color>
<color>green</color>
</colors>""")
NodeChild blueNode = new XmlSlurper().parseText("<color>blue</color>") // just for illustration. The actual contents are all dynamic
colorsNode.appendNode(blueNode) // In real life, I need to be be able to take in any node and append to a given node as child.
I was expecting the resulting node to be the same as slurping the following:
“””
<colors>
<color>red</color>
<color>green</color>
<color>blue</color>
</colors>"""
However the result of appending is:
colorsNode
.node
.children => LinkedList[Node('red') -> Node('green') -> <b>NodeChild</b>(.node='blue')]
In other words, what gets appended to the LinkedList is the NodeChild that wraps the new node, not the node itself.
Not surprising, looking at the source code for NodeChild.java:
protected void appendNode(final Object newValue) {
this.node.appendNode(newValue, this);
}
Well, I would gladly modify my code into:
colorsNode.appendNode(blueNode<b>.node</b>)
Unfortunately NodeChild.node is private :(, don't know why! What would be a decent way of achieving what I am trying? I couldn’t see any solutions online.
I was able to complete my prototyping work by tweaking Groovy source and exposing NodeChild.node, but now need to find a proper solution.
Any help would be appreciated.
Thanks,
Aby Mathew
It would be easier if you use XmlParser:
#Grab('xmlunit:xmlunit:1.1')
import org.custommonkey.xmlunit.Diff
import org.custommonkey.xmlunit.XMLUnit
def xml = """
<colors>
<color>red</color>
<color>green</color>
</colors>
"""
def expectedResult = """
<colors>
<color>red</color>
<color>green</color>
<color>blue</color>
</colors>
"""
def root = new XmlParser().parseText(xml)
root.appendNode("color", "blue")
def writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(root)
def result = writer.toString()
XMLUnit.setIgnoreWhitespace(true)
def xmlDiff = new Diff(result, expectedResult)
assert xmlDiff.identical()

groovy returning different node count

I am trying to get the count of result nodes in soapUI using groovy and the below code gave me the correct count
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def holder = groovyUtils.getXmlHolder("StepName#ResponseAsXml")
def cnt = holder["count(//Results/ResultSet/Row)"]
but when i tried the below i got a count of 1. How are the two different?
def cnt = holder["count('//Results/ResultSet/Row')"]
Though I've never used SoapUI, in the second one, you are passing a String (wrapped in '...') to count.
The first passes a path which I guess gets evaluated into a list of nodes.
All the examples I can find do not wrap the path in a String, so my guess is the first example is the way to do it ;-)
EDIT
Refer Tips and Tricks for most of the SoapUI and Groovy related questions. And count in xpath.

Resources