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

org.xmlunit.matchers.EvaluateXPathMatcher 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 evaluation of the provided XPath expression
 * corresponds to the value matcher specified for the provided input XML object.
 *
 * 

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

* *

Simple Example

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

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(xml,
 *          hasXPath("//atom:feed/atom:entry/atom:id/text()", equalTo("id1"))
 *          .withNamespaceContext(prefix2Uri));
 * 
* * @since XMLUnit 2.1.0 */ public class EvaluateXPathMatcher extends BaseMatcher { private final String xPath; private final Matcher valueMatcher; private DocumentBuilderFactory dbf; private Map prefix2Uri; /** * Creates a {@link EvaluateXPathMatcher} instance with the associated XPath expression and * the value matcher corresponding to the XPath evaluation. * * @param xPath xPath expression * @param valueMatcher matcher for the value at the specified xpath */ public EvaluateXPathMatcher(String xPath, Matcher valueMatcher) { this.xPath = xPath; this.valueMatcher = valueMatcher; } /** * Creates a matcher that matches when the examined XML input has a value at the * specified xPath that satisfies the specified valueMatcher. * *

For example:

*
assertThat(xml, hasXPath("//fruits/fruit/@name", equalTo("apple"))
* * @param xPath the target xpath * @param valueMatcher matcher for the value at the specified xpath * @return the xpath matcher */ @Factory public static EvaluateXPathMatcher hasXPath(String xPath, Matcher valueMatcher) { return new EvaluateXPathMatcher(xPath, valueMatcher); } /** * Sets the {@link DocumentBuilderFactory} to use when creating a * {@link org.w3c.dom.Document} from the XML input. * * @since XMLUnit 2.6.0 */ public EvaluateXPathMatcher withDocumentBuilderFactory(DocumentBuilderFactory f) { dbf = f; return this; } @Override public boolean matches(Object object) { String value = xPathEvaluate(object); return valueMatcher.matches(value); } @Override public void describeTo(Description description) { description.appendText("XML with XPath ").appendText(xPath); if (valueMatcher != null) { description.appendText(" evaluated to ").appendDescriptionOf(valueMatcher); } } @Override public void describeMismatch(Object object, Description mismatchDescription) { if (valueMatcher != null) { String value = xPathEvaluate(object); valueMatcher.describeMismatch(value, mismatchDescription); } } /** * 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 EvaluateXPathMatcher withNamespaceContext(Map prefix2Uri) { this.prefix2Uri = prefix2Uri; return this; } /** * Evaluates the provided XML input to the configured xPath field XPath expression. * @param input an XML input * @return the result of the XPath evaluation */ private String xPathEvaluate(Object input) { JAXPXPathEngine engine = new JAXPXPathEngine(); if (prefix2Uri != null) { engine.setNamespaceContext(prefix2Uri); } Source s = Input.from(input).build(); Node n = dbf != null ? Convert.toNode(s, dbf) : Convert.toNode(s); return engine.evaluate(xPath, n); } }