From: Lanam, J. <jef...@hp...> - 2010-08-20 22:26:57
|
From: James Abley [mailto:jam...@gm...] Sent: Friday, August 20, 2010 3:34 AM To: Lanam, Jeff Cc: xml...@li... Subject: Re: [Xmlunit-general] Comparing XPath expressions in DifferenceEngine On 20 August 2010 01:31, Lanam, Jeff <jef...@hp...<mailto:jef...@hp...>> wrote: I’m trying to write a DifferenceEngine for XMLUnit 1.3 that will allow or reject differences based on a list of elements specified by the user. I have a simple one working which just compares the element names, but I would like to use XPath expressions for more precise specification. The problem I have is that the Difference.getTestNodeDetail().getXpathLocation() method returns a non-abbreviated expression, but I want the user to be able to use abbreviated syntax. Is there a way to compare two XPath expressions, using the control document as a reference, and determine if they are referencing the same element? XPath is new to me, and I haven’t done much with XSLT or Java XML APIs. Thanks for any help. Jeff Lanam Hewlett-Packard Hi Jeff, Can you supply a test which indicates what you're trying to do? Cheers, James ---------------------------------- Thanks for responding, James. Here’s a test that shows what I want: @Test public void test_DuplicateName() throws XpathException, SAXException, IOException { String control = "<mydoc><child name=\"Tom\"><city>Chicago</city></child>" + "<child name=\"Dick\"><city>Memphis</city></child>" + "</mydoc>"; String data = "<mydoc><child name=\"Tom\"><city>Cleveland</city></child>" + "<child name=\"Dick\"><city>Memphis</city></child>" + "</mydoc>"; XPathInclusionDifferenceListener dl = new XPathInclusionDifferenceListener( new String[]{"//child[@name='Dick']/city"}, control); Diff diff = new Diff(control, data); diff.overrideDifferenceListener(dl); assertXMLEqual("compare Dick's city", diff, true); } The DifferenceListener method differenceFound should determine if the XPath location of the difference it’s passed is contained in the array of XPath references passed to the constructor. If it is, then differenceFound should return RETURN_ACCEPT_DIFFERENCE. Otherwise, it should return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL. The code below shows what I’m trying to implement. The missing piece is the method expandXPathReference. Alternatively, I could use a method that compares an abbreviated reference like the one above, with an expanded one. In the example above, getXPathLocation returns “/mydoc[1]/child[1]/city[1]/text()[1]”. I need a way to determine that this is equivalent to "//child[@name='Dick']/city". public class XPathInclusionDifferenceListener implements DifferenceListener { Document document_ = null; Set<String> includedElements_ = new HashSet<String>(); static XpathEngine engine_ = XMLUnit.newXpathEngine(); public XPathInclusionDifferenceListener(String includedElements[], String docString) throws XpathException, SAXException, IOException { super(); document_ = XMLUnit.buildControlDocument(docString);; setIncludedElements(includedElements); } /* (non-Javadoc) * @see org.custommonkey.xmlunit.DifferenceListener#differenceFound(org.custommonkey.xmlunit.Difference) */ @Override public int differenceFound(Difference difference) { String nodeName = difference.getTestNodeDetail().getXpathLocation(); String expanded = null; try { expanded = expandXPathReference(nodeName, document_); } catch (XpathException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(includedElements_.contains(expanded)) { return DifferenceListener.RETURN_ACCEPT_DIFFERENCE; } return DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL; } /* (non-Javadoc) * @see org.custommonkey.xmlunit.DifferenceListener#skippedComparison(org.w3c.dom.Node, org.w3c.dom.Node) */ @Override public void skippedComparison(Node control, Node test) { // TODO Auto-generated method stub } /** * @return the collection of strings that specifies which elements are significant */ public Collection<String> getIncludedElements() { return includedElements_; } /** * Sets the collection of strings that specifies which elements are significant. * @param elements an array of strings which must be XML element names * @throws XpathException */ public void setIncludedElements(String elements[]) throws XpathException { for (String e : elements) { includedElements_.add(expandXPathReference(e, document_)); } } private String expandXPathReference(String e, Document document) throws XpathException { // TODO Replace e with the fully expanded XPath reference return e; } } |