Home | History | Annotate | Download | only in xml
      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      */
     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 
     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 
     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
     65     public static Matcher<Node> hasXPath(String xPath, Matcher<String> valueMatcher) {
     66         return new HasXPath(xPath, valueMatcher);
     67     }
     68 
     69     @Factory
     70     public static Matcher<Node> hasXPath(String xPath) {
     71         return hasXPath(xPath, null);
     72     }
     73 
     74 }
     75