Forum Discussion

geoffcamp's avatar
geoffcamp
Contributor
16 years ago

Removing Complex tags when empty.

Hi,

I have a number of Service Operations which contain complex tags that must either be populated, or not exist at all within the request.
This is causing me an issue as each of the tags is parameterised, and therefore if they are not populated then they are passed as blank rather than not existing.

For example:


    ${DataSource#partyIdentifier}


    ${DataSource#agreementIdentifier}
    ${DataSource#agreementType}
    ${DataSource#agreementSourceSystem}


In this example the distributionAgreement tag itself is conditional.  That is to say if any of the tags within the distributionAgreement complex tag are populated then the distributionAgreement tag must exist.
However if each of the three values within the distributionAgreement complex tag are blank then the entire complex tag must not be present.

If any of the tags within the distributionAgreement tag are populated then the following should be sent:


    12345678


    Agent 01
    Agent of
   


And if none of the tags within the distributionAgreement tag are populated then the following should be sent:


    12345678


However because each of the tags is parameterised, when these are passed as blank the actual Request sent currently is:


    12345678


   
   
   


I'm sure there must be a number of people who are facing / have faced the same issue.
Is there a way I can ensure that if an entire complex tag is empty then the tag itself is removed?

I could probably cater for this within a groovy script, however I don't want to have to individually script for each complex tag that acts this way within each of our Service Operations.
Is there inbuilt functionality I can use to accomplish this?
Alternatively does anyone have an idea of how I could accomplish this with a single groovy script that I could use as a template for all Service Operations?

Cheers in advance,

Geoff

3 Replies

  • M_McDonald's avatar
    M_McDonald
    Super Contributor
    Assuming you are using the free version, how about this:

    1) A Properties step containing all the parameterized fragments for the request, eg:

    [tt:20t7leec]distributionAgreement:[/tt:20t7leec][tt:20t7leec]
         ${DataSource#agreementIdentifier}
         ${DataSource#agreementType}
         ${DataSource#agreementSourceSystem}
    [/tt:20t7leec]
    [tt:20t7leec]otherfragment:[/tt:20t7leec][tt:20t7leec]$(someValue}[/tt:20t7leec]


    2) A Groovy script step which loops through first Properties step properties, evaluates each and if any elements are populated, puts the value into another Properties step. Something like this:

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

    def propList = testRunner.testCase.getTestStepByName("Properties1").propertyList

    propList.each { prop ->

    def propName = prop.name
    def propVal = context.expand(prop.value)
    def parsedXml = new XmlParser().parseText(propVal)

    def count = 0
    parsedXml.depthFirst().each { node ->
    if (node.text().trim() != "") { count++ }
    }

    if (count == 0) { propVal = "" }

    gu.setPropertyValue("Properties2",propName,propVal)
    }



    3) The Request step then uses the second Properties step properties.
  • Hi,

    Thanks for the reply - it works a treat.  However I want to, if possible, come up with a single solution that would work regardless of the service, so I wouldn't have to go through and define specific elements.

    I've actually got the Pro version - if there's a clever inbuilt function in there I'd love to know about it

    What  I've currently got is as follows in a RequestFilter.filterRequest event:

    import com.eviware.soapui.support.xml.XmlUtils

    def request = context.expand( '${Request#Request}' )

    def parsedXml = new XmlParser().parseText(request)

    def writer = new StringWriter()
    new XmlNodePrinter(new PrintWriter(writer)).print(parsedXml)
    def result = writer.toString()

    def count = 0

    while (count < 5) {

    result = XmlUtils.prettyPrintXml(result)
    result = result.replaceAll( "<(.+)/>", "" )
    result = XmlUtils.prettyPrintXml(result)
    result = result.replaceAll( "<(.+)>", "" )
    result = XmlUtils.prettyPrintXml(result)

    count = count + 1
    }

    context.requestContent = result


    Thus far I've not encountered any complex tags in our Service Operations more than 5 levels deep.  I've not extensively tested this yet, but it appears to work.
    That said, it's clearly a hamfisted attempt, and if anyone has any (and I'm sure there are plenty) suggested improvements I'd love to hear them.

    Cheers,

    Geoff
  • M_McDonald's avatar
    M_McDonald
    Super Contributor
    Interesting. This assumes however that the presence of empty elements is not important, and that you don't care about leading or trailing whitespace. Even CDATA sections will not protect against this:

    [tt:1aepzjt1]&nbsp; text1&nbsp; text2[/tt:1aepzjt1]
    yields

    [tt:1aepzjt1]
      text1
      text2
    [/tt:1aepzjt1]