cancel
Showing results for 
Search instead for 
Did you mean: 

Grab value within XML fragment within a single XML element (CDATA element query)?

Highlighted
Community Hero

Grab value within XML fragment within a single XML element (CDATA element query)?

Hey!

 

 

I'm posting a SOAP request to a web service which generates a SOAP response.  The XML payload within the SOAP response is all contained within 1 tag (using a CDATA element)

 

Within the payload there is a unique identifier that I need to transfer to a subsequent JDBC test step as the filter in the query - see as follows:

 

 

Datasource (directory type) with fileContents property
SOAP request (sourcing the fileContents property as the payload of the request) <-- need to do a PROPERTY TRANSFER on a specific value in the payload 
JDBC Test Step (using the uniqueID from the SOAP response)

When I've done this before - the response wasn't in a SOAP wrapper - so all the tags/attributes within the Response's XML were on different lines in the Response - so it was straightforward to do a PROPERTY TRANSFER on to transfer the uniqueID from the response.

 

HOWEVER - because all the payload of the XML response is contained within a single SOAP payload tag (using the CDATA element) - I'm struggling to extract the uniqueID (SyncID in the XML below)

 

<SOAP-ENV:Envelope>
   <SOAP-ENV:Body>
      <NS1:SyncResponse>
         <return><![CDATA[<SyncVenueOutput>
  <Responses>
    <SyncSuccesses>
      <SyncSuccess SyncID="AB123"/>
    </SyncSuccesses>
    <SyncIgnores>
      
    </SyncIgnores>
    <SyncErrors>
      
    </SyncErrors>
  </Responses>
</SyncOutput>]]></return>
      </NS1:SyncResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

 

As I say above - I need to extract the SyncID value (currently set above as 'AB123' above) to pass to the JDBC test step - but when I try the transfer - I'm transferring ALL the XML - not just the 'AB123'

 

 

I hope I've been clear,

 

Can anyone provide any guidance please?

 

Many thanks to all!

 

richie

if this helped answer the post, could you please mark it as 'solved'? Also if you consider whether the title of your post is relevant? Perhaps if the post is solved, it might make sense to update the Subject header field of the post to something more descriptive? This will help people when searching for problems. Ta
23 REPLIES 23
Highlighted
Community Hero

Re: Grab value within XML fragment within a single XML element (CDATA element query)?

I merged your two threads together since they are so closely related. For doing the property transfer, you are going to probably need to use a groovy script as well due to having to manually parse the CDATA tag(s).

 

import com.eviware.soapui.support.XmlHolder

def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context );

// get the response, specifically the //RETURN element that contains DATA tags
def response = context.expand( '${TESTTSTEP#Request#declare namespace NS1=\'urn:SyncServicesIntf-ISyncServices\'; //NS1:SyncResponse[1]/return[1]}' )

// remove the CDATA tags
response = response.replaceAll( "<!\\[CDATA\\[", "" )
response = response.replaceAll( "]]>", "" )

// Parse the response into XML
def holder = groovyUtils.getXmlHolder( response )

// Parse the XML of the cdata for the attribute
def successID = (holder["//Responses/SyncSuccesses/SyncSuccess/@SyncID"]);

// set the property in a property test step
properyTestStepName.setPropertyValue("SyncID", successID);

 




---

Click the Accept as Solution button if my answer has helped, and remember to give kudos where appropriate too!
Highlighted
Community Hero

Re: Grab value within XML fragment within a single XML element (CDATA element query)?

nice one to @msiadak

 

I made some small updates and its working (see below)

 

import com.eviware.soapui.support.XmlHolder
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context );
// get the response, specifically the //RETURN element that contains DATA tags. This may need to be adjusted to fit your own project, but you want to collect the //return element
def response = context.expand( '${SOAP Request#Response#declare namespace NS1=\'urn:CSMVenueSyncServicesIntf-ICSMVenueSyncServices\'; //NS1:SyncVenueResponse[1]/return[1]}' )
// remove the CDATA tags
response = response.replaceAll( "<!\\[CDATA\\[", "" )
response = response.replaceAll( "]]>", "" )
// Parse the response into XML
def holder = groovyUtils.getXmlHolder( response )
log.info((holder["exists(//Responses/VenueSyncSuccesses/VenueSyncSuccess)"]));
log.info(holder["count(//Responses/VenueSyncErrors/VenueSyncError)"]);
def successExists = (holder["exists(//Responses/VenueSyncSuccesses/VenueSyncSuccess)"]);
def errorCount = (holder["count(//Responses/VenueSyncErrors/VenueSyncError)"]).toInteger();
assert (successExists && errorCount == 0);

 

I've placed the groovy step immediately after my SOAP Request step and it generates 2 rows in the logging as follows:

 

So - the above is logging the info fine - returns 2 rows depending on the presence of VenueSyncSuccess & VenueSyncError tags are present

 

 

 

 

I can see the 'assert (successExists && errorCount == 0);' line - can you confirm what they are actually doing?

 

