Ask a Question

Groovy : XML Comparison: Dynamic XML Attributes are not ignored whie comparison.

SOLVED
vpachpute1
Frequent Contributor

Groovy : XML Comparison: Dynamic XML Attributes are not ignored whie comparison.

Hi

 

I have one Groovy utility to compare current response with external response kept in xml file.

 

But while comparison, I am facing issue if parameter contains space. e.g.

1. If parameter is present as , subscription id .Then it is not ignored

2. If parameter is present as, subscription-id. Then it is ignored while comparison. Working file.

 

My case:

Actually in my case, subscription id will be dynamic. So while comparison , I added it in ignore list. So that next time this will be ignored while comparison.

 

Attached my groovy Utility and sample external response file.

 

Regards

Vishal

 

17 REPLIES 17
vpachpute1
Frequent Contributor

Hi nmrao

 

1. While comparison, there are some dynamic parameters. e.g. subscription id, purchase-date, expiry-date. So I add them in ignore list.

Issue:
1. Able to ignore xml elements like purchase-date, expiry-date while comparison. Which is fine.
But not able to ignore attributes. e.g. for subscription, 'id' is attribute. And not able to ignore it.

So question is hot to ignore attribute values while xml comparison.

 

Note: Attached my actual responses and Groovy utility. PFA

 

Can you please have a look into it. Actually I am really struggling around this.

 

Regards

Vishal Pachpute

Not sure if you got my request, as requested info is not available. Note that you do not have to provide your exact data, just resembling your case, so that you could implement based on example solution if at all solution posted.

 

EDIT

 

looks like, this time added some more elements in the responses.

 

NOTE: While adding file, have some file extension.

 

By the way, you posted both same responses. Not sure if that is copy-paste. Hoping that what you posted are more nearistic to your data. Post the responses that you have problem while comparing.



Regards,
Rao.
vpachpute1
Frequent Contributor

Hi

 

Sorry, By mistake I copy-pasted twice.

 

But there is no issue. As I mentioned there are only following 3 dynamic parameters values will be different. You can also change these 3 parameters values at your end. 

subscription id, purchase-date, expiry-date

 

I have changed these 3 parameters and added file extension. (Actually working on Ubuntu so it was plain file)

 

Issue:
1. Able to ignore xml elements like purchase-date, expiry-date while comparison. Which is fine.
But not able to ignore attributes. e.g. for subscription, 'id' is attribute. And not able to ignore it.

So question is hot to ignore attribute values while xml comparison.

 

PFA.

 

Regards

Vishal

 

@vpachpute1,

 

The data provided is not well-formed. Fixed a bit to make it well-formed.

 

Here is the script:

 

//assign xml string data for the below two statements, not assigned here to reduce the size of the script

def expected = 
def actual = 

//Don't have to modify beyond this point

//If required, add more ignore nodes or attributes(node: attribute format) in the below appropriately
def ignoreNodes = ['purchase-date', 'expiry-date']
def ignoreAttributes = ['subscription':'id']

//Closure to update the xml with a fixed value REPLACED in place of dynamic value, so that comparison is done successfully
def updateIgnoreElements = { data, fixedVal = 'REPLACED' ->
    def parsedData = new XmlSlurper().parseText(data)
    ignoreAttributes.each { k,v -> parsedData.'**'.findAll { it.name() == k}.collect{it.@"$v" = fixedVal} }
    ignoreNodes.each { element ->  parsedData.'**'.findAll { it.name() == element}.collect{it.replaceBody fixedVal} }
    groovy.xml.XmlUtil.serialize(parsedData) 
}

assert updateIgnoreElements(expected) == updateIgnoreElements(actual), 'Both are not matching'

You can quickly try online demo and the same is available at github



Regards,
Rao.
vpachpute1
Frequent Contributor

Hi nmrao

 

Thanks a lot for your help .

 

It perfectly worked out.

 

Regards

Vishal

@vpachpute1, if the right information is provided along with the problem statement in the beginning, it might not have to wait so long. Any ways, glad it helped.

 

Adding kudoes for the helpful posts is appreciated.



Regards,
Rao.

I hope you don't mind me coming back to this issue, as it kind of piqued my interest.

 

