Just pressing this quick blog for people who always ask question about CDATA handling in request/response using soapUI/Groovy.

Now the very first question anybody would ask is why we use CDATA in XML? Isn’t the XML suppose to be the simplest form of data communication? If yes, then why by introducing the CDATA tag in XML we are making it more complex?

Well, my take on above question would be as follow :

Yes, XML is still remains simplest form of data communication. And actually by introducing the CDATA tag in request/response we are making the life more simpler in certain cases. Now you might wonder what are those cases?

Consider the case when, you want to transfer some data which is in XML tag format (but not necessarily pure xml). Now if you will directly transfer the XML file across the machine the receiving XML parser will parse that complete xml. That would obviously take someย  time to process & few more work. This can be avoided if we directly pass the required XML as “String”. Yes and CDATA actually help in achieving the same. So whenever you want to pass the XML tags in XML you can use CDATA and then those XML tags will be treated as String.

Now coming back the “CDATA Handling” in soapui using Groovy. This can be further divided into 2 parts :

CDATA in response :

if( submit.response == null )
   return
def responseContent = submit.response.responseContent
responseContent = responseContent.replaceAll( "<!\\[CDATA\\[", "" )
responseContent = responseContent.replaceAll( "]]>", "" )
log.info( responseContent )
submit.response.responseContent =  responseContent

Above mentioned code should be written in following navigation :
Select the Project name & double click to open a new window, select the “Events” tab and add a SubmitListener.afterSubmit handler. Set its content to above groovy code lines.

CDATA in request : *

if( request.requestContent == null )
   return
log.info "Old request with CDATA : " + request.requestContent
def requestContent = request.requestContent
requestContent = requestContent.replaceAll( "<!\\[CDATA\\[", "" )
requestContent = requestContent.replaceAll( "]]>", "" )
log.info "New request without CDATA : " + request.requestContent
request.requestContent =  requestContent

* please make sure that playing with request CDATA is not hampering your server response. As in if your server is expected to receive the CDATA in request.

Above mentioned code should be written in following navigation :
Select the Project name & double click to open a new window, select the “Events” tab and add a RequestFilter.filterRequest handler. Set its content to above groovy code lines.

There are few other ways to do it and soapui Documentation provides more details about the same at soapUI
Source code courtesy : soapUI.org

UPDATE :: Below is the another way to handle CDATA in soaui using property transfer. Thanks to “Tim Reynolds” for sharing it many other users ๐Ÿ™‚
Also, do have a look into the comments of this blog, you might find another interesting finding by Tim.

<!-- A TestResponse, lets call it TestStepNameXYZ -->
<soap:Envelope
    xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
    xmlns:rpc="http://www.w3.org/2003/05/soap-rpc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
   <SomeCmdResponse xmlns="http://wsdl.coolstuff.com/Morestuff/">
      <SomeCmdResult xmlns="">
          <![CDATA[<RESULT><THE_ELEMENT_I_WANT/><LotsOfXmlElements/></RESULT>]]>
      </SomeCmdResult>
  </SomeResponse>
</soap:Body>
</soap:Envelope>

<!-- A Transfer TestStep with multiple Transfers -->
<!-- Call this XFR-GetToCDATA -->
<!-- Here you define/declare the required namespaces -->
<!-- Next you use XPATH to get to the element that contains the CDATA -->
<!-- note the use of text(), this gets you ALL the CDATA -->
<!-- AND does the translation for you - very nice -->
<!-- Use  Source: TestStepNameXYZ Property: Response -->
declare namespace ns1='';
declare namespace coolstuff='http://wsdl.coolstuff.com/Morestuff/';
declare namespace rpc='http://www.w3.org/2003/05/soap-rpc';
declare namespace soap='http://www.w3.org/2003/05/soap-envelope';
declare namespace saxon='http://saxon.sf.net/' ;
//coolstuff:SomeCmdResponse/SomeCmdResult/text()
<!-- Use  Target: TestCaseName/Project/global/youPickIt Property: SomeTmpPropName -->

<!-- Create a 2nd XFR Step -->
<!-- Call this XFR-UseTheUnCDATAdXml -->
<!-- XPATH to whatever you want, or you could just use the SomeTmpPropName in you groovy -->
<!-- Use  Source: TargetValueFromAbove Property: SomeTmpPropName -->
/RESULT/THE_ELEMENT_I_WANT
<!-- Use  Target: TestCaseName/Project/global/youPickIt Property: SomeOtherPropName -->
Advertisements
Comments
  1. Tim says:

    Hi Pradeep,

    First, thanks for the nice blog, I was just looking at this and your 10 steps page.

    I have written an Xslt script which translates my soap xml with CDATA and 32char UID values into
    something I can actually read during test and Debug. However I only know how to run it in Eclipse
    using a run config main class com.me.xslt.SimpleXMLTransform with the following arguments:
    ../Input.xml ../EchelonMappingTransformXml.xslt ../Output.xml. I am forced to copy the XML Rsp from SoapUI and put it in the above Input.xml.

    How can I run this Xslt Transfrom inside SoapUI from a Groovy Script and send the output to a log or a file? I am new to XSLT but I got thru it, I am also trying to learn Groovy and SoapUI. I have
    written some simple test but its time to go a bit deeper!

    Thanks,
    Tim

    • Hi Tim,

      I never had a luck/chance to get direct exposure to XSLT. However did learnt quite a few things.
      If i am correctly understanding your question (taking soapUI response & pass the same into Eclipse config main with some defined arguments) then i might give you hints to work upon.
      – Using groovy ( a script assertion under a teststep) we can save the response data as a XML file.
      – Also using groovy we can call few executables with required agruments, refer http://groovy.codehaus.org/Executing+External+Processes+From+Groovy
      – I bet, (since) Eclipse is performing the XSLT script transformation using some config class there must be an command file for the same.

      I hope this would be of some help.
      However, it might be useful if you can share more details about the process/steps involved with Eclipse config. How about dropping in a mail ๐Ÿ™‚

      Regards,
      {Pradeep Bishnoi}

      • Tim says:

        thanks for the tip, the link you included looks promising. I will let you know more when I review
        the information on the link.

  2. Tim says:

    Pradeep,

    from: http://groovy.codehaus.org/Processing+XML+with+XSLT
    i figured out the following:

    // require(url=’http://xml.apache.org/xalan-j/’, jar=’serializer.jar’)
    // require(url=’http://xml.apache.org/xalan-j/’, jar=’xalan_270.jar’)
    import javax.xml.transform.ErrorListener;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerConfigurationException;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.TransformerFactory;

    import javax.xml.transform.sax.SAXTransformerFactory;
    import javax.xml.transform.sax.TransformerHandler;

    import javax.xml.transform.stream.StreamResult;
    import javax.xml.transform.stream.StreamSource;

    import java.io.File;

    def response = context.expand( ‘${SomeSoapTestStepName#Response}’ )
    def StreamSource xsource = new StreamSource(new File(‘MappingTransformXml.xslt’))
    def factory = TransformerFactory.newInstance()
    def transformer = factory.newTransformer(xsource)
    def OutputStream os = new FileOutputStream((new File(“Result-RSP-XFRM.xml”)).getName());
    transformer.transform(new StreamSource(new StringReader(response)), new StreamResult(os))
    log.info(‘>>>> XSLT Transform Complete!!! <<<')

    Note: my xslt transform is read in. it resides in the SOAPUI_HOME/bin dir along with a map.xml
    file I use to do the conversions.

    I wrote to you initially because the part of the msg that I am transforming is CDATA.
    I use a slightly different way to get to CDATA, in my case the embedded CDATA is XML.
    see next reply

  3. Tim says:

    Pradeep,

    I get to CDATA via a Property Transfer Step, I am not sure if it is easier /better/worse or just
    different than what you do but it works for me. It also works when the CDATA is just escaped
    with the lt and gt notation.

    Example Soap Response from a TestCase Step

    <![CDATA[]]>








    declare namespace ns1=”;
    declare namespace coolstuff=’http://wsdl.coolstuff.com/Morestuff/’;
    declare namespace rpc=’http://www.w3.org/2003/05/soap-rpc’;
    declare namespace soap=’http://www.w3.org/2003/05/soap-envelope’;
    declare namespace saxon=’http://saxon.sf.net/’ ;
    //coolstuff:SomeCmdResponse/SomeCmdResult/text()





    /RESULT/THE_ELEMENT_I_WANT

    This turns out to be pretty easy, its also pretty clean when you get rid of all the comments I stuck
    in.

    I don’t have blog, but I use google and other folks blogs all the time. I hope this helps the next guy
    and if you care to pretty it up with wordpress code blocks that would be great ๐Ÿ™‚

    Thanks,
    Tim

  4. Tim says:

    sorry, I sent a followup email to your gmail account. I used xml comments in the above reply and they got blown away

    Tim

  5. Dawn says:

    I am dealing with the issue of responses containing french language elements. When I send the request (soap REST) using en property, the xml response comes back parsed, as expected. However, when I change the property to fr (french language) then the xml comes back raw, with CDATA tags surrounding everything. I am trying to write a script that will strip out the CDATA takes when the response is brought back, and display it correctly. Any ideas? i cannot get my test suites or test steps to work otherwise.

  6. Tim says:

    Hi Dawn,
    Are you using SoapUI? and are you using SOAP or REST?
    Please include some sample of your data that has the CDATA tags in it.

    you will see line #10 which contains the CDATA
    and line #28 which shows how to get the content of the CDATA with an XPATH expression
    that ends in /text() , this is what gets the CDATA content.

  7. Ashish says:

    Hi Pradeep,

    I am still can’t get this working with request. I am getting the following error:

    groovy.lang.MissingMethodException: No signature of method:
    com.eviware.soapui.support.XmlHolder.replaceAll() is applicable for argument types: (java.lang.String,java.lang.String) values: [<!\[CDATA\[,]

    what does this mean?

    Thanks,
    Ashish

  8. Ashish says:

    OOPS !! I think I missed the “navigation point”. but Pradeep I am using a free source and not the PRO version. can I still be able to achieve my goal. Is there any other way to do it?

    • Hi Ashish,

      It should work with the OPEN source version. Another approach to implement the same has been shared by Tim (i have updated this blog with same).

      Regards,
      /Pradeep Bishnoi

      • Tim says:

        Pradeep,
        yet another way to deal with CDATA that contains XML. this was done inside a
        RequestFilter.afterRequest

        def rspSoap = new XmlSlurper().parseText(request.response.contentAsXml)
        if(rspSoap.Body.MyRootElementName == null)
        {return }
        def cdata = rspSoap.Body.MyRootElementName.ElementNameContainingCdata.text()
        log.info “CDATA: ${cdata}”
        def cdataAsXML = new XmlSlurper().parseText(cdata)

        Tim

  9. Dawn says:

    Hi Pradeep, Is it possible to send you the file? It contains proprietary information which I should not display on the blog. thanks

  10. dawnjardine says:

    I’m still having the same issue. All my responses with the fr property return with CDATA which means I cannot use the automation for the French language. The Content type in the request is set to text/html due to the accents in the French language.

  11. Tim says:

    Dawn,
    I don’t use REST on a daily basis, but I can take a look. Can you include a trimmed down example
    of the entire msg please? All I saw last time was “12010”
    For me it seems there are two steps to dealing with CDATA
    1. Get to the element that contains the CDATA via groovy or xpath and use “text()”
    to capture the CDATA portion. e.g
    groovy def cdata = rspSoap.Body.MyRootElementName.ElementNameContainingCdata.text()
    2. Once you have the CDATA, translate it to XML
    groovy def cdataAsXML = new XmlSlurper().parseText(cdata)

    Pradeep – do you have a way to include code surrounded by some tags?

    Tim

    • Hi Tim,

      Thanks for sharing your findings again.
      I don’t have any information handy with me which allow us to include code.
      However we can try (groovy,xml etc):

      my code
      

      Else, drop in a mail and i would try to publish the same.

      Best Regards,
      {Pradeep Bishnoi}

  12. Tim says:

    Pradeep,

    I should have been more specific about

    “Pradeep โ€“ do you have a way to include code surrounded by some tags?”

    what I meant was, do you have a way for commentors to include code snipets in their comments?
    I see that you can put code in your comments.

    like surround comment by
    code goes here

    I am learning more about SoapUI every day, its a great tool but there is lots to learn.

    Tim

    • Hey Tim,

      Nope, i haven’t came across such a feature for the comment section yet. I have to manually do the same, if the code is available to me over a mail.

      Best Regards,
      {Pradeep Bishnoi}

  13. Sadhanandhan B says:

    Tim, Pradeep

    I followed Tim’s explanation on using double property transfers for extracting CDATA from the response. I am using WebServiceX, and a newbie in SoapUI. Everything just worked for me perfectly, for getting the weather for a particular city and country using the GetWeather service from WebServiceX. My issue is that the City/Country combination extracted from CDATA cannot navigate to the next city. I am stuck with the first city for country India, namely “Diego Garcia”. I used the following step in the last property before sending my request and it works
    /NewDataSet/Table[1]/City[1]

    But when i am trying to use /NewDataSet/Table[2]/City[2], it throws an error : Missing Match for Source XQuery [/NewDataSet/Table[2]/City[2]]

    With best regards
    Sadhanandhan B.

  14. Manoj says:

    Hey Pradeep, I have an issue to write XPATH when response contains CDATA tag like in this WSDL
    http://www.webservicex.net/uklocation.asmx?WSDL

    Please explain how to write XPATH for above WSDL response

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s