
ext.test4j.hamcrest.xml.HasXPath Maven / Gradle / Ivy
package ext.test4j.hamcrest.xml;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import ext.test4j.hamcrest.Description;
import ext.test4j.hamcrest.Factory;
import ext.test4j.hamcrest.Matcher;
import ext.test4j.hamcrest.TypeSafeDiagnosingMatcher;
import org.w3c.dom.Node;
/**
* Applies a Matcher to a given XML Node in an existing XML Node tree, specified by an XPath expression.
*
* @author Joe Walnes
*/
public class HasXPath extends TypeSafeDiagnosingMatcher {
private final Matcher super String> valueMatcher;
private final XPathExpression compiledXPath;
private final String xpathString;
private final QName evaluationMode;
/**
* @param xPathExpression XPath expression.
* @param valueMatcher Matcher to use at given XPath.
* May be null to specify that the XPath must exist but the value is irrelevant.
*/
public HasXPath(String xPathExpression, Matcher super String> valueMatcher) {
this(xPathExpression, null, valueMatcher);
}
/**
* @param xPathExpression XPath expression.
* @param namespaceContext Resolves XML namespace prefixes in the XPath expression
* @param valueMatcher Matcher to use at given XPath.
* May be null to specify that the XPath must exist but the value is irrelevant.
*/
public HasXPath(String xPathExpression, NamespaceContext namespaceContext, Matcher super String> valueMatcher) {
this(xPathExpression, namespaceContext, valueMatcher, XPathConstants.STRING);
}
private HasXPath(String xPathExpression, NamespaceContext namespaceContext, Matcher super String> valueMatcher, QName mode) {
try {
XPath xPath = XPathFactory.newInstance().newXPath();
if (namespaceContext != null) {
xPath.setNamespaceContext(namespaceContext);
}
compiledXPath = xPath.compile(xPathExpression);
this.xpathString = xPathExpression;
this.valueMatcher = valueMatcher;
this.evaluationMode = mode;
} catch (XPathExpressionException e) {
throw new IllegalArgumentException("Invalid XPath : " + xPathExpression, e);
}
}
@Override
public boolean matchesSafely(Node item, Description mismatchDescription) {
try {
return matchesResult(compiledXPath.evaluate(item, evaluationMode), mismatchDescription);
} catch (XPathExpressionException e) {
return false;
}
}
public void describeTo(Description description) {
description.appendText("an XML document with XPath ").appendText(xpathString);
if (valueMatcher != null) {
description.appendText(" ").appendDescriptionOf(valueMatcher);
}
}
private boolean matchesResult(Object result, Description mismatchDescription) {
if (result == null) {
mismatchDescription.appendText("xpath returned no results.");
return false;
} else if (valueMatcher == null) {
return true;
} else {
boolean valueMatched = valueMatcher.matches(result);
if (!valueMatched) {
mismatchDescription.appendText("xpath result ");
valueMatcher.describeMismatch(result, mismatchDescription);
}
return valueMatched;
}
}
@Factory
public static Matcher hasXPath(String xPath, Matcher super String> valueMatcher) {
return hasXPath(xPath, null, valueMatcher);
}
@Factory
public static Matcher hasXPath(String xPath, NamespaceContext namespaceContext, Matcher super String> valueMatcher) {
return new HasXPath(xPath, namespaceContext, valueMatcher, XPathConstants.STRING);
}
@Factory
public static Matcher hasXPath(String xPath) {
return hasXPath(xPath, (NamespaceContext) null);
}
@Factory
public static Matcher hasXPath(String xPath, NamespaceContext namespaceContext) {
return new HasXPath(xPath, namespaceContext, null, XPathConstants.NODE);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy