5. XPath Tests
Prev |  | Next

## 5. XPath Tests

### 5.1. XPath Engines

Central to XMLUnit's XPath support is the `XpathEngine` interface which consists of only three methods:

        /**
         * Execute the specified xpath syntax <code>select</code> expression
         * on the specified document and return the list of nodes (could have
         * length zero) that match
         * @param select
         * @param document
         * @return list of matching nodes
         */
        NodeList getMatchingNodes(String select, Document document)
            throws XpathException;

        /**
         * Evaluate the result of executing the specified XPath syntax
         * <code>select</code> expression on the specified document
         * @param select
         * @param document
         * @return evaluated result
         */
        String evaluate(String select, Document document)
            throws XpathException;

        /**
         * Establish a namespace context.
         */
        void setNamespaceContext(NamespaceContext ctx);

The first two methods expect an XPath expression that selects content from the DOM document that is the second argument. The result of the selection can be either a DOM `NodeList` or a `String`. The later form tries to flatten the result, the value is said to be "String-ified".

The third method is part of XMLUnit's support for XML Namespaces in XPath expressions. See Section 5.2, “Using XML Namespaces in XPath Selectors” for more details.

There are two implementations of the interface, `org.custommonkey.xmlunit.SimpleXpathEngine` and `org.custommonkey.xmlunit.jaxp13.Jaxp13XpathEngine`. The first implementation is the only one available in XMLUnit 1.0 and uses the configured JAXP XSLT transformer. The second is new to XMLUnit 1.1 and only available if JAXP 1.3 or later is supported, which should be the case for Java 5 and later.

`XpathException` is an `Exception` that will be thrown for invalid XPath expressions or other problems with the underlying XPath engine. It will typically wrap a `javax.xml.xpath.XPathExpressionException` in the `Jaxp13XpathEngine` case or a `javax.xml.transform.TransformerException` when `SimpleXpathEngine` is used.

The `XMLUnit.newXpathEngine` method will first try to create an instance of `Jaxp13XpathEngine` and fall back to `SimpleXpathEngine` if JAXP 1.3 is not supported.

One example of using the XPath support is included inside it `org.custommonkey.xmlunit.examples` package. It asserts that the string-ified form of an XPath selection matches a regular expression. The code needed for this is:

Example 31. Matching an XPath Selection Against a Regular Expression

        XpathEngine engine = XMLUnit.newXpathEngine();
        String value = engine.evaluate(xpath, doc);
        Assert.assertTrue(message, value.matches(regex));

### 5.2. Using XML Namespaces in XPath Selectors

Starting with XMLUnit 1.1 XML Namespaces are supported for XPath queries.

The `NamespaceContext` interface provides a mapping from prefix to namespace URI and is used by the XPath engine. XPath selections then use the mapping's prefixes where needed. Note that a prefix used in the document under test and a prefix given as part of the `NamespaceContext` are not related at all; the context only applies to the XPath expression, the prefix used in the document is ignored completely.

Right now XMLUnit provides only a single implementation of the `NamespaceContext` interface: `SimpleNamespaceContext`. This implementation expects a `java.util.Map` as its constructor argument. The `Map` must contain (`String`) prefixes as keys and (`String`) namespace URIs as values.

Note there is nothing like a default namespace in XPath selectors. If you are using namespaces in your XPath, all namespaces need a prefix (of length greater than zero). This is independent of the prefixes used in your document.

The following example is taken from XMLUnit's own tests. It demonstrates that the namespace prefix of the document under test is irrelevant and shows how to set up the namespace context.

Example 32. Using Namespaces in XPath Tests

        String testDoc = "<t:test xmlns:t=\"urn:foo\"><t:bar/></t:test>";
        Document d = XMLUnit.buildControlDocument(testDoc);
        HashMap m = new HashMap();
        m.put("foo", "urn:foo");

        NamespaceContext ctx = new SimpleNamespaceContext(m);
        XpathEngine engine = XMLUnit.newXpathEngine();
        engine.setNamespaceContext(ctx);

        NodeList l = engine.getMatchingNodes("//foo:bar", d);
        assertEquals(1, l.getLength());
        assertEquals(Node.ELEMENT_NODE, l.item(0).getNodeType());

In some cases the "stringified" value of an XPath evaluation is a qualified name - a string that encodes a namespace URI together with a local name. There are two common formats for such qualified names, one used by Java5's `QName` in the format `{NS-URI}LOCAL-NAME` and one using `PREFIX:LOCAL-NAME`. Starting with XMLUnit 1.6 a new `QualifiedName` class can parse either representation. The `assertXpathEvaluatesTo` overloads where the expected value is a `QualifiedName` try to parse the stringified value in either format - using the documents namespace context when parsing the actual value.

It is possible to set a global `NamespaceContext`, see Section 5.4, “Configuration Options” for details.

### 5.3. JUnit 3.x Convenience Methods

`XMLTestCase` and `XMLAssert` provide several overloads for the following common types of assertions:

- Two XPath expression should return the same DOM `NodeList` as result: `assertXpathsEqual`. There are methods that use two different expressions on the same document and others that compare expressions selecting from two different documents.

  The `NodeList`s are wrapped into a surrogate root XML element and the resulting DOM `Document`s are compared using `Diff.similar()`.

- The opposite of the above, the expressions should yield different results: `assertXpathsNotEqual`.
- Two XPath expression should return the same "String-ified" result: `assertXpathValuesEqual`. There are methods that use two different expressions on the same document and others that compare expressions selecting from two different documents.
- The opposite of the above, the expressions should yield different results: `assertXpathValuesNotEqual`.
- The XPath expression should return an expected value when "String-ified" or interpreted as qualified name: `assertXpathEvaluatesTo`.
- The `NodeList` selected by an XPath expression is not empty: `assertXpathExists`.
- The `NodeList` selected by an XPath expression is empty: `assertXpathNotExists`.

Neither method provides any control over the message of the `AssertionFailedError` in case of a failure.

### 5.4. Configuration Options

When using `XpathEngine` directly you are responsible for creating the DOM document yourself. If you use the convenience methods of `XMLTestCase` or `XMLAssert` you have several options to specify the input; XMLUnit will use the control or test parser that has been configured (see Section 2.4.1, “JAXP”) to create a DOM document from the given piece of XML in that case - using the configured `EntityResolver`(s) (see Section 2.4.2, “`EntityResolver`”) if any.

If JAXP 1.3 is not available, `SimpleXpathEngine` will use the configured JAXP XSLT transformer (see Section 2.4.1, “JAXP”) under the covers.

When using JAXP 1.3 you can chose the actual `XPathFactory` implementation using `XMLUnit.setXPathFactory`.

It is possible to establish a global `NamespaceContext` with the help of the `XMLUnit.setXpathNamespaceContext` method. Any `XpathEngine` created by `XMLUnit.newXpathEngine` will automatically use the given context. Note that the JUnit 3 convenience methods use `XMLUnit.newXpathEngine` implicitly and will thus use the configured `NamespaceContext`.

Prev |  | Next
4. Validating XML Documents | Home | 6. DOM Tree Walking