XMLHolder in groovy unable to Retrieve value - groovy

I have the following xml:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<Login_v1Response>
<result xsi:nil="true"/>
<opSessionID>FjqkjEjipbhkdiin</opSessionID>
</Login_v1Response>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I have the following code in groovy which returns me null:
def groovyUtils=new com.eviware.soapui.support.GroovyUtils(context)
def holder = groovyUtils.getXmlHolder("Step1-Login#response")
log.info holder.getNodeValue("//SOAP-ENV:Envelope/SOAP-ENV:Body/Login_v1Response/opSessionID")
Please help out.
Thanks.

You are using namespaces in your script, without defining what those namespaces are. For just reading values it is generally easier to use wildcards and not worry about them.
def groovyUtils=new com.eviware.soapui.support.GroovyUtils(context)
def holder = groovyUtils.getXmlHolder("Step1-Login#Response")
log.info holder.getNodeValue("//*:opSessionID")
Or even something simpler like:
log.info context.expand('${Step1-Login#Response#//*:opSessionID}')

Related

A better XML Serializer for Python 3

I tried xml_marshaller as follows:
from xml_marshaller import xml_marshaller
class Person:
firstName = "John"
lastName = "Doe"
person1 = Person()
strXmlPerson = xml_marshaller.dumps(person1);
print(strXmlPerson)
The output from above is:
b'<marshal><object id="i2" module="__main__" class="Person"><tuple/><dictionary id="i3"><string>firstName</string><string>John</string><string>lastName</string><string>Doe</string></dictionary></object></marshal>'
which when formatted looks like this, which in my opinion is the ugliest XML possible:
b'<marshal>
<object id="i2" module="__main__" class="Person">
<tuple/>
<dictionary id="i3">
<string>firstName</string>
<string>John</string>
<string>lastName</string>
<string>Doe</string>
</dictionary>
</object>
</marshal>'
What is the b and quotes doing there? Means "binary" maybe? Is that really part of the data, or just a side effect of printing it to the console?
Is there any Python 3 library that will create something more closer to "human" like this:
<Person>
<firstname>John</firstname>
<lastname>Doe<lastname>
</Person>
I'm looking for something close to what .NET creates (see http://mylifeismymessage.net/xml-serializerdeserializer/.
Please don't tell me try JSON or YAML, that's not the question. I might want to run the file through XSLT for example.
Update 2 days later:
I like the Peter Hoffman answer here:
How can I convert XML into a Python object?
person1 = Person("John", "Doe")
#strXmlPerson = xml_marshaller.dumps(person1);
person = objectify.Element("Person")
strXmlPerson = lxml.etree.tostring(person1, pretty_print=True)
print(strXmlPerson)
gives error:
TypeError: Type 'Person' cannot be serialized.
In my scenario I might already have a class structure, and don't want to switch to they way they are doing it You can I serialize my "Person" class?
The reason the output is showing xml as a dictionary is most likely because the properties don't have a reference to the class. You should consider using self. and assigning values within a __init__ function.
class Person:
def __init__(self):
self.firstName = "John"
self.lastName = "Doe"
There are many ways to convert an object to XML. However try using the package dicttoxml. As the name suggest you'll need to convert object to a dictionary, which can be done using vars().
The full solution:
from dicttoxml import dicttoxml
class Person:
def __init__(self):
self.firstName = "John"
self.lastName = "Doe"
person = vars(Person()) # vars is pythonic way of converting to dictionary
xml = dicttoxml(person, attr_type=False, custom_root='Person') # set root node to Person
print(xml)
Output:
b'<?xml version="1.0" encoding="UTF-8" ?><Person><firstName>John</firstName><lastName>Doe</lastName></Person>'
If you want to format the XML nicely, then you can use the built in xml.dom.minidom.parseString library.
from dicttoxml import dicttoxml
from xml.dom.minidom import parseString
class Person:
def __init__(self):
self.firstName = "John"
self.lastName = "Doe"
person = vars(Person()) # vars is pythonic way of converting to dictionary
xml = dicttoxml(person, attr_type=False, custom_root='Person') # set root node to Person
print(xml)
dom = parseString(xml)
print(dom.toprettyxml())
Output:
<?xml version="1.0" ?>
<Person>
<firstName>John</firstName>
<lastName>Doe</lastName>
</Person>
Do check out the documentation https://pypi.org/project/dicttoxml/ as you can pass additional arguments to alter the output.

What is the right way to compare two strings in SoapUI with groovy script assertion?

I need to compare two strings in SoapUI. The first one is from a text file stored in my local directory, and the second one is from an XML response I get from a REST API operation. Before comparing the two strings, I use some methods on them to remove the header because they contain information like Dates and Processing Time which is sure to be different each time.
Below is what I've tried.
def xml = messageExchange.responseContentAsXml
String fileData = new File("C://Users/362784/project/outputPGB123.txt").text
String responseContent = new XmlSlurper().parseText(xml)
String fileDataFiltered = fileData.substring(fileData.indexOf("PASSED :"))
String responseContentFiltered = responseContent.substring(responseContent.indexOf("PASSED :"))
log.info(fileDataFiltered)
log.info(responseContentFiltered)
assert fileDataFiltered == responseContentFiltered
Here is the error I received
SoapUI error message
and my two identical log.info
log.info
Here's what the XML response looks like
I am new to SoapUI and I'm not sure what those two are actually comparing but I've checked the log.info of them on https://www.diffchecker.com/diff and the contents are identical. However, this assertion returns an error.
Can anyone point out what I did wrong and how do I get the result as passed?
In Java/Groovy you compare string values for equality like this:
assert fileDataFiltered.equals(responseContentFiltered)
See if that solves your problem.
The == comparator could, for example, compare object instances which could fail even if the text values are identical. See here for a more in-depth explanation.
EDIT:
Having seen your sample, it looks like the value you are comparing is inside XML character data (CDATA).
Consider the following example from here:
Some XML:
def response = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:sam="http://www.example.org/sample/">
<soapenv:Header/>
<soapenv:Body>
<sam:searchResponse>
<sam:searchResponse>
<item><id>1234</id><description><![CDATA[<item><width>123</width><height>345</height><length>098</length><isle>A34</isle></item>]]></description><price>123</price>
</item>
</sam:searchResponse>
</sam:searchResponse>
</soapenv:Body>
</soapenv:Envelope>
'''
Then access the CDATA node with XmlSlurper:
def Envelope = new XmlSlurper().parseText(response)
def cdata = Envelope.Body.searchResponse.searchResponse.item.description
log.info cdata
log.info cdata.getClass()
assert cdata instanceof groovy.util.slurpersupport.NodeChildren
As you can see, the value returned is of object NodeChildren. You can convert it to a string with:
log.info cdata.toString()
log.info cdata.toString().getClass()
So let's do a comparison (as per cfrick's comment, you can use == or .equals())
def expectedCdata = '<item><width>123</width><height>345</height>length>098</length><isle>A34</isle></item>'
if (cdata.toString().equals(expectedCdata)) { log.info 'Equal' }
else {log.info 'Different'}
It still fails ???
Well, that is because of a residual newline that isn't obvious from printing with log.info, if you remove whitespace it works in this case:
if (cdata.toString().replaceAll("\\s","").equals(expectedCdata)) { log.info 'Equal' }
else {log.info 'Different'}
As you can see, there are many levels of possible failure. You have to work through it.

Insert child node in XML

need help with simple inserting node after specific one in XML using Groovy. Searching through the existing posts came to that, closer but not enough
import groovy.xml.*
def x='''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns7:setPlayerInfoRequest xmlns:ns7="http://www.playtech.com/services/player-management">
<ns7:behaviourType>Create</ns7:behaviourType>
<ns7:playerDataMap>
<ns7:currency>${p_currency}</ns7:currency>
</ns7:playerDataMap>
</ns7:setPlayerInfoRequest>'''
def n = '''<ns7:custom01>custom01</ns7:custom01>'''
def xml=new XmlParser().parseText(x)
def node = new XmlSlurper(false,false).parseText(n)
def nodes = xml.'**'.findAll{ it.name().localPart == 'currency' }
nodes.each{it.parent().appendNode(node)}
XmlUtil.serialize(xml).toString()
Result
<?xml version="1.0" encoding="UTF-8"?><ns7:setPlayerInfoRequest xmlns:ns7="http://www.playtech.com/services/player-management">
<ns7:behaviourType>Create</ns7:behaviourType>
<ns7:playerDataMap>
<ns7:currency>${p_currency}</ns7:currency>
<custom01/>
</ns7:playerDataMap>
</ns7:setPlayerInfoRequest>
Expected result is to have <ns7:custom01>custom01</ns7:custom01> inserted under parent playerDataMap
You use XmlSlurper to create node from n. But you should use XmlParser as you already do at the line above
You should also use it.parent().append(node) at the line with nodes.each { it.parent().appendNode(node) }
After applying these two changes, it will work as you expect

how to retrieve text from an xml

I want to try an retrieve the name of a hotel (in this example the hotel is called 'Test Hotel'), but I am unsure how to do it because I believe to get a #node it's using # but how do I retrieve a text?
Below is the xml:
<xxx xmlns:soap="xxx" xmlns:xsi="xxx" xmlns:xsd="xxx">
<xxx>
<xxxxmlns="xxx">
<AvailabilityRS Url="xxx" IntCode="xxx">
<Results>
<HotelResult Code="xxx"DestinationZone="xxx">
<HotelInfo>
<Name>Test Hotel</Name>
Below is the script:
def response = testRunner.testCase.getTestStepByName("xxx").getProperty("Response").getValue()
def parsedxml = new XmlSlurper().parseText(response)
def hotelName = parsedxml.'soap:Body'.HotelAvailResponse[0].xxx[0].Results[0].xxxx[0].xxx[0].Name[0].toString()
Instead of using toString(), you should be able to just use text()
def hotelName = parsedxml.Body
.HotelAvailResponse
.AvailabilityRS
.Results
.HotelResult
.HotelInfo
.Name.text()

not able to extract attribute from xml in groovy script

I am trying to automate using groovy script. Here is my script. I am not able to mention namspace.
<ns2:contactPref xmlns="namespace 1" xmlns:ns2="name space 2">
<ns2:Information>
<value>Pass</value>
</ns2:Information>
<ns2:contactPreference>
<ns2:contactPointRel>
<contactPoint xs:type="Tele" xmlns:xs="namespace 3">
<cat>mob</cat>
<med>Int</med>
</contactPoint>
</ns2:contactPointRel>
</ns2:contactPreference>
</ns2:contactPref>
Now I want to fetch attribute at contactPoint tag
for this I have tried like this
groovyUtils=new com.eviware.soapui.support.Groovyutills(context)
def xPath=XPathFactory.newInstance().newXPath()
def type=context.expand('${GetResponse#Response#//*:contactPoint/#xs:type}')
log.info type
tried this
def type=context.expand('${GetResponse#Response#//*:contactPoint/#type}')
and I also tried this
def resp=groovyUtils.getXmlHolder("GetResponse#Response")
def type1=(String)xPath.evaluate('//:contactpoint/#xs:type',resp,xPathConstants.STRING)
but no help. please some one tell me how to do this??
try using this it should work
#{namespace 3}type
if you see xs:type="Tele" xmlns:xs="namespace 3" in contactPoint then xs which has value namespace 3 and {type} is Tele
Edited - You could use something like this - with xmlString as XML
def xml = new XmlSlurper().parseText(xmlString)
println
xml.contactPreference.contactPointRel.contactPoint."#{namespace
3}type"

Resources