0

I am trying to compare two xml only partially using XMLUnit2. I tried below Xpath to compare element int alone. But my test is failed because, it is checking boolean tag as well.

How do I make this test pass?

@Test
    public void diff_through_xPath(){
        String myControlXML = "<struct><boolean>false</boolean><int>3</int></struct>";
        String myTestXML = "<struct><boolean>true</boolean><int>3</int></struct>";

        ElementSelector childSelector = selectorForElementNamed("int", byXPath("//int", byName));

        Diff myDiffSimilar = DiffBuilder.compare(myControlXML).withTest(myTestXML)
                .withNodeMatcher(new DefaultNodeMatcher(childSelector, byName))
                .checkForSimilar()
                .ignoreWhitespace()
                .build();

        assertFalse("XML similar " + myDiffSimilar.toString(),
                myDiffSimilar.hasDifferences());


    }

Edit: With NodeFilter, I removed the unwanted nodes from comparison. But is there a way to give Xpath, and compare only the nodes evaluated by XPath.

@Test
    public void diff_through_xPath() {
        String myControlXML = "<struct><boolean>false</boolean><int>3</int></struct>";
        String myTestXML = "<struct><boolean>true</boolean><int>3</int></struct>";

        Diff myDiffSimilar = DiffBuilder.compare(myControlXML).withTest(myTestXML)
                .withNodeFilter(new Predicate<Node>() {
                    public boolean test(Node node) {
                        return !node.getNodeName().equals("boolean"); //ignores all child nodes from of 'a'.
                    }
                })
                //.checkForSimilar()
                .ignoreWhitespace()
                .build();

        assertFalse("XML similar " + myDiffSimilar.toString(),
                myDiffSimilar.hasDifferences());


    }
Manoj
  • 5,707
  • 19
  • 56
  • 86
  • I'm not sure I understand what you want to compare. Do you want to compare the `struct`s at all or just the `int`s? `NodeMatcher` is used to decide which nodes of a set of siblings to compare with each other, it doesn't have any effect on which nodes are eligible for comparison at all. You'd use `NodeFilter` to strip out those you don't want. – Stefan Bodewig Sep 25 '17 at 16:05
  • I want to compare just 'int' tag in both xml. I don't care whether Boolean tag matches or not. – Manoj Sep 25 '17 at 20:59
  • As I have edited, I could use Nodefilter to remove unwanted nodes. Is there a way to use Xpath and compare? – Manoj Sep 26 '17 at 06:14

1 Answers1

0

I don't know whether this is the right approach. But posted here anyway to get comments from you. In this way, I can only compare the XPath evaluated XML node list.

@Test
    public void testXpath() throws Exception {

        File controlFile = new File("src/test/resources/myControlXML.xml");
        File testFile = new File("src/test/resources/myTest.xml");


        Diff myDiff = DiffBuilder.compare(Input.fromDocument(getDocument("src/test/resources/myControlXML.xml", "/struct/int")))
                .withTest(Input.fromDocument(getDocument("src/test/resources/myTest.xml", "/struct/int")))
                .checkForSimilar().withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byName))
                .ignoreWhitespace()
                .build();

        assertFalse("XML similar " + myDiff.toString(),
                myDiff.hasDifferences());
    }

    public Document getDocument(String fileName, String xpathExpression) throws Exception {
        File controlFile = new File(fileName);
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder;

        dBuilder = dbFactory.newDocumentBuilder();

        Document controlDoc = dBuilder.parse(controlFile);
        controlDoc.getDocumentElement().normalize();

        XPath xPath = XPathFactory.newInstance().newXPath();

        NodeList nodes = (NodeList) xPath.compile(xpathExpression).evaluate(
                controlDoc, XPathConstants.NODESET);

        Document newXmlDocument = DocumentBuilderFactory.newInstance()
                .newDocumentBuilder().newDocument();
        Element root = newXmlDocument.createElement("root");
        newXmlDocument.appendChild(root);
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            Node copyNode = newXmlDocument.importNode(node, true);
            root.appendChild(copyNode);
        }

        return newXmlDocument;
    }
Manoj
  • 5,707
  • 19
  • 56
  • 86
  • You could have saved a few lines by using XMLUnit's [XPath abstractions](https://github.com/xmlunit/user-guide/wiki/XPath-Support) but yes, this is probably the best way to do it right now. In future releases the `Input` builder could probably be modified to accept a `NodeList` as source or even a `Source` and an XPath expression to perform the same tasks under the covers. – Stefan Bodewig Sep 26 '17 at 16:13