Firstly I always felt a bit uncomfortable with the idea of altering the response XML to make the comparison, and secondly I noticed in you were using a third party library XMLUnit. This is something I had not come across before your post, and was unable to research at the time of answering your question, but since then have had time to investigate.

 

From the XMLUnit web page: "The most important part is a diff-engine that provides you with full control over what kind of difference is important to you and which part of the generated document to compare with which part of your reference document."

 

Seeing as you had already gone to the trouble of installing the XMLUnit libraries, and were using the diff engine, I thought there should be a way of leveraging the XMLUnit functionality to do what you wanted.

 

The following code answers your original question, without having to resort to hacking your response XML. What I really like is that (and I hope you'll agree) it that the code is very readable and you can easily understand what the intention is. I must admit that with your original code, to me it was not very obvious what the intent was.

 

import javax.xml.transform.Source
import org.w3c.dom.Attr
import org.w3c.dom.Node
import org.xmlunit.builder.DiffBuilder
import org.xmlunit.builder.Input
import org.xmlunit.util.Predicate

// Fixed control XML to compare responses too.
def controlXmlText = '''<response>
  <payload>
    <selfcare>
      <subscription id="2306" status="24">
          <charging-method>3</charging-method>
          <duration-code>2</duration-code>
          <rate resource="GBP" tax-rate="0.185">2.37</rate>
        <pricepoint/>
        <purchase-date>2017-04-18T14:12:39+05:30</purchase-date>
        <expiry-date>2017-04-25T23:59:59+05:30</expiry-date>
        <package-id>ReservedPackage</package-id>
       <b2b-partner>
          <id>B2B_Google</id>
        </b2b-partner>
        <partner-id>B2B_Google</partner-id>
      </subscription>
    </selfcare>
  </payload>
</response>'''

// Response XML has differences in the two date elements and the id attributes, which
// are ignored by the filters below, edit other elements and attributes to see the
// assertion below identify other differences.
def responseXmlText = '''<response>
  <payload>
    <selfcare>
      <subscription id="2310" status="24">
          <charging-method>3</charging-method>
          <duration-code>2</duration-code>
          <rate resource="GBP" tax-rate="0.185">2.37</rate>
        <pricepoint/>
        <purchase-date>2017-04-19T14:12:39+06:30</purchase-date>
        <expiry-date>2017-04-26T23:59:59+06:30</expiry-date>
        <package-id>ReservedPackage</package-id>
       <b2b-partner>
          <id>B2B_Google</id>
        </b2b-partner>
        <partner-id>B2B_Google</partner-id>
      </subscription>
    </selfcare>
  </payload>
</response>'''

// Control and response sources, this demo is just from text strings, See:
// http://www.xmlunit.org/api/java/2.3.0/org/xmlunit/builder/Input.html
// For details of all other input source.
def controlXml = Input.from(controlXmlText).build();
def responseXml = Input.from(responseXmlText).build();

def nodeFilter = new Predicate<Node>() {
    public boolean test(Node element) {
        // List of element names to ignore.
        def elementsToIgnore = ['purchase-date', 'expiry-date']
        return !elementsToIgnore.contains(element.getLocalName())
    }
}

def attributeFilter = new Predicate<Attr>() {
    public boolean test(Attr attribute) {
        // List of attributes names to ignore (regardless of element).
        def attributesToIgnore = ['id']
        return !attributesToIgnore.contains(attribute.getLocalName())
    }
}

def diff = DiffBuilder.compare(controlXml)
        .withTest(responseXml)
        .withNodeFilter(nodeFilter)
        .withAttributeFilter(attributeFilter)
        .ignoreComments()
        .ignoreWhitespace()
        .build()

assert !diff.hasDifferences()

 

I was really just investigating XMLUnit for my own interest, but I thought I'd post back here what I found as someone might find it useful. If so here is the user guide and javadocs.

vpachpute1
Frequent Contributor

Hi

 

I really appreciate your efforts for my issue.

 

Thanks a lot. I will try this solution and let you know by this weekend.

 

Thanks

Vishal

cancel
Showing results for 
Search instead for 
Did you mean: