Small library for those who have a hard time understanding the complexity of XPath.
Have you ever met such a XPath expression?
/root[matches(property1, concat('',"'",'"<>\[\]\(\)'))]
Pretty isn’t it? Wouldn’t it be better to just read:
assertThat(xml).node("root").node("property1").matches('\'"<>\\[\\]\\(\\)')
XMLAssert to the rescue!
The library has a couple of main classes. One is XmlAssertion
that gives you public static methods:
public static XmlVerifiable assertThat(String xml)
NOTE! The aforementioned version caches the Document
for the provided XML.
and
public static XmlVerifiable assertThat(org.w3c.dom.Document parsedXml)
Both these methods give return the public XmlVerifiable
interface which is a fluent interface with which you can build your
XPath expression. Please check the Javadocs of that file for more information.
As you could see it’s not that easy to build a XPath. With XMLAssert you can use the XPathBuilder
class to finally
build the XPaths yourself! This is the contract for the XPathBuilder
class:
/**
* Returns a builder of {@link XmlVerifiable} with which you can build your
* XPath. Once finished just call {@link XmlVerifiable#xPath()} to get
* XPath as String.
*/
public static XmlVerifiable builder()
and when you call:
XPathBuilder.builder().node("some").node("nested").array("withlist").contains("name").isEqualTo("name1").xPath();
you will receive /some/nested/withlist[name='name1']
String.
Wouldn’t it be great to retrieve the value from the XML via the XPath? There you go!
Note
|
It works only for String values |
def 'should resolve the value of XML via XPath'() {
given:
String xml =
'''<?xml version="1.0" encoding="UTF-8" ?>
<root>
<element>
<some>
<nested>
<json>with value</json>
<anothervalue>4</anothervalue>
<withlist>
<name>name1</name>
</withlist>
<withlist>
<name>name2</name>
</withlist>
<withlist>
<anothernested>
<name>name3</name>
</anothernested>
</withlist>
</nested>
</some>
</element>
<element>
<someother>
<nested>
<json>true</json>
<anothervalue>4</anothervalue>
<withlist>
<name>name1</name>
</withlist>
<withlist>
<name>name2</name>
</withlist>
<withlist2>a</withlist2>
<withlist2>b</withlist2>
</nested>
</someother>
</element>
</root>'''
expect:
XPathBuilder.builder(xml).node("root").array("element").node("some").node("nested").node("json").read() == 'with value'
XPathBuilder.builder(xml).node("root").array("element").node("some").node("nested").node("anothervalue").read() == 4.toString()
assertThat(xml).node("root").array("element").node("someother").node("nested").node("json").read() == true.toString()
}
All thanks to the XmlReader
interface:
/**
* Returns the value from the XML, based on the created XPath.
*/
String read();
Just add it as your dependency (Example for Gradle)
testCompile 'com.toomuchcoding.xmlassert:xmlassert:0.0.1'
XMLAssert is really lightweight. It depends only on:
compile 'com.rackspace.eclipse.webtools.sourceediting:org.eclipse.wst.xml.xpath2.processor:2.1.100'
compile 'xerces:xercesImpl:2.11.0'
compile "ch.qos.logback:logback-classic:1.1.2"
For the XML
<?xml version="1.0" encoding="UTF-8" ?>
<some>
<nested>
<json>with "val'ue</json>
<anothervalue>4</anothervalue>
<withattr id="a" id2="b">foo</withattr>
<withlist>
<name>name1</name>
</withlist>
<withlist>
<name>name2</name>
</withlist>
<withlist>
8
</withlist>
<withlist>
<name id="10" surname="kowalski">name3</name>
</withlist>
</nested>
</some>
The following is true
XMLAssert expressions:
assertThat(xml1).node("some").node("nested").node("anothervalue").isEqualTo(4)
assertThat(xml1).node("some").node("nested").node("anothervalue")
assertThat(xml1).node("some").node("nested").node("withattr").withAttribute("id", "a").withAttribute("id2", "b")
assertThat(xml1).node("some").node("nested").node("withattr").isEqualTo("foo").withAttribute("id", "a").withAttribute("id2", "b")
assertThatXml(xml1).node("some").node("nested").node("anothervalue").isEqualTo(4)
assertThat(xml1).node("some").node("nested").array("withlist").contains("name").isEqualTo("name1")
assertThat(xml1).node("some").node("nested").array("withlist").contains("name").isEqualTo("name2")
assertThat(xml1).node("some").node("nested").array("withlist").contains("name").isEqualTo("name3").withAttribute("id", "10").withAttribute("surname", "kowalski")
assertThat(xml1).node("some").node("nested").array("withlist").isEqualTo(8)
assertThat(xml1).node("some").node("nested").node("json").isEqualTo("with \"val'ue")
assertThat(xml1).node("some", "nested", "json").isEqualTo("with \"val'ue")
Respective XPath expressions:
/some/nested[anothervalue=4]
/some/nested/anothervalue
/some/nested/withattr[@id='a'][@id2='b']
/some/nested[withattr='foo']/withattr[@id='a'][@id2='b']
/some/nested[anothervalue=4]
/some/nested/withlist[name='name1']
/some/nested/withlist[name='name2']
/some/nested/withlist[name='name3']/name[@id='10'][@surname='kowalski']
/some/nested/withlist[number()=8]
/some/nested[json=concat('with "val',"'",'ue')]
/some/nested[json=concat('with "val',"'",'ue')]
There is a possibility to use XMLAssert via AssertJ. Regardless of which version you’ll choose you have the same class that you can use to start the fluent assertion.
The standard version
com.toomuchcoding.xmlassert.XmlAssertions.assertThat(Document context);
com.toomuchcoding.xmlassert.XmlAssertions.assertThat(XmlAsString xmlAsString);
com.toomuchcoding.xmlassert.XmlAssertions.assertThat(XmlVerifiable xmlVerifiable);
or the BDD version
com.toomuchcoding.xmlassert.BDDXmlAssertions.then(DocumentContext context);
com.toomuchcoding.xmlassert.BDDXmlAssertions.then(XmlAsString xmlAsString);
com.toomuchcoding.xmlassert.BDDXmlAssertions.then(XmlVerifiable xmlVerifiable);