-
Notifications
You must be signed in to change notification settings - Fork 8
XPath Support
The (I)XPathEngine
interface inside the xpath/XPath
package/namespace provides two pairs of methods that apply an XPath
expression to a piece of XML and return the result as a string or
collection of DOM nodes.
The first pair expects the "piece of XML" to be provided as
(I)Source
like
most other code in XMLUnit as well, the
second pair directly works on DOM nodes. Initially only the
Source
-arg versions existed, but the underlying implementations can
work efficiently on nodes directly, so the overloads have been added.
For Java as well as .NET only a single implementation of the
XPathEngine
interface exists - they use javax.xml.xpath
and
System.Xml.XPath
under the covers directly. In the Java case all
checked exceptions will be
transformed to runtime exceptions.
In order to use namespace prefixes inside the XPath expressions you need to provide a NamespaceContext.
Selecting nodes:
Iterable<Node> i = new JAXPXPathEngine().selectNodes("//li", source);
assertNotNull(i);
int count = 0;
for (Iterator<Node> it = i.iterator(); it.hasNext(); ) {
count++;
assertEquals("li", it.next().getNodeName());
}
assertEquals(4, count);
in Java. For .NET it would be
IEnumerable<XmlNode> i = new XPathEngine().SelectNodes("//li", source);
Assert.IsNotNull(i);
int count = 0;
foreach (XmlNode n in i) {
count++;
Assert.AreEqual("li", n.Name);
}
Assert.AreEqual(4, count);
Evaluating an XPath to a string:
assertEquals("Don't blame it on the...",
new JAXPXPathEngine().evaluate("//title", source));
in Java. For .NET it would be
Assert.AreEqual("Don't blame it on the...",
new XPathEngine().Evaluate("//title", source));
XMLUnit for Java provides a Hamcrest macher named HasXPathMatcher
and XMLUnit.NET NUnit
(2.x and 3.x) constraints HasXPathConstraint
that
can be used to verify if a XPath expression corresponds to at least one
element in the provided XML input.
The Java Hamcrest matcher can be used in the following manner :
import static org.xmlunit.matchers.HasXPathMatcher.hasXPath;
import static org.hamcrest.core.IsNot.not;
...
final String xml = "<a><b attr=\"abc\"></b></a>";
assertThat(xml, hasXPath("//a/b/@attr"));
assertThat(xml, not(hasXPath("//a/b/c")));
The corresponding .NET code would be
string xml = "<a><b attr=\"abc\"></b></a>";
Assert.That(xml, HasXpathConstraint.HasXPath("//a/b/@attr"));
Assert.That(xml, !HasXpathConstraint.HasXPath("//a/b/c"));
The matcher and constraints also provide XML NamespaceContext support using the withNamespaceContext
method :
import static org.xmlunit.matchers.HasXPathMatcher.hasXPath;
...
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(xmlRootElement,
hasXPath("//atom:feed/atom:entry/atom:id").withNamespaceContext(prefix2Uri));
XMLUnit for Java provides a Hamcrest macher named EvaluateXPathMatcher
and XMLUnit.NET NUnit (2.x and 3.x) constraints EvaluateXPathConstraint
that
can be used to verify if the evaluation of the provided XPath expression
corresponds to the value matcher specified for the provided input XML object.
The Java Hamcrest matcher can be used in the following manner :
import static org.xmlunit.matchers.EvaluateXPathMatcher.hasXPath;
import static org.hamcrest.CoreMatchers.equalTo;
...
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")));
The corresponding .NET code would be
string xml = "<a><b attr=\"abc\"></b></a>";
Assert.That(xml, EvaluateXPathConstraint.HasXPath("//a/b/@attr", Is.EqualTo("abc")));
Assert.That(xml, EvaluateXPathConstraint.HasXPath("count(//a/b/c)", Is.EqualTo("0")));
The matcher and constraints also provide XML NamespaceContext support using the withNamespaceContext
method :
import static org.xmlunit.matchers.EvaluateXPathMatcher.hasXPath;
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(xmlRootElement,
hasXPath("//atom:feed/atom:entry/atom:id/text()", equalTo("id1"))
.withNamespaceContext(prefix2Uri));
XMLUnit for Java 7+ provides an AssertJ assert classes named MultipleNodeAssert
and SingleNodeAssert
that can be used to verify if a XPath expression corresponds to at least one element in the provided XML input
and perform assertions on those elements.
Access to MultipleNodeAssert is provided by XmlAssert.nodesByXPath(XPath)
.
Using first()
, last()
, element()
on MultipleNodeAssert navigates to corresponding element node
and allow to perform assertions provided by SingleNodeAssert.
import static org.xmlunit.assertj.XmlAssert.assertThat;
...
final String xml = "<a><b attr=\"abc\"></b></a>";
assertThat(xml).nodesByXPath("//a/b/@attr") // MultipleNodeAssert type
.exist();
assertThat(xml).hasXPath("//a/b/@attr");
assertThat(xml).nodesByXPath("//a/b/c") // MultipleNodeAssert type
.doNotExist();
assertThat(xml).doesNotHaveXPath("//a/b/c");
import static org.xmlunit.assertj.XmlAssert.assertThat;
final 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>";
final Map<String, String> prefix2Uri = new HashMap<String, String>();
prefix2Uri.put("atom", "http://www.w3.org/2005/Atom");
assertThat(xml)
.withNamespaceContext(prefix2Uri)
.hasXPath("//atom:feed/atom:entry/atom:id");
import static org.xmlunit.assertj.XmlAssert.assertThat;
final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<feed>" +
" <title>title</title>" +
" <entry attr=\"abc\" attr2=\"value\" foo=\"bar\">" +
" <title>title1</title>" +
" </entry>" +
" <entry attr=\"xyz\" attr2=\"value\">" +
" <title>title1</title>" +
" </entry>" +
"</feed>";
assertThat(xml).nodesByXPath("/feed/entry")
.haveAttribute("attr")
.haveAttribute("attr2", "value");
assertThat(xml).nodesByXPath("/feed/entry") // MultipleNodeAssert type
.first() // SingleNodeAssert type
.hasAttribute("foo");
assertThat(xml).nodesByXPath("/feed/entry") // MultipleNodeAssert type
.last() // SingleNodeAssert type
.doesNotHaveAttribute("foo");
assertThat(xml).nodesByXPath("/feed/entry") // MultipleNodeAssert type
.element(1) // SingleNodeAssert type
.doesNotHaveAttribute("foo");
XMLUnit for Java 7+ provides an AssertJ assert class named ValueAssert
that can be used to verify if the evaluation of the provided XPath expression
meets certain conditions.
Access to MultipleNodeAssert is provided by XmlAssert.valueByXPath(XPath)
.
import static org.xmlunit.assertj.XmlAssert.assertThat;
final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<fruits>" +
" <fruit name=\"apple\"/>" +
" <fruit name=\"orange\"/>" +
" <fruit name=\"banana\"/>" +
"</fruits>";
assertThat(xml).valueByXPath("count(//fruits/fruit)").isEqualTo("3");
assertThat(xml).valueByXPath("count(//fruits/fruit)").isEqualTo(3);
assertThat(xml).valueByXPath("count(//fruits/fruit[@name=\"orange\"])").isEqualTo(1);
assertThat(xml).valueByXPath("count(//fruits/fruit[@name=\"apricot\"])").isEqualTo(0);
assertThat(xml).valueByXPath("count(//fruits/fruit)") // ValueAssert type
.asInt() // org.assertj.core.api.AbstractIntegerAssert type
.isEqualTo(3)
.isGreaterThan(2);
final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<fruits>" +
" <fruit name=\"apple\" weight=\"66.6\"/>" +
"</fruits>";
assertThat(xml).valueByXPath("//fruits/fruit/@weight") // ValueAssert type
.asDouble() // org.assertj.core.api.AbstractDoubleAssert type
.isEqualTo(66.6)
.isPositive();
final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<fruits>" +
" <fruit name=\"apple\" fresh=\"True\"/>" +
" <fruit name=\"pear\" fresh=\"0\"/>" +
"</fruits>";
assertThat(xml).valueByXPath("//fruits/fruit[@name=\"apple\"]/@fresh") // ValueAssert type
.asBoolean() // org.assertj.core.api.AbstractBooleanAssert type
.isTrue();
assertThat(xml).valueByXPath("//fruits/fruit[@name=\"pear\"]/@fresh").asBoolean().isFalse();
final String xml ="<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<a><b>" +
"<![CDATA[<c><d attr=\"xyz\"></d></c>]]>" +
"</b></a>";
assertThat(xml).valueByXPath("//a/b/text()") // ValueAssert type
.isEqualTo("<c><d attr=\"xyz\"></d></c>")
.asXml() // XmlAssert type
.hasXPath("/c/d");
import static org.xmlunit.assertj.XmlAssert.assertThat;
final 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>";
final Map<String, String> prefix2Uri = new HashMap<String, String>();
prefix2Uri.put("atom", "http://www.w3.org/2005/Atom");
assertThat(xml)
.withNamespaceContext(prefix2Uri)
.hasXPath("//atom:feed/atom:entry/atom:id/text()")
.isEqualTo("id1");
- Overview
- General Concepts
- Comparing XML
- Validating XML
- Utilities
- Migrating from XMLUnit 1.x to 2.x
- Known Issues