I got this problem – took me like 8 hours to solve, so that qualifies it as a problem. In SoapUI I have a call that responds with something like <night ratePlanID="A" stayDate="B" availCodeID="C" regularPrice="D" totalPrice="E" />
. There are multiple of these, the number can change depending on the inputs to this call. I need to create the same number of elements for my next call, and change the attributes around a bit to make it look something like: <hot:night ratePlanID="A" resDate="B" quotedPrice="E" />
. Luckily Groovy abstracts away the need for counting things, and I naively thought that manipulating the XML would be a breeze too…
version 1.0
The first useful hints that I got were from the SoapUI tips & tricks. After that getting at the individual attributes is done with attributes.getNamedItem()
. After that I just brute-forced my way through it.
// create groovyUtils and XmlHolder for response of my "find room" call def grUtils = new com.eviware.soapui.support.GroovyUtils(context) def holder = grUtils.getXmlHolder("find room#Response") // place for my final result def entireXmlFragment = new StringBuilder() // get only the nodes that I am interested in, and iterate over all of them holder.getDomNodes("//*:hotel/*:roomType/*:guestCount[1]/*:night").each { // create a new node one piece of string at a time def oneXmlFragment = new StringBuilder() oneXmlFragment << "<hot:night ratePlanID='" oneXmlFragment << it.attributes.getNamedItem("ratePlanID").getNodeValue() oneXmlFragment << "' resDate='" oneXmlFragment << it.attributes.getNamedItem("stayDate").getNodeValue() oneXmlFragment << "' quotedPrice='" oneXmlFragment << it.attributes.getNamedItem("totalPrice").getNodeValue() oneXmlFragment << "' />" oneXmlFragment << System.getProperty("line.separator") // add the new node to my final result entireXmlFragment << oneXmlFragment } // push the final result into a property testRunner.testCase.setPropertyValue("entireXmlFragment", entireXmlFragment.toString())
Now in my next call I just insert ${#TestCase#entireXmlFragment}
where I want this XML fragment to be placed. Works, but seems kinda neanderthal.
version 2.0
There has to be a way to manipulate my XmlFragments as XML objects, and there has to be a way to push them directly into the next call? The grUtils.getXmlHolder()
led me to holder.getDomNodes()
, which gives you back a org.w3c.dom.Node
.
// create groovyUtils and XmlHolder for response of my "find room" call def grUtils = new com.eviware.soapui.support.GroovyUtils(context) def responseHolder = grUtils.getXmlHolder("find room#Response") // create XmlHolder for request of my "bookHotelRes" call def requestHolder = grUtils.getXmlHolder("bookHotelRes#Request") // find the Node that I am interested in def requestNode = requestHolder.getDomNode("//*:bookHotelResInput/*:room") // the Document object is used to create new nodes def requestDoc = requestNode.getOwnerDocument() // get only the nodes that I am interested in, and iterate over all of them responseHolder.getDomNodes("//*:hotel/*:roomType/*:guestCount[1]/*:night").each { // create a new Element in the Document def oneElement = requestDoc.createElementNS(requestNode.getNamespaceURI(), "night") // define all the attributes oneElement.setAttribute("ratePlanID", it.attributes.getNamedItem("ratePlanID").getNodeValue()) oneElement.setAttribute("resDate", it.attributes.getNamedItem("stayDate").getNodeValue()) oneElement.setAttribute("quotedPrice", it.attributes.getNamedItem("totalPrice").getNodeValue()) // insert the Element requestNode.insertBefore(oneElement, requestNode.getFirstChild()) } // write the Document out to the request requestHolder.updateProperty(true)
The above will write out the next Element as the first child. Also, and perhaps more importantly, the above will write it out into your request – if you run your test twice in a row, you will end up with both results (old and new) in your request. This is undesirable, but easy to take care of.
// cleanup from a "previous" run requestHolder.getDomNodes("//*:bookHotelResInput/*:room/*:night").each { requestNode.removeChild(it) }
HTH 🙂
set value?
Comment by Anonymous — October 14, 2015 @ 1:42 pm |
Hi Siking,
I have a problem with groovy with the same situation as you point above. Can I mail you about it?
ps: I can not find your mail in this site.
Dennis
Comment by Orrin — September 23, 2015 @ 4:31 am |
Hi Siking,
Ik get this error: java.lang.NullPointerException: Cannot invoke method getNodeValue() on null object java.lang.NullPointerException: Cannot invoke method getNodeValue() on null object error at line: 30
at this piece of code:
responseHolder.getDomNodes(“//*:hotel/*:roomType/*:guestCount[1]/*:night”).each {
What might be the problem
Comment by Orrin — September 11, 2015 @ 7:25 am |
Sounds like you are trying to get value of a node that does not exist. From that piece of code it is impossible to tell.
Comment by SiKing — September 11, 2015 @ 7:31 am |
[…] dynamically emanate elements in a SoapUI ask | SiKing […]
Pingback by SoapUI – Automaticaly add custom SOAP headers to outgoing request | Zale Answers — December 11, 2014 @ 4:37 pm |
When I try to use the same code as mentioned above , still getting the error as Getting the error:
Groovy.lang.MissingMethodException: No signature of method: [Lorg.w3c.dom.Node;.getOwnerDocument() is applicable for argument types: () values: []
Checked the jar is there in the lib directory, moved it to ext folder also, still no luck.
what should i do to resolve the same..?
Comment by Anand — September 27, 2014 @ 3:21 am |
This does not involve any external jars. All jars should be part of the SoapUI installation.
Comment by SiKing — September 29, 2014 @ 7:46 am |
Getting the error:
Groovy.lang.MissingMethodException: No signature of method: [Lorg.w3c.dom.Node;.getOwnerDocument() is applicable for argument types: () values: [] error at line: 33
I am new to SOAPUI and groovy. Could you please help me with this error?
Comment by Kanchan — June 18, 2012 @ 1:38 am |
I would need to see much more of your code to be able to perhaps take a guess. Perhaps one of the support fora would be a better medium for this?
Comment by siking — June 18, 2012 @ 7:01 am |
This is the code:
Pretty much the same thing as you have written
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def holder = groovyUtils.getXmlHolder(“matchRanking – Request 1#Request”)
def node = holder.getDomNodes(“//ran:matchRanking”)
def nodeCount = node.length
log.info “nodeCount = ” + nodeCount
def requestDoc = node.getOwnerDocument()
def oneElement = requestDoc.createElementNS(node.getNamespaceURI(), “candidatePropsList”)
def childNode = holder.getDomNodes(“//candidatePropsList”)
def childNodeCount = childNode.length
log.info “childNodeCount = ” + childNodeCount
Comment by Kanchan — June 18, 2012 @ 10:18 pm |
I do not see anything immediately wrong in the code. However, I do not see “line 33” either.
Comment by siking — June 19, 2012 @ 8:45 am |
Ignore the line number.. I made some changes, so the line number has changed.
Basically the error is for getOwnerDocument().
Do I need to include some files for this to work? since it says “MissingMethodException”
Comment by Kan — June 19, 2012 @ 7:35 pm
The getOwnerDocument() method is declared in $SOAPUI_HOME/lib/xml-apis-2.9.1.jar. I do not have any special imports for my code.
Comment by siking — June 20, 2012 @ 1:39 pm
jQuery & Sizzle have similar regex expressions.
Comment by Karaoke_King — April 26, 2012 @ 8:36 pm |
Thanx. However, there is not a single regular expression in the above post. Perhaps you mean XPath?
Comment by siking — April 27, 2012 @ 7:08 am |
Yes, exactly.
Comment by Anonymous — July 2, 2012 @ 3:30 pm |
Copying a node from one document to another, with no modifications:
Comment by siking — April 11, 2012 @ 9:50 am |
Adding text is a child node itself, and it is done with something like:
Comment by siking — January 9, 2012 @ 10:24 am |