1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
|
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>6.DOM Tree Walking</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="XMLUnit Java User's Guide"><link rel="up" href="index.html" title="XMLUnit Java User's Guide"><link rel="prev" href="ar01s05.html" title="5.XPath Tests"><link rel="next" href="apa.html" title="A.Changes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.DOM Tree Walking</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a></td><th width="60%" align="center"></th><td width="20%" align="right"><a accesskey="n" href="apa.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="DOM%20Tree%20Walking"></a>6.DOM Tree Walking</h2></div></div></div>
<p>Sometimes it is easier to test a piece of XML's validity by
traversing the whole document node by node and test each node
individually. Maybe there is no control XML to validate against
or the expected value of an element's content has to be
calculated. There may be several reasons.</p>
<p>XMLUnit supports this approach of testing via the
<code class="literal">NodeTest</code> class. In order to use it, you need a
DOM implementation that generates <code class="literal">Document</code>
instances that implement the optional
<code class="literal">org.w3c.traversal.DocumentTraversal</code> interface,
which is not part of JAXP's standardized DOM support.</p>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="DocumentTraversal"></a>6.1.<code class="literal">DocumentTraversal</code></h3></div></div></div>
<p>As of the release of XMLUnit 1.1 the
<code class="literal">Document</code> instances created by most parsers
implement <code class="literal">DocumentTraversal</code>, this includes
but is not limited to Apache Xerces, the parser shipping with
Sun's JDK 5 and later or GNU JAXP. One notable exception is
Apache Crimson, which also means the parser shipping with Sun's
JDK 1.4 does not support traversal; you need to specify a
different parser when using JDK 1.4 (see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1.JAXP">Section2.4.1, “JAXP”</a>).</p>
<p>You can test whether your XML parser supports
<code class="literal">DocumentTraversal</code> by invoking
<code class="literal">org.w3c.dom.DOMImplementation</code>'s
<code class="literal">hasFeature</code> method with the feature
<code class="literal">"Traversal"</code>.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="NodeTest"></a>6.2.<code class="literal">NodeTest</code></h3></div></div></div>
<p>The <code class="literal">NodeTest</code> is instantiated with a
piece of XML to traverse. It offers two
<code class="literal">performTest</code> methods:</p>
<pre class="programlisting">
/**
* Does this NodeTest pass using the specified NodeTester instance?
* @param tester
* @param singleNodeType note <code>Node.ATTRIBUTE_NODE</code> is not
* exposed by the DocumentTraversal node iterator unless the root node
* is itself an attribute - so a NodeTester that needs to test attributes
* should obtain those attributes from <code>Node.ELEMENT_NODE</code>
* nodes
* @exception NodeTestException if test fails
*/
public void performTest(NodeTester tester, short singleNodeType);
/**
* Does this NodeTest pass using the specified NodeTester instance?
* @param tester
* @param nodeTypes note <code>Node.ATTRIBUTE_NODE</code> is not
* exposed by the DocumentTraversal node iterator unless the root node
* is itself an attribute - so a NodeTester that needs to test attributes
* should obtain those attributes from <code>Node.ELEMENT_NODE</code>
* nodes instead
* @exception NodeTestException if test fails
*/
public void performTest(NodeTester tester, short[] nodeTypes);
</pre>
<p><code class="literal">NodeTester</code> is the class testing each
node and is described in the next section.</p>
<p>The second argument limits the tests on DOM
<code class="literal">Node</code>s of (a) specific type(s).
<code class="literal">Node</code> types are specified via the
<code class="literal">static</code> fields of the <code class="literal">Node</code>
class. Any <code class="literal">Node</code> of a type not specified as
the second argument to <code class="literal">performTest</code> will be
ignored.</p>
<p>Unfortunately XML attributes are not exposed as
<code class="literal">Node</code>s during traversal. If you need access
to attributes you must add <code class="literal">Node.ELEMENT_NODE</code>
to the second argument of <code class="literal">performTest</code> and
access the attributes from their parent
<code class="literal">Element</code>.</p>
<div class="example"><a name="nodetest-attributes"></a><p class="title"><b>Example33.Accessing Attributes in a
<code class="literal">NodeTest</code></b></p><div class="example-contents">
<pre class="programlisting">
...
NodeTest nt = new NodeTest(myXML);
NodeTester tester = new MyNodeTester();
nt.performTest(tester, Node.ELEMENT_NODE);
...
class MyNodeTester implements NodeTester {
public void testNode(Node aNode, NodeTest test) {
Element anElement = (Element) aNode;
Attr attributeToTest = anElement.getAttributeNode(ATTRIBUTE_NAME);
...
}
...
}
</pre></div></div><br class="example-break">
<p>Any entities that appear as part of the
<code class="literal">Document</code> are expanded before the traversal
starts.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="NodeTester"></a>6.3.NodeTester</h3></div></div></div>
<p>Implementations of the <code class="literal">NodeTester</code>
interface are responsible for the actual test:</p>
<pre class="programlisting">
/**
* Validate a single Node
* @param aNode
* @param forTest
* @exception NodeTestException if the node fails the test
*/
void testNode(Node aNode, NodeTest forTest) throws NodeTestException ;
/**
* Validate that the Nodes passed one-by-one to the <code>testNode</code>
* method were all the Nodes expected.
* @param forTest
* @exception NodeTestException if this instance was expecting more nodes
*/
void noMoreNodes(NodeTest forTest) throws NodeTestException ;
</pre>
<p><code class="literal">NodeTest</code> invokes
<code class="literal">testNode</code> for each <code class="literal">Node</code> as
soon as it is reached on the traversal. This means
<code class="literal">NodeTester</code> "sees" the
<code class="literal">Node</code>s in the same order they appear within
the tree.</p>
<p><code class="literal">noMoreNodes</code> is invoked when the
traversal is finished. It will also be invoked if the tree didn't
contain any matched <code class="literal">Node</code>s at all.</p>
<p>Implementations of <code class="literal">NodeTester</code> are
expected to throw a <code class="literal">NodeTestException</code> if the
current not doesn't match the test's expectations or more nodes
have been expected when <code class="literal">noMoreNodes</code> is
called.</p>
<p>XMLUnit ships with two implementations of
<code class="literal">NodeTest</code> that are described in the following
to sections.</p>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="AbstractNodeTester"></a>6.3.1.<code class="literal">AbstractNodeTester</code></h4></div></div></div>
<p><code class="literal">AbstractNodeTester</code> implements
<code class="literal">testNode</code> by testing the passed in
<code class="literal">Node</code> for its type and delegating to one of
the more specific <code class="literal">test...</code> Methods it adds.
By default the new <code class="literal">test...</code> methods all
throw a <code class="literal">NodeTestException</code> because of an
unexpected <code class="literal">Node</code>.</p>
<p>It further implements <code class="literal">noMoreNodes</code>
with an empty method - i.e. it does nothing.</p>
<p>If you are only testing for specific types of
<code class="literal">Node</code> it may be more convenient to subclass
<code class="literal">AbstractNodeTester</code>. For example <a class="xref" href="ar01s06.html#nodetest-attributes" title="Example33.Accessing Attributes in a NodeTest">Example33, “Accessing Attributes in a
<code class="literal">NodeTest</code>”</a> could be re-written as:</p>
<div class="example"><a name="idp43404032"></a><p class="title"><b>Example34.Accessing Attributes in a
<code class="literal">NodeTest</code> -
<code class="literal">AbstractNodeTester</code> version</b></p><div class="example-contents">
<pre class="programlisting">
...
NodeTest nt = new NodeTest(myXML);
NodeTester tester = new AbstractNodeTester() {
public void testElement(Element element) throws NodeTestException {
Attr attributeToTest = element.getAttributeNode(ATTRIBUTE_NAME);
...
}
};
nt.performTest(tester, Node.ELEMENT_NODE);
...
</pre></div></div><br class="example-break">
<p>Note that even though
<code class="literal">AbstractNodeTester</code> contains a
<code class="literal">testAttribute</code> method it will never be
called by default and you still need to access attributes via
their parent elements.</p>
<p>Note also that the root of the test is the document's
root element, so any <code class="literal">Node</code>s preceding the
document's root <code class="literal">Element</code> won't be visited
either. For this reason the
<code class="literal">testDocumentType</code>,
<code class="literal">testEntity</code> and
<code class="literal">testNotation</code> methods are probably never
called either.</p>
<p>Finally, all entity references have been expanded before
the traversal started. <code class="literal">EntityReference</code>s
will have been replaced by their replacement text if it is
available, which means <code class="literal">testEntityReference</code>
will not be called for them either. Instead the replacement
text will show up as (part of) a <code class="literal">Text</code> node
or as <code class="literal">Element</code> node, depending on the
entity's definition.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="CountingNodeTester"></a>6.3.2.<code class="literal">CountingNodeTester</code></h4></div></div></div>
<p><code class="literal">org.custommonkey.xmlunit.examples.CountingNodeTester</code>
is a simple example <code class="literal">NodeTester</code> that asserts
that a given number of <code class="literal">Node</code>s have been
traversed. It will throw a
<code class="literal">NodeTestException</code> when
<code class="literal">noMoreNodes</code> is called before the expected
number of <code class="literal">Node</code>s has been visited or the
actual number of nodes exceeded the expected count.</p>
</div>
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="DOM%20Tree:%20JUnit%203"></a>6.4.JUnit 3.x Convenience Methods</h3></div></div></div>
<p><code class="literal">XMLAssert</code> and
<code class="literal">XMLTestCase</code> contain overloads of
<code class="literal">assertNodeTestPasses</code> methods.</p>
<p>The most general form of it expects you to create a
<code class="literal">NodeTest</code> instance yourself and lets you
specify whether you expect the test to fail or to pass.</p>
<p>The other two overloads create a
<code class="literal">NodeTest</code> instance from either
<code class="literal">String</code> or a SAX
<code class="literal">InputSource</code> and are specialized for the case
where you are only interested in a single <code class="literal">Node</code>
type and expect the test to pass.</p>
<p>Neither method provides any control over the message of
the <code class="literal">AssertionFailedError</code> in case of a
failure.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="DOM%20Tree:%20Configuration"></a>6.5.Configuration Options</h3></div></div></div>
<p>The only configurable option for
<code class="literal">NodeTest</code> is the XML parser used if the piece
of XML is not specified as a <code class="literal">Document</code> or
<code class="literal">DocumentTraversal</code>.
<code class="literal">NodeTest</code> will use the "control" parser that
has been configured - see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1.JAXP">Section2.4.1, “JAXP”</a> for
details.</p>
<p>It will also use the <code class="literal">EntityResolver</code>
configured for the control parser if one has been set - see
<a class="xref" href="ar01s02.html#EntityResolver" title="2.4.2.EntityResolver">Section2.4.2, “<code class="literal">EntityResolver</code>”</a>.</p>
</div>
</div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a></td><td width="20%" align="center"></td><td width="40%" align="right"><a accesskey="n" href="apa.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5.XPath Tests</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">A.Changes</td></tr></table></div></body></html>
|