Skip to content

Commit 65b1166

Browse files
author
neildunn
committed
Integrated XML namespace support for XPath matcher
1 parent 873014e commit 65b1166

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

hamcrest-library/src/main/java/org/hamcrest/xml/HasXPath.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.hamcrest.TypeSafeMatcher;
77
import org.w3c.dom.Node;
88

9+
import javax.xml.namespace.NamespaceContext;
910
import javax.xml.xpath.XPath;
1011
import javax.xml.xpath.XPathConstants;
1112
import javax.xml.xpath.XPathExpression;
@@ -29,8 +30,22 @@ public class HasXPath extends TypeSafeMatcher<Node> {
2930
* May be null to specify that the XPath must exist but the value is irrelevant.
3031
*/
3132
public HasXPath(String xPathExpression, Matcher<String> valueMatcher) {
33+
this(xPathExpression, null, valueMatcher);
34+
}
35+
36+
/**
37+
* @param xPathExpression XPath expression.
38+
* @param namespaceContext Resolves XML namespace prefixes in the XPath expression
39+
* @param valueMatcher Matcher to use at given XPath.
40+
* May be null to specify that the XPath must exist but the value is irrelevant.
41+
*/
42+
public HasXPath(String xPathExpression, NamespaceContext namespaceContext, Matcher<String> valueMatcher) {
3243
try {
3344
XPath xPath = XPathFactory.newInstance().newXPath();
45+
if (namespaceContext != null)
46+
{
47+
xPath.setNamespaceContext(namespaceContext);
48+
}
3449
compiledXPath = xPath.compile(xPathExpression);
3550
this.xpathString = xPathExpression;
3651
this.valueMatcher = valueMatcher;
@@ -63,12 +78,21 @@ public void describeTo(Description description) {
6378

6479
@Factory
6580
public static Matcher<Node> hasXPath(String xPath, Matcher<String> valueMatcher) {
66-
return new HasXPath(xPath, valueMatcher);
81+
return hasXPath(xPath, null, valueMatcher);
82+
}
83+
84+
@Factory
85+
public static Matcher<Node> hasXPath(String xPath, NamespaceContext namespaceContext, Matcher<String> valueMatcher) {
86+
return new HasXPath(xPath, namespaceContext, valueMatcher);
6787
}
6888

6989
@Factory
7090
public static Matcher<Node> hasXPath(String xPath) {
71-
return hasXPath(xPath, null);
91+
return hasXPath(xPath, null, null);
7292
}
7393

94+
@Factory
95+
public static Matcher<Node> hasXPath(String xPath, NamespaceContext namespaceContext) {
96+
return hasXPath(xPath, namespaceContext, null);
97+
}
7498
}

hamcrest-unit-test/src/main/java/org/hamcrest/xml/HasXPathTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
import static org.hamcrest.xml.HasXPath.hasXPath;
1010
import org.w3c.dom.Document;
1111

12+
import javax.xml.namespace.NamespaceContext;
1213
import javax.xml.parsers.DocumentBuilder;
1314
import javax.xml.parsers.DocumentBuilderFactory;
1415
import java.io.ByteArrayInputStream;
16+
import java.util.HashSet;
17+
import java.util.Iterator;
1518

1619
/**
1720
* @author Joe Walnes
@@ -25,6 +28,7 @@ protected void setUp() throws Exception {
2528
+ "<root type='food'>\n"
2629
+ " <something id='a'><cheese>Edam</cheese></something>\n"
2730
+ " <something id='b'><cheese>Cheddar</cheese></something>\n"
31+
+ " <f:foreignSomething xmlns:f=\"http://cheese.com\" milk=\"camel\">Caravane</f:foreignSomething>\n"
2832
+ "</root>\n"
2933
);
3034
}
@@ -47,6 +51,31 @@ public void testFailsIfNodeIsMissing() throws Exception {
4751
assertThat(xml, not(hasXPath("//something[@id='c']/cheese")));
4852
}
4953

54+
public void testMatchesWithNamespace() throws Exception {
55+
NamespaceContext ns = new NamespaceContext() {
56+
public String getNamespaceURI(String prefix) {
57+
return ("cheese".equals(prefix) ? "http://cheese.com" : null);
58+
}
59+
60+
public String getPrefix(String namespaceURI) {
61+
return ("http://cheese.com".equals(namespaceURI) ? "cheese" : null);
62+
}
63+
64+
public Iterator getPrefixes(String namespaceURI) {
65+
HashSet<String> prefixes = new HashSet<String>();
66+
String prefix = getPrefix(namespaceURI);
67+
if (prefix != null) {
68+
prefixes.add(prefix);
69+
}
70+
return prefixes.iterator();
71+
}
72+
};
73+
74+
assertThat(xml, hasXPath("//cheese:foreignSomething", ns));
75+
assertThat(xml, hasXPath("//cheese:foreignSomething/@milk", ns, equalTo("camel")));
76+
assertThat(xml, hasXPath("//cheese:foreignSomething/text()", ns, equalTo("Caravane")));
77+
}
78+
5079
public void testThrowsIllegalArgumentExceptionIfGivenIllegalExpression() {
5180
try {
5281
hasXPath("\\g:dfgd::DSgf/root/something[2]/cheese", equalTo("blah"));
@@ -65,6 +94,7 @@ public void testDescribesItself() throws Exception {
6594

6695
private Document parse(String xml) throws Exception {
6796
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
97+
documentBuilderFactory.setNamespaceAware(true);
6898
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
6999
return documentBuilder.parse(new ByteArrayInputStream(xml.getBytes()));
70100
}

0 commit comments

Comments
 (0)