1 package org.hamcrest.xml; 2 3 import org.hamcrest.Description; 4 import org.hamcrest.Factory; 5 import org.hamcrest.Matcher; 6 import org.hamcrest.TypeSafeMatcher; 7 import org.w3c.dom.Node; 8 9 import javax.xml.xpath.XPath; 10 import javax.xml.xpath.XPathConstants; 11 import javax.xml.xpath.XPathExpression; 12 import javax.xml.xpath.XPathExpressionException; 13 import javax.xml.xpath.XPathFactory; 14 15 /** 16 * Applies a Matcher to a given XML Node in an existing XML Node tree, specified by an XPath expression. 17 * 18 * @author Joe Walnes 19 */ 20 public class HasXPath extends TypeSafeMatcher<Node> { 21 22 private final Matcher<String> valueMatcher; 23 private final XPathExpression compiledXPath; 24 private final String xpathString; 25 26 /** 27 * @param xPathExpression XPath expression. 28 * @param valueMatcher Matcher to use at given XPath. 29 * May be null to specify that the XPath must exist but the value is irrelevant. 30 */ HasXPath(String xPathExpression, Matcher<String> valueMatcher)31 public HasXPath(String xPathExpression, Matcher<String> valueMatcher) { 32 try { 33 XPath xPath = XPathFactory.newInstance().newXPath(); 34 compiledXPath = xPath.compile(xPathExpression); 35 this.xpathString = xPathExpression; 36 this.valueMatcher = valueMatcher; 37 } catch (XPathExpressionException e) { 38 throw new IllegalArgumentException("Invalid XPath : " + xPathExpression, e); 39 } 40 } 41 matchesSafely(Node item)42 public boolean matchesSafely(Node item) { 43 try { 44 String result = (String) compiledXPath.evaluate(item, XPathConstants.STRING); 45 if (result == null) { 46 return false; 47 } else if (valueMatcher == null) { 48 return !result.equals(""); 49 } else { 50 return valueMatcher.matches(result); 51 } 52 } catch (XPathExpressionException e) { 53 return false; 54 } 55 } 56 describeTo(Description description)57 public void describeTo(Description description) { 58 description.appendText("an XML document with XPath ").appendText(xpathString); 59 if (valueMatcher != null) { 60 description.appendText(" ").appendDescriptionOf(valueMatcher); 61 } 62 } 63 64 @Factory hasXPath(String xPath, Matcher<String> valueMatcher)65 public static Matcher<Node> hasXPath(String xPath, Matcher<String> valueMatcher) { 66 return new HasXPath(xPath, valueMatcher); 67 } 68 69 @Factory hasXPath(String xPath)70 public static Matcher<Node> hasXPath(String xPath) { 71 return hasXPath(xPath, null); 72 } 73 74 } 75