All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xmlunit.matchers.HasXPathMatcher Maven / Gradle / Ivy

package org.xmlunit.matchers;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Factory;
import org.hamcrest.Matcher;
import org.w3c.dom.Node;
import org.xmlunit.builder.Input;
import org.xmlunit.util.Convert;
import org.xmlunit.xpath.JAXPXPathEngine;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import java.util.Map;

/**
 * This Hamcrest {@link Matcher} verifies whether the provided XPath expression corresponds to at least
 * one element in the provided object.
 *
 * 

All types which are supported by {@link Input#from(Object)} can be used as input for the object * against the matcher is evaluated.

* *

Simple Example

* *
 * final String xml = "<a><b attr=\"abc\"></b></a>";
 *
 * assertThat(xml, hasXPath("//a/b/@attr"));
 * assertThat(xml, not(hasXPath("//a/b/c")));
 * 
* *

Example with namespace mapping

* *
 *    String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
 *          "<feed xmlns=\"http://www.w3.org/2005/Atom\">" +
 *          "   <title>title</title>" +
 *          "   <entry>" +
 *          "       <title>title1</title>" +
 *          "       <id>id1</id>" +
 *          "   </entry>" +
 *          "</feed>";
 *
 *    HashMap<String, String> prefix2Uri = new HashMap<String, String>();
 *    prefix2Uri.put("atom", "http://www.w3.org/2005/Atom");
 *    assertThat(xmlRootElement,
 *          hasXPath("//atom:feed/atom:entry/atom:id").withNamespaceContext(prefix2Uri));
 * 
* * @since XMLUnit 2.1.0 */ public class HasXPathMatcher extends BaseMatcher { private String xPath; private DocumentBuilderFactory dbf; private Map prefix2Uri; /** * Creates a {@link HasXPathMatcher} instance with the associated XPath expression. * * @param xPath xPath expression */ public HasXPathMatcher(String xPath) { this.xPath = xPath; } /** * Sets the {@link DocumentBuilderFactory} to use when creating a * {@link org.w3c.dom.Document} from the XML input. * * @since XMLUnit 2.6.0 */ public HasXPathMatcher withDocumentBuilderFactory(DocumentBuilderFactory f) { dbf = f; return this; } @Override public boolean matches(Object object) { JAXPXPathEngine engine = new JAXPXPathEngine(); if (prefix2Uri != null) { engine.setNamespaceContext(prefix2Uri); } Source s = Input.from(object).build(); Node n = dbf != null ? Convert.toNode(s, dbf) : Convert.toNode(s); Iterable nodes = engine.selectNodes(xPath, n); return nodes.iterator().hasNext(); } @Override public void describeTo(Description description) { description.appendText("XML with XPath ").appendText(xPath); } @Override public void describeMismatch(Object item, Description mismatchDescription) { mismatchDescription.appendText("XPath returned no results."); } /** * Creates a matcher that matches when the examined XML input has at least one node * corresponding to the specified xPath. * *

For example:

*
assertThat(xml, hasXPath("/root/cars[0]/audi"))
* * @param xPath the target xpath * @return the xpath matcher */ @Factory public static HasXPathMatcher hasXPath(String xPath) { return new HasXPathMatcher(xPath); } /** * Utility method used for creating a namespace context mapping to be used in XPath matching. * * @param prefix2Uri prefix2Uri maps from prefix to namespace URI. It is used to resolve * XML namespace prefixes in the XPath expression */ public HasXPathMatcher withNamespaceContext(Map prefix2Uri) { this.prefix2Uri = prefix2Uri; return this; } }