I am trying to retrieve a number of flightids from an xml and place them in an array but I keep getting no data displayed. It doesn't seem to find 'flights' but I am not sure why, is there anything wrong with the code below?
import groovy.xml.XmlUtil
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def response = context.expand( '${SOAP Request#Response}' )
def parsedxml = new XmlSlurper().parseText(response)
def tests= parsedxml.'**'.findAll { it.name() == 'b:TestId'}
log.info tests
//Get the rate plan codes
def testId = { option ->
def res = option.'**'.findAll {it.name() == 'b:TestId'}
if (res) return option.TestId.text()
null
}
def testIdArray = []
tests.each { if (testId(it)) testIdArray << testId(it) }
for (int i = 0; i < testIdArray.size(); i++) {
log.error "TestIds: " + testIdArray[i]
}
log.warn testIdArray.size()
Below is the xml:
<s:Envelope xxx="xxx" xxx="xxx">
<s:Header>
<a:Action s:mustUnderstand="1">xxx</a:Action>
</s:Header>
<s:Body>
<XML1 xmlns="xxx">
<XML2 xmlns:b="xxx" xmlns:i="xxx">
<XML3>
<b:TestId>000000</b:TestId>
</XML3>
<XML3>
<b:TestId>000000</b:TestId>
</XML3>
</XML2>
</XML1>
</s:Body>
</s:Envelope>
Pass the xml string response to below response variable
def xml = new XmlSlurper().parseText(response)
def getFlightIds = { type = '' ->
type ? xml.'**'.findAll { it.name() == type }.collect { it.FlightId.text() } : xml.'**'.findAll {it.FlightId.text()}
}
//Get the respective flight ids
//Use the desired one as you have mentioned none
def inFlightIds = getFlightIds('InboundFlightInformation')
def outFlightIds = getFlightIds('OutboundFlightInformation')
def allFlightIds = getFlightIds()
log.info "Inbound flight ids: ${inFlightIds}"
log.info "Outbound flight ids: ${outFlightIds}"
log.info "All flight ids: ${allFlightIds}"
You can quickly try online Demo
it.name() in your case it is a NodeChild
so, it.name() returns just a name without prefix. it means you should compare it to FlightId (without b: )
if you want to check a namespace (linked to a prefix) then your lookup must be like this:
def flights = parsedxml.'**'.findAll { it.name() == 'FlightId' && it.namespaceURI()=='xxx' }
I have written below code to read values dynamically from Excel, call web service from SOAP UI and to write values between Response tags to Excel.
import jxl.*;
import jxl.read.biff.BiffException;
import jxl.write.*;
def reqOperationName = "TestRequest";
def inputDataFileName = "Automate/SampleData.xls";
def inputDataSheetName = "sendSampleData";
log.info("Service Testing Started")
Workbook workbook = Workbook.getWorkbook(new File(inputDataFileName));
WritableWorkbook copy = Workbook.createWorkbook(new File(inputDataFileName),workbook);
WritableSheet sheetl = copy.getSheet(inputDataSheetName);
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context);
def reqholder = groovyUtils.getXmlHolder(reqOperationName+"#Request");
try{
rowcount = sheetl.getRows();
colcount = sheetl.getColumns();
for(Row in 1..rowcount-1){
for(Col in 2..colcount-1){
String reqTagName = sheetl.getCell(Col,0).getContents()
def TagCount = reqholder["count(//*:"+reqTagName+")"]
if(TagCount!=0){
String reqTagValue = sheetl.getCell(Col,Row).getContents()
reqholder.setNodeValue("//*:"+reqTagName, reqTagValue)
reqholder.updateProperty()
}
}
// To Run Test Request
testRunner.runTestStepByName(reqOperationName)
//Read Response XML
def resholder = groovyUtils.getXmlHolder(reqOperationName+"#Response")
resTagValue1 = resholder.getNodeValues("//*:message")
//Write Response value to Excel Sheet
Label resValue1 = new Label(8,Row,java.lang.String resTagValue1);
sheetl.addCell(resValue1);
}// Row loop Ends Here
}catch (Exception e) {log.info(e) }
finally{
copy.write();
copy.close();
workbook.close();
}
log.info("Service Testing Finished")
Response from my web service is as shown follows:-
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<Response xmlns="http://eh.dummy.com">
<sets xmlns="">
<sets_InnerSet xmlns="http://eh.dummy.com">
<visibleSetsInnerSet>
<set_cd>QS1</set_cd>
</visibleSetsInnerSet>
<visibleSetsInnerSet>
<set_cd>QS8</set_cd>
</visibleSetsInnerSet>
<visibleSetsInnerSet>
<set_cd>QS9</set_cd>
</visibleSetsInnerSet>
</sets_InnerSet>
</sets>
<responseCode xmlns="">success</responseCode>
</Response>
</soap:Body>
</soap:Envelope>
Can you please let me know how can I read values (QS1/QS8/QS9) from set_CD tags and write to Excel file in a single cell as QS1, QS8, QS9.
You can use below groovy code snippet to get the desired value in the required format.
//Pass the xml string to parseText method below i.e., your response
def parsedXml = new XmlSlurper().parseText(xml)
//Get the desired value in required format
def result = parsedXml.'**'.findAll {it.name() == 'set_cd'}.collect{it.text().trim()}.join(',')
log.info "Desired output : $result"
//You can use result variable to write or use anywhere you needed
You can try this quickly online Demo
Hoping that you will be able to proceed and write the above retried result to where you needed.
I want to transform an XML document which I have parsed with XmlSlurper. The (identical) XML tag names should be replaced with the value of the id attribute; all other attributes should be dropped. Starting from this code:
def xml = """<tag id="root">
| <tag id="foo" other="blah" more="meh">
| <tag id="bar" other="huh"/>
| </tag>
|</tag>""".stripMargin()
def root = new XmlSlurper().parseText(xml)
// Some magic here.
println groovy.xml.XmlUtil.serialize(root)
I want to get the following:
<root>
<foo>
<bar/>
</foo>
</root>
(I write test assertions on the XML, and want to simplify the structure for them.) I've read Updating XML with XmlSlurper and searched around, but found no way with replaceNode() or replaceBody() to exchange a node while keeping its children.
Adding the 'magic' in to the code in the question gives:
def xml = """<tag id="root">
| <tag id="foo" other="blah" more="meh">
| <tag id="bar" other="huh"/>
| </tag>
|</tag>""".stripMargin()
def root = new XmlSlurper().parseText(xml)
root.breadthFirst().each { n ->
n.replaceNode {
"${n.#id}"( n.children() )
}
}
println groovy.xml.XmlUtil.serialize(root)
Which prints:
<?xml version="1.0" encoding="UTF-8"?><root>
<foo>
<bar/>
</foo>
</root>
HOWEVER, this will drop any content in the nodes. To maintain content, we would probably need to use recursion and XmlParser to generate a new doc from the existing one... I'll have a think
More general solution
I think this is more generalised:
import groovy.xml.*
def xml = """<tag id="root">
| <tag id="foo" other="blah" more="meh">
| <tag id="bar" other="huh">
| something
| </tag>
| <tag id="bar" other="huh">
| something else
| </tag>
| <noid>woo</noid>
| </tag>
|</tag>""".stripMargin()
def root = new XmlParser().parseText( xml )
def munge( builder, node ) {
if( node instanceof Node && node.children() ) {
builder."${node.#id ?: node.name()}" {
node.children().each {
munge( builder, it )
}
}
}
else {
if( node instanceof Node ) {
"${node.#id ?: node.name()}"()
}
else {
builder.mkp.yield node
}
}
}
def w = new StringWriter()
def builder = new MarkupBuilder( w )
munge( builder, root )
println XmlUtil.serialize( w.toString() )
And prints:
<?xml version="1.0" encoding="UTF-8"?><root>
<foo>
<bar>something</bar>
<bar>something else</bar>
<noid>woo</noid>
</foo>
</root>
Now passes through nodes with no (or empty) id attributes
I've got a grouped query that results in a list of clinics. Within the clinics are patients. And within the patients are prescriptions. I'm trying to output this structure using MarkupBuilder, but I can't seem to get the containment working.
What I'm getting is this:
<worklist>
<clinics>
<clinic id="1" name="Clinic 1"/>
<patient firstName="John" id="2" lastName="Doe"/>
<prescription id="4">
<prescriptionType/>
<duration/>
<drugName>Tums</drugName>
<route/>
<refills>0</refills>
</prescription>
<clinic id="2" name="Clinic 2"/>
<patient firstName="John" id="2" lastName="Doe"/>
<prescription id="2">
<prescriptionType>Formulary</prescriptionType>
<duration>duration</duration>
<drugName>Lipitor</drugName>
<route>route</route>
<refills>5</refills>
</prescription>
<patient firstName="Sylvia" id="4" lastName="Plath"/>
<prescription id="5">
<prescriptionType/>
<duration/>
<drugName>BandAids</drugName>
<route/>
<refills>0</refills>
</prescription>
</clinics>
</worklist>
Note that clinic element closes and does not contain the patients. And patient element closes and does not contain the prescriptions. This is incorrect. It should look like this:
<worklist>
<clinics>
<clinic id="1" name="Clinic 1">
<patient firstName="John" id="2" lastName="Doe">
<prescription id="4">
<prescriptionType/>
<duration/>
<drugName>Tums</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
<clinic id="2" name="Clinic 2"/>
<patient firstName="John" id="2" lastName="Doe">
<prescription id="2">
<prescriptionType>Formulary</prescriptionType>
<duration>duration</duration>
<drugName>Lipitor</drugName>
<route>route</route>
<refills>5</refills>
</prescription>
</patient>
<patient firstName="Sylvia" id="4" lastName="Plath">
<prescription id="5">
<prescriptionType/>
<duration/>
<drugName>BandAids</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
</clinics>
</worklist>
Here is my code:
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
#Path('/api/worklist')
class WorklistResource {
def addClinic = { idx, name ->
clinic(id:idx, name:name)
}
def addPatient = { idx, fname, lname ->
patient(id:idx, firstName:fname, lastName:lname)
}
#GET
#Produces(['application/xml','application/json'])
String getWorklistRepresentation() {
def groupedScripts = Prescription.createCriteria().list {
createAlias('clinic', 'clinicAlias')
createAlias('patient', 'patientAlias')
projections {
groupProperty "id"
groupProperty "clinicAlias.id"
groupProperty "patientAlias.id"
}
order "clinicAlias.name"
order "patientAlias.lastName"
order "patientAlias.firstName"
}
def curClinic = null
def curPatient = null
def worklist = new StreamingMarkupBuilder().bind {
worklist {
clinics {
groupedScripts.each { arr ->
def (rx, clinic, patient) = arr
def script = Prescription.get(rx)
def cl = Clinic.get(clinic)
def pat = Patient.get(patient)
if( curClinic != cl ) {
curClinic = cl
addClinic.delegate = delegate
addClinic(cl.id, cl.name)
}
if( curPatient != pat ) {
curPatient = pat
addPatient.delegate = delegate
addPatient(pat.id, pat.firstName, pat.lastName)
}
prescription(id:script.id) {
prescriptionType(script.prescriptionType)
duration(script.duration)
drugName(script.drugName)
route(script.route)
refills(script.refills)
}
}
}
}
}
def xml = XmlUtil.serialize(worklist)
xml
}
}
Obviously, I need to somehow keep the clinic closure open until I hit a new clinic or reach the end of the collection. And the same with patient closure. I'm just not sure how to do that.
Thanks in advance for any help. I need to get this working tonight.
You can use just the each method on lists. You have to take care on the following: every matched method call inside the builder.bind will call the respective method/variable; thus you will need different names. That's even better, because you don't make ambiguous naming. You can just structure the whole XML inside the eachs. It's a somewhat large, but this fills your XML the way you want:
UPDATE:
Since your model is reversed, i made the following:
// definition of the model and mock data
#Canonical class Prescription {
int id
String prescriptionType, duration, drugName, route
int refills
Clinic clinic
Patient patient
}
#Canonical class Clinic {
int id
String name
}
#Canonical class Patient {
int id
String firstName, lastName
}
def patient2 = new Patient(2, "John", "Doe")
def patient4 = new Patient(4, "Sylvia", "Plath")
def clinic1 = new Clinic(1, "Clinic 1")
def clinic2 = new Clinic(2, "Clinic 2")
def prescriptions = [
new Prescription(2, "Formulary", "duration", "Lipitor", "route", 5, clinic1, patient2),
new Prescription(4, null, null, "Tums", null, 0, clinic2, patient2),
new Prescription(5, null, null, "BandAids", null, 5, clinic2, patient4)
]
The best bet is to reverse the model so it matches the XML structure. You can easily reverse it using this snippet:
clins = prescriptions.inject([:].withDefault({ [:] })) { map, pres ->
map[ pres.clinic ] << [ (pres.patient) : pres ]
map
}
Now you build the XML according to the map structure:
builder = new groovy.xml.StreamingMarkupBuilder()
xml = builder.bind {
clinics {
clins.each { cliEntry -> cli = cliEntry.key
clinic(id: cli.id, name: cli.name) {
cliEntry.value.each { patEntry -> pat = patEntry.key
patient(id: pat.id, firstName: pat.firstName, lastName: pat.lastName){
patEntry.value.each { pres ->
prescription(id: pres.id) {
prescriptionType pres.prescriptionType
duration pres.duration
drugName pres.drugName
route pres.route
refills pres.refills
}
}
}
}
}
}
}
}
And the test:
assert xml.toString() == """<clinics><clinic id='1' name='Clinic 1'><patient id='2' firstName='John' lastName='Doe'><prescription id='2'><prescriptionType>Formulary</prescriptionType><duration>duration</duration><drugName>Lipitor</drugName><route>route</route><refills>5</refills></prescription></patient></clinic><clinic id='2' name='Clinic 2'><patient id='2' firstName='John' lastName='Doe'><prescription id='4'><prescriptionType/><duration/><drugName>Tums</drugName><route/><refills>0</refills></prescription></patient><patient id='4' firstName='Sylvia' lastName='Plath'><prescription id='4'><prescriptionType/><duration/><drugName>Tums</drugName><route/><refills>0</refills></prescription></patient></clinic></clinics>"""
I've got some ugliness in here with the global _index variable, termination conditions, and try..catch nonsense, but I've been at this for many hours and this code works:
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
#Path('/api/worklist')
class WorklistResource {
def _index = null // global index into groupedScripts collection
def addClinic = { scripts, index ->
addPatient.delegate = delegate
def (rxId, clinicId, patientId) = scripts[index]
def startingClinicId = clinicId
def cl = Clinic.get(clinicId)
clinic(id:cl.id, name:cl.name) {
while( clinicId == startingClinicId ) {
_index = index
index = addPatient(scripts, index)
if( index == -1 ) return -1
try {
(rxId, clinicId, patientId) = scripts[++index]
} catch(NullPointerException e) {
return -1
}
}
}
return _index
}
def addPatient = { scripts, index ->
def result = index
def (rxId, clinicId, patientId) = scripts[index]
def startingPatientId = patientId
def pat = Patient.get(patientId)
patient(id:pat.id, firstName:pat.firstName, lastName:pat.lastName) {
while( patientId == startingPatientId ) {
_index = index
def script = Prescription.get(rxId)
prescription(id:script.id) {
prescriptionType(script.prescriptionType)
duration(script.duration)
drugName(script.drugName)
route(script.route)
refills(script.refills)
}
try {
(rxId, clinicId, patientId) = scripts[++index]
} catch(NullPointerException e) {
return -1
}
}
}
return _index
}
#GET
#Produces(['application/xml','application/json'])
String getWorklistRepresentation() {
def groupedScripts = Prescription.createCriteria().list {
createAlias('clinic', 'clinicAlias')
createAlias('patient', 'patientAlias')
projections {
groupProperty "id"
groupProperty "clinicAlias.id"
groupProperty "patientAlias.id"
}
order "clinicAlias.name"
order "patientAlias.lastName"
order "patientAlias.firstName"
}
def finished = false
def worklist = new StreamingMarkupBuilder().bind {
worklist {
clinics {
_index = 0
addClinic.delegate = delegate
while( !finished && _index < groupedScripts.size() ) {
_index = addClinic(groupedScripts, _index)
if( _index == -1 ) finished = true
++_index
}
}
}
}
def xml = XmlUtil.serialize(worklist)
xml
}
}
The output is:
<worklist>
<clinics>
<clinic id="1" name="Clinic 1">
<patient firstName="Mariah" id="3" lastName="Brookstone">
<prescription id="1">
<prescriptionType>New</prescriptionType>
<duration>30 days</duration>
<drugName>Lisinopril 20mg Tablet</drugName>
<route>By Mouth</route>
<refills>2</refills>
</prescription>
</patient>
<patient firstName="John" id="2" lastName="Doe">
<prescription id="4">
<prescriptionType/>
<duration/>
<drugName>Tums</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
<clinic id="2" name="Clinic 2">
<patient firstName="Mariah" id="3" lastName="Brookstone">
<prescription id="11">
<prescriptionType/>
<duration/>
<drugName>Milk Duds</drugName>
<route/>
<refills>0</refills>
</prescription>
<prescription id="12">
<prescriptionType/>
<duration/>
<drugName>Hershey</drugName>
<route/>
<refills>0</refills>
</prescription>
<prescription id="7">
<prescriptionType/>
<duration/>
<drugName>Skittles</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
<patient firstName="John" id="2" lastName="Doe">
<prescription id="2">
<prescriptionType>Formulary</prescriptionType>
<duration>duration</duration>
<drugName>Lipitor</drugName>
<route>route</route>
<refills>5</refills>
</prescription>
</patient>
<patient firstName="Sylvia" id="4" lastName="Plath">
<prescription id="5">
<prescriptionType/>
<duration/>
<drugName>BandAids</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
<clinic id="3" name="Clinic 3">
<patient firstName="Jane" id="12" lastName="Doe">
<prescription id="9">
<prescriptionType/>
<duration/>
<drugName>Reese's Pieces</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
<patient firstName="Jill" id="13" lastName="Doe">
<prescription id="8">
<prescriptionType/>
<duration/>
<drugName>Toothpaste</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
<patient firstName="Jim" id="11" lastName="Doe">
<prescription id="10">
<prescriptionType/>
<duration/>
<drugName>Hallmark</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
<patient firstName="John" id="2" lastName="Doe">
<prescription id="6">
<prescriptionType/>
<duration/>
<drugName>Gauze</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
</clinics>
</worklist>
That's (almost) exactly what I was after.
I've been trying to do some xml modifications with groovy's XML Slurper.
Basically, i'm going through the xml and looking for tags or attributes that have ? as the value and then replacing it with some value.
I've got it working for xml that doesn't have namespaces but once I include them things get wonky. For example, this:
String foo = "<xs:test xmlns:xs="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:foo="http://myschema/xmlschema" name='?'>
<foo:tag1>?</foo:tag1>
<foo:tag2>?</foo:tag2>
</xs:test>";
produces:
<Envelope/>
Here's the groovy code I'm using. This does appear to work when I am not using a namespace:
public def populateRequest(xmlString, params) {
def slurper = new XmlSlurper().parseText(xmlString)
//replace all tags with ?
def tagsToReplace = slurper.depthFirst().findAll{ foundTag ->
foundTag.text() == "?"
}.each { foundTag ->
foundTag.text = {webServiceOperation.parameters[foundTag.name()]}
foundTag.replaceNode{
"${foundTag.name()}"(webServiceOperation.parameters[foundTag.name()])
}
}
//replace all attributes with ?
def attributesToReplace = slurper.list().each{
it.attributes().each{ attributes ->
if(attributes.value == '?')
{
attributes.value = webServiceOperation.parameters[attributes.key]
}
}
}
new StreamingMarkupBuilder().bind { mkp.yield slurper }.toString()
}
from groovy documentation
def wsdl = '''
<definitions name="AgencyManagementService"
xmlns:ns1="http://www.example.org/NS1"
xmlns:ns2="http://www.example.org/NS2">
<ns1:message name="SomeRequest">
<ns1:part name="parameters" element="SomeReq" />
</ns1:message>
<ns2:message name="SomeRequest">
<ns2:part name="parameters" element="SomeReq" />
</ns2:message>
</definitions>
'''
def xml = new XmlSlurper().parseText(wsdl).declareNamespace(ns1: 'http://www.example.org/NS1', ns2: 'http://www.example.org/NS2')
println xml.'ns1:message'.'ns1:part'.size()
println xml.'ns2:message'.'ns2:part'.size()