FINALLY - I need to create an ASSERTION on the above somehow to indicate during execution whether the VenueSyncSuccess is present or not (to prove the request was successful)

 

I have both positive and negative tests that will generate either a VenueSyncSuccess tag or a VenueSyncError tag - I need to (based on the purpose of the test) assert whether these are present or not - can you please advise?

 

I raised a separate query a while back about passing logged info to a PROPERTY test step - would this allow me to assert on the values?  

 

I'm sorry - I avoid groovy just because I dont know where to start (I'm the only tester where I work - so it;s not like I can ask anybody else!)

 

Many thanks - you're really saving my life here!

 

richie

 

if this helped answer the post, could you please mark it as 'solved'? Also if you consider whether the title of your post is relevant? Perhaps if the post is solved, it might make sense to update the Subject header field of the post to something more descriptive? This will help people when searching for problems. Ta
Highlighted
Community Hero

Re: Grab value within XML fragment within a single XML element (CDATA element query)?

The assert statement that you called out is asserting that there is a success and that there is no error. That statement makes the groovy script act like an assertion.



---

Click the Accept as Solution button if my answer has helped, and remember to give kudos where appropriate too!
Highlighted
Community Hero

Re: Grab value within XML fragment within a single XML element (CDATA element query)?

Without getting into the nitty gritty details (which can be found here), an assert statement is like an assertion on a Soap/REST Test Step. It is verifying a certain piece of information and making the groovy test step pass or fail accordingly. 




---

Click the Accept as Solution button if my answer has helped, and remember to give kudos where appropriate too!
Highlighted
Community Hero

Re: Grab value within XML fragment within a single XML element (CDATA element query)?

I gotcha - the groovy step will go 'red' if it fails - right?

 

I don't know if you noticed, but I had a second 'failed' option (VenueSyncIgnore as well as the VenueSyncError) within the cdata - I've altered your script as follows (totally ripping off what you've already done) and the results appear to work - script is below:

 

import com.eviware.soapui.support.XmlHolder
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context );
// get the response, specifically the //RETURN element that contains DATA tags. This may need to be adjusted to fit your own project, but you want to collect the //return element
def response = context.expand( '${SOAP Request#Response#declare namespace NS1=\'urn:CSMVenueSyncServicesIntf-ICSMVenueSyncServices\'; //NS1:SyncVenueResponse[1]/return[1]}' )
// remove the CDATA tags
response = response.replaceAll( "<!\\[CDATA\\[", "" )
response = response.replaceAll( "]]>", "" )
// Parse the response into XML
def holder = groovyUtils.getXmlHolder( response )
log.info((holder["exists(//Responses/VenueSyncSuccesses/VenueSyncSuccess)"]));
log.info(holder["count(//Responses/VenueSyncErrors/VenueSyncError)"]);
log.info(holder["count(//Responses/VenueSyncIgnores/VenueSyncIgnore)"]);
def successExists = (holder["exists(//Responses/VenueSyncSuccesses/VenueSyncSuccess)"]);
def errorCount = (holder["count(//Responses/VenueSyncErrors/VenueSyncError)"]).toInteger();
def ignoreCount = (holder["count(//Responses/VenueSyncIgnores/VenueSyncIgnore)"]).toInteger();
assert (successExists && errorCount == 0 && ignoreCount ==0);

OK - if you're feeling in a helpful mood I have 1 more point and all I'll stand by all previous conversations

 

I need to be able to extract the VenueID attribute value from within the cdata string to pass this onto a subsequent JDBC test step.  Essentially, once the successful request has been posted, I need to run a query to retrieve the record from within the DB to verify certain attributes have been updated.

 

I should highlight - the VenueID attribute will 'move' in the response, relative to whether the request is successful or is ignored (for certain error scenario) or is a failure (most severe failed options).

 

Obviously I only care about when the request has been successful as only successful requests will write to the DB.

 

I can extract the value and pass it onto the JDBC test step that'll be me very happy!

 

 

Cheers!

 

richie

if this helped answer the post, could you please mark it as 'solved'? Also if you consider whether the title of your post is relevant? Perhaps if the post is solved, it might make sense to update the Subject header field of the post to something more descriptive? This will help people when searching for problems. Ta
Highlighted
Community Hero

Re: Grab value within XML fragment within a single XML element (CDATA element query)?

The first question I have is whether or not there will be more than one VenueID  in the response, or if it will be singular? I can probably whip something up in a bit.




---

Click the Accept as Solution button if my answer has helped, and remember to give kudos where appropriate too!
Highlighted
Community Hero

Re: Grab value within XML fragment within a single XML element (CDATA element query)?

aaah - my whole SoapUI project got corrupted - I lost all msiadak's and Rao's good work!

 

if anyone gets the following warning "WARN:Test Monitor: Trying to unregister a non-existing test model item [model item ID" - in the ReadyAPI! Log - don't ignore it.  I lost ALL my tests.

 

if you get this warning - do the following (sourced from https://community.smartbear.com/t5/SoapUI-Pro/Error-notifying-listener-before-run-ReadyAPI-1-8-0/td-...)

 

1. On the SoapUI NG tab, double-click a project and check the "Compare" or "History" screen. Do you see the "Test Run History Disabled" message on them (see: http://screencast.com/t/eDWaD300USH)? If so, back up the DB, and then update it. Does this resolve the issue?

 

lesson to all (and me especially) backup all your stuff

 

 

@msiadak -  YES - there is only 1 VenueID in any request.  BTW - you'll be getting another email later on tonight with the correct details

 

Cheers to all!

 

richie

 

 

if this helped answer the post, could you please mark it as 'solved'? Also if you consider whether the title of your post is relevant? Perhaps if the post is solved, it might make sense to update the Subject header field of the post to something more descriptive? This will help people when searching for problems. Ta
2016-12-05_1013
Free online storage and sharing with Screencast.com. 2 GB of storage and 2 GB of bandwidth per month for free. We won't compress, alter or take ownership of your content.
Highlighted
Community Hero

Re: Grab value within XML fragment within a single XML element (CDATA element query)?

Okay, working with the last script you had modified and posted, here's what I have:

 

import com.eviware.soapui.support.XmlHolder

def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context );

// get the response, specifically the //RETURN element that contains DATA tags
def response = context.expand( '${TESTTSTEP#Request#declare namespace NS1=\'urn:SyncServicesIntf-ISyncServices\'; //NS1:SyncResponse[1]/return[1]}' )

// remove the CDATA tags
response = response.replaceAll( "<!\\[CDATA\\[", "" )
response = response.replaceAll( "]]>", "" )

// Parse the response into XML
def holder = groovyUtils.getXmlHolder( response )
log.info((holder["exists(//Responses/VenueSyncSuccesses/VenueSyncSuccess)"]));
log.info(holder["count(//Responses/VenueSyncErrors/VenueSyncError)"]);
log.info(holder["count(//Responses/VenueSyncIgnores/VenueSyncIgnore)"]);
def successExists = (holder["exists(//Responses/VenueSyncSuccesses/VenueSyncSuccess)"]);
def errorCount = (holder["count(//Responses/VenueSyncErrors/VenueSyncError)"]).toInteger();
def ignoreCount = (holder["count(//Responses/VenueSyncIgnores/VenueSyncIgnore)"]).toInteger();

def porps = context.testCase.testSteps["porps"];

porps.setPropertyValue("Test", errorCount.toString());

// If success exists, that means there's a VenueID to use
// Find the venue id via Xpath, store to properties step if (successExists) { def syncID = (holder["//Responses/VenueSyncSuccesses/VenueSyncSuccess/@VenueID"])
def propertiesStep = context.testCase.testSteps["Properties Test Step Name"]; propertiesStep.setPropertyValue("VenueID", syncID); } assert (successExists && errorCount == 0 && ignoreCount ==0);


The new addition will transfer the VenueID from the success statement to a properties step. You can then reference in other steps (JDBC request, etc) with property expansion like ${PropertiestestStepName#PropertyName}

 

Does that help?




---

Click the Accept as Solution button if my answer has helped, and remember to give kudos where appropriate too!
Highlighted
Community Hero

Re: Grab value within XML fragment within a single XML element (CDATA element query)?

My environment's db is down  at moment so I can try it properly - I'm sure it works - all the groovy you've given so far always does!

 

Anyway - I have 2 questions.

 

In regards to editing the testcase to support the script - I just need to create a Properties step (edit the groovy to point to the Properties step) AFTER the groovystep and within the Properties step I create a property entitled 'VenueID' is that right? or does the groovystep actually create the 'VenueID' property in the step as well as populate the 'VenueID' property with the value?

 

Second question.  Quite often when you've given me some groovy before and today and yesterday - I kept getting an error response 'org.apache.xmlbeans.XmlException: error: Unexpected element: CDATA
error at line:13'

 

Now I've had a similar error before (when I've just ran the groovy to check it works) and I've either just run the test case or made a couple of edits and  all of a sudden the groovystep doesnt generate the error response anymore.  It seems like I need to initialise (for want of a better word) the groovy - sometimes just editing it will get rid of the error - sometimes running the whole test case (within the groovystep embedded resolves the  problem).  Is there something I should be doing that I'm not?  I had it a couple of years ago when I'd come into work, try and execute a groovystep and I'd get an error - later in the day I wouldnt.  I know this sounds a little flaky - and for the most part - software isnt.  I'm just wondering if there's something I can do to minimise this?????

 

Many thanks again,

 

richie

if this helped answer the post, could you please mark it as 'solved'? Also if you consider whether the title of your post is relevant? Perhaps if the post is solved, it might make sense to update the Subject header field of the post to something more descriptive? This will help people when searching for problems. Ta
New Here?
Join us and watch the welcome video:
Announcements
Top Kudoed Authors