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 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
|
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>3.Comparing Pieces of XML</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="ar01s02.html" title="2.Using XMLUnit"><link rel="next" href="ar01s04.html" title="4.Validating XML Documents"></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">3.Comparing Pieces of XML</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s02.html">Prev</a></td><th width="60%" align="center"></th><td width="20%" align="right"><a accesskey="n" href="ar01s04.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Comparing%20Pieces%20of%20XML"></a>3.Comparing Pieces of XML</h2></div></div></div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="The%20Difference%20Engine"></a>3.1.The Difference Engine</h3></div></div></div>
<p>At the center of XMLUnit's support for comparisons is the
<code class="literal">DifferenceEngine</code> class. In practice you
rarely deal with it directly but rather use it via instances of
<code class="literal">Diff</code> or <code class="literal">DetailedDiff</code>
classes (see <a class="xref" href="ar01s03.html#Diff" title="3.5.Diff and DetailedDiff">Section3.5, “<code class="literal">Diff</code> and
<code class="literal">DetailedDiff</code>”</a>).</p>
<p>The <code class="literal">DifferenceEngine</code> walks two trees of
DOM <code class="literal">Node</code>s, the control and the test tree, and
compares the nodes. Whenever it detects a difference, it sends
a message to a configured <code class="literal">DifferenceListener</code>
(see <a class="xref" href="ar01s03.html#DifferenceListener" title="3.3.DifferenceListener">Section3.3, “<code class="literal">DifferenceListener</code>”</a>) and asks a
<code class="literal">ComparisonController</code> (see <a class="xref" href="ar01s03.html#ComparisonController" title="3.2.ComparisonController">Section3.2, “<code class="literal">ComparisonController</code>”</a>) whether the current comparison
should be halted.</p>
<p>In some cases the order of elements in two pieces of XML
may not be significant. If this is true, the
<code class="literal">DifferenceEngine</code> needs help to determine
which <code class="literal">Element</code>s to compare. This is the job
of an <code class="literal">ElementQualifier</code> (see <a class="xref" href="ar01s03.html#ElementQualifier" title="3.4.ElementQualifier">Section3.4, “<code class="literal">ElementQualifier</code>”</a>).</p>
<p>The types of differences
<code class="literal">DifferenceEngine</code> can detect are enumerated in
the <code class="literal">DifferenceConstants</code> interface and
represented by instances of the <code class="literal">Difference</code>
class.</p>
<p>A <code class="literal">Difference</code> can be recoverable;
recoverable <code class="literal">Difference</code>s make the
<code class="literal">Diff</code> class consider two pieces of XML similar
while non-recoverable <code class="literal">Difference</code>s render the
two pieces different.</p>
<p>The types of <code class="literal">Difference</code>s that are
currently detected are listed in <a class="xref" href="ar01s03.html#docleveldiff" title="Table1.Document level Differences detected by DifferenceEngine">Table1, “Document level <code class="literal">Difference</code>s detected by
<code class="literal">DifferenceEngine</code>”</a>
to <a class="xref" href="ar01s03.html#otherdiff" title="Table4.Other Differences detected by DifferenceEngine">Table4, “Other <code class="literal">Difference</code>s detected by
<code class="literal">DifferenceEngine</code>”</a> (the first two columns refer to
the <code class="literal">DifferenceConstants</code> class).</p>
<div class="table"><a name="docleveldiff"></a><p class="title"><b>Table1.Document level <code class="literal">Difference</code>s detected by
<code class="literal">DifferenceEngine</code></b></p><div class="table-contents">
<table summary="Document level Differences detected by
DifferenceEngine" width="100%" border="1"><colgroup><col align="center" class="id"><col align="center" class="constant"><col align="center" class="recoverable"><col align="left" class="description"></colgroup><thead><tr><th align="center"><code class="literal">ID</code></th><th align="center"><code class="literal">Constant</code></th><th align="center"><code class="literal">recoverable</code></th><th align="center">Description</th></tr></thead><tbody><tr><td align="center"><code class="literal">HAS_DOCTYPE_DECLARATION_ID</code></td><td align="center"><code class="literal">HAS_DOCTYPE_DECLARATION</code></td><td align="center"><code class="literal">true</code></td><td align="left">One piece of XML has a DOCTYPE declaration while
the other one has not.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_NAME_ID</code></td><td align="center"><code class="literal">DOCTYPE_NAME</code></td><td align="center"><code class="literal">false</code></td><td align="left">Both pieces of XML contain a DOCTYPE declaration
but the declarations specify different names for the
root element.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_PUBLIC_ID_ID</code></td><td align="center"><code class="literal">DOCTYPE_PUBLIC_ID</code></td><td align="center"><code class="literal">false</code></td><td align="left">Both pieces of XML contain a DOCTYPE declaration
but the declarations specify different PUBLIC
identifiers.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_SYSTEM_ID_ID</code></td><td align="center"><code class="literal">DOCTYPE_SYSTEM_ID</code></td><td align="center"><code class="literal">true</code></td><td align="left">Both pieces of XML contain a DOCTYPE declaration
but the declarations specify different SYSTEM
identifiers.</td></tr><tr><td align="center"><code class="literal">NODE_TYPE_ID</code></td><td align="center"><code class="literal">NODE_TYPE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The test piece of XML contains a different type
of node than was expected. This type of difference will
also occur if either the root control or test
<code class="literal">Node</code> is <code class="literal">null</code> while
the other is not.</td></tr><tr><td align="center"><code class="literal">NAMESPACE_PREFIX_ID</code></td><td align="center"><code class="literal">NAMESPACE_PREFIX</code></td><td align="center"><code class="literal">true</code></td><td align="left">Two nodes use different prefixes for the same
XML Namespace URI in the two pieces of XML.</td></tr><tr><td align="center"><code class="literal">NAMESPACE_URI_ID</code></td><td align="center"><code class="literal">NAMESPACE_URI</code></td><td align="center"><code class="literal">false</code></td><td align="left">Two nodes in the two pieces of XML share the same
local name but use different XML Namespace URIs.</td></tr><tr><td align="center"><code class="literal">SCHEMA_LOCATION_ID</code></td><td align="center"><code class="literal">SCHEMA_LOCATION</code></td><td align="center"><code class="literal">true</code></td><td align="left">Two nodes have different values for the
<code class="literal">schemaLocation</code> attribute of the
XMLSchema-Instance namespace. The attribute could be
present on only one of the two nodes.</td></tr><tr><td align="center"><code class="literal">NO_NAMESPACE_SCHEMA_LOCATION_ID</code></td><td align="center"><code class="literal">NO_NAMESPACE_SCHEMA_LOCATION</code></td><td align="center"><code class="literal">true</code></td><td align="left">Two nodes have different values for the
<code class="literal">noNamespaceSchemaLocation</code> attribute
of the XMLSchema-Instance namespace. The attribute
could be present on only one of the two nodes.</td></tr></tbody></table>
</div></div><br class="table-break">
<div class="table"><a name="elementleveldiff"></a><p class="title"><b>Table2.Element level <code class="literal">Difference</code>s detected by
<code class="literal">DifferenceEngine</code></b></p><div class="table-contents">
<table summary="Element level Differences detected by
DifferenceEngine" width="100%" border="1"><colgroup><col align="center" class="id"><col align="center" class="constant"><col align="center" class="recoverable"><col align="left" class="description"></colgroup><thead><tr><th align="center"><code class="literal">ID</code></th><th align="center"><code class="literal">Constant</code></th><th align="center"><code class="literal">recoverable</code></th><th align="center">Description</th></tr></thead><tbody><tr><td align="center"><code class="literal">ELEMENT_TAG_NAME_ID</code></td><td align="center"><code class="literal">ELEMENT_TAG_NAME</code></td><td align="center"><code class="literal">false</code></td><td align="left">The two pieces of XML contain elements with
different tag names.</td></tr><tr><td align="center"><code class="literal">ELEMENT_NUM_ATTRIBUTES_ID</code></td><td align="center"><code class="literal">ELEMENT_NUM_ATTRIBUTES</code></td><td align="center"><code class="literal">false</code></td><td align="left">The two pieces of XML contain a common element,
but the number of attributes on the element is
different.</td></tr><tr><td align="center"><code class="literal">HAS_CHILD_NODES_ID</code></td><td align="center"><code class="literal">HAS_CHILD_NODES</code></td><td align="center"><code class="literal">false</code></td><td align="left">An element in one piece of XML has child nodes
while the corresponding one in the other has not.</td></tr><tr><td align="center"><code class="literal">CHILD_NODELIST_LENGTH_ID</code></td><td align="center"><code class="literal">CHILD_NODELIST_LENGTH</code></td><td align="center"><code class="literal">false</code></td><td align="left">Two elements in the two pieces of XML differ by
their number of child nodes.</td></tr><tr><td align="center"><code class="literal">CHILD_NODELIST_SEQUENCE_ID</code></td><td align="center"><code class="literal">CHILD_NODELIST_SEQUENCE</code></td><td align="center"><code class="literal">true</code></td><td align="left">Two elements in the two pieces of XML contain the
same child nodes but in a different order.</td></tr><tr><td align="center"><code class="literal">CHILD_NODE_NOT_FOUND_ID</code></td><td align="center"><code class="literal">CHILD_NODE_NOT_FOUND</code></td><td align="center"><code class="literal">false</code></td><td align="left">A child node in one piece of XML couldn't be
matched against any other node of the other piece.</td></tr><tr><td align="center"><code class="literal">ATTR_SEQUENCE_ID</code></td><td align="center"><code class="literal">ATTR_SEQUENCE</code></td><td align="center"><code class="literal">true</code></td><td align="left">The attributes on an element appear in different
order<a href="#ftn.idp42740768" class="footnote" name="idp42740768"><sup class="footnote">[a]</sup></a> in the two pieces of
XML.</td></tr></tbody><tbody class="footnotes"><tr><td colspan="4"><div id="ftn.idp42740768" class="footnote"><p><a href="#idp42740768" class="para"><sup class="para">[a] </sup></a>Note that the order of attributes
is not significant in XML, different parsers may return
attributes in a different order even if parsing the same
XML document. There is an option to turn this check off
- see <a class="xref" href="ar01s03.html#Comparing:%20Configuration" title="3.8.Configuration Options">Section3.8, “Configuration Options”</a> - but it is on
by default for backwards compatibility
reasons</p></div></td></tr></tbody></table>
</div></div><br class="table-break">
<div class="table"><a name="attributeleveldiff"></a><p class="title"><b>Table3.Attribute level <code class="literal">Difference</code>s detected by
<code class="literal">DifferenceEngine</code></b></p><div class="table-contents">
<table summary="Attribute level Differences detected by
DifferenceEngine" width="100%" border="1"><colgroup><col align="center" class="id"><col align="center" class="constant"><col align="center" class="recoverable"><col align="left" class="description"></colgroup><thead><tr><th align="center"><code class="literal">ID</code></th><th align="center"><code class="literal">Constant</code></th><th align="center"><code class="literal">recoverable</code></th><th align="center">Description</th></tr></thead><tbody><tr><td align="center"><code class="literal">ATTR_VALUE_EXPLICITLY_SPECIFIED_ID</code></td><td align="center"><code class="literal">ATTR_VALUE_EXPLICITLY_SPECIFIED</code></td><td align="center"><code class="literal">true</code></td><td align="left">An attribute that has a default value according
to the content model of the element in question has been
specified explicitly in one piece of XML but not in the
other.<a href="#ftn.idp42757728" class="footnote" name="idp42757728"><sup class="footnote">[a]</sup></a></td></tr><tr><td align="center"><code class="literal">ATTR_NAME_NOT_FOUND_ID</code></td><td align="center"><code class="literal">ATTR_NAME_NOT_FOUND</code></td><td align="center"><code class="literal">false</code></td><td align="left">One piece of XML contains an attribute on an
element that is missing in the other.</td></tr><tr><td align="center"><code class="literal">ATTR_VALUE_ID</code></td><td align="center"><code class="literal">ATTR_VALUE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The value of an element's attribute is different
in the two pieces of XML.</td></tr></tbody><tbody class="footnotes"><tr><td colspan="4"><div id="ftn.idp42757728" class="footnote"><p><a href="#idp42757728" class="para"><sup class="para">[a] </sup></a>In order for this difference to be
detected the parser must have been in validating mode
when the piece of XML was parsed and the DTD or XML
Schema must have been available.</p></div></td></tr></tbody></table>
</div></div><br class="table-break">
<div class="table"><a name="otherdiff"></a><p class="title"><b>Table4.Other <code class="literal">Difference</code>s detected by
<code class="literal">DifferenceEngine</code></b></p><div class="table-contents">
<table summary="Other Differences detected by
DifferenceEngine" width="100%" border="1"><colgroup><col align="center" class="id"><col align="center" class="constant"><col align="center" class="recoverable"><col align="left" class="description"></colgroup><thead><tr><th align="center"><code class="literal">ID</code></th><th align="center"><code class="literal">Constant</code></th><th align="center"><code class="literal">recoverable</code></th><th align="center">Description</th></tr></thead><tbody><tr><td align="center"><code class="literal">COMMENT_VALUE_ID</code></td><td align="center"><code class="literal">COMMENT_VALUE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The content of two comments is different in the
two pieces of XML.</td></tr><tr><td align="center"><code class="literal">PROCESSING_INSTRUCTION_TARGET_ID</code></td><td align="center"><code class="literal">PROCESSING_INSTRUCTION_TARGET</code></td><td align="center"><code class="literal">false</code></td><td align="left">The target of two processing instructions is
different in the two pieces of XML.</td></tr><tr><td align="center"><code class="literal">PROCESSING_INSTRUCTION_DATA_ID</code></td><td align="center"><code class="literal">PROCESSING_INSTRUCTION_DATA</code></td><td align="center"><code class="literal">false</code></td><td align="left">The data of two processing instructions is
different in the two pieces of XML.</td></tr><tr><td align="center"><code class="literal">CDATA_VALUE_ID</code></td><td align="center"><code class="literal">CDATA_VALUE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The content of two CDATA sections is different in
the two pieces of XML.</td></tr><tr><td align="center"><code class="literal">TEXT_VALUE_ID</code></td><td align="center"><code class="literal">TEXT_VALUE</code></td><td align="center"><code class="literal">false</code></td><td align="left">The value of two texts is different in the two
pieces of XML.</td></tr></tbody></table>
</div></div><br class="table-break">
<p>Note that some of the differences listed may be ignored by
the <code class="literal">DifferenceEngine</code> if certain configuration
options have been specified. See <a class="xref" href="ar01s03.html#Comparing:%20Configuration" title="3.8.Configuration Options">Section3.8, “Configuration Options”</a> for details.</p>
<p><code class="literal">DifferenceEngine</code> passes differences
found around as instances of the <code class="literal">Difference</code>
class. In addition to the type of of difference this class also
holds information on the nodes that have been found to be
different. The nodes are described by
<code class="literal">NodeDetail</code> instances that encapsulate the DOM
<code class="literal">Node</code> instance as well as the XPath expression
that locates the <code class="literal">Node</code> inside the given piece
of XML. <code class="literal">NodeDetail</code> also contains a "value"
that provides more information on the actual values that have
been found to be different, the concrete interpretation depends
on the type of difference as can be seen in <a class="xref" href="ar01s03.html#diffvalue" title="Table5.Contents of NodeDetail.getValue() for Differences">Table5, “Contents of <code class="literal">NodeDetail.getValue()</code>
for <code class="literal">Difference</code>s”</a>.</p>
<div class="table"><a name="diffvalue"></a><p class="title"><b>Table5.Contents of <code class="literal">NodeDetail.getValue()</code>
for <code class="literal">Difference</code>s</b></p><div class="table-contents">
<table summary="Contents of NodeDetail.getValue()
for Differences" border="1"><colgroup><col align="center" class="id"><col align="left" class="value"></colgroup><thead><tr><th align="center"><code class="literal">Difference.getId()</code></th><th align="center"><code class="literal">NodeDetail.getValue()</code></th></tr></thead><tbody><tr><td align="center"><code class="literal">HAS_DOCTYPE_DECLARATION_ID</code></td><td align="left"><code class="literal">"not null"</code> if the document has
a DOCTYPE declaration, <code class="literal">"null"</code>
otherwise.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_NAME_ID</code></td><td align="left">The name of the root element.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_PUBLIC_ID</code></td><td align="left">The PUBLIC identifier.</td></tr><tr><td align="center"><code class="literal">DOCTYPE_SYSTEM_ID</code></td><td align="left">The SYSTEM identifier.</td></tr><tr><td align="center"><code class="literal">NODE_TYPE_ID</code></td><td align="left">If one node was absent: <code class="literal">"not
null"</code> if the node exists,
<code class="literal">"null"</code> otherwise. If the node types
differ the value will be a string-ified version of
<code class="literal">org.w3c.dom.Node.getNodeType()</code>.</td></tr><tr><td align="center"><code class="literal">NAMESPACE_PREFIX_ID</code></td><td align="left">The Namespace prefix.</td></tr><tr><td align="center"><code class="literal">NAMESPACE_URI_ID</code></td><td align="left">The Namespace URI.</td></tr><tr><td align="center"><code class="literal">SCHEMA_LOCATION_ID</code></td><td align="left">The attribute's value or "[attribute absent]" if
it has not been specified.</td></tr><tr><td align="center"><code class="literal">NO_NAMESPACE_SCHEMA_LOCATION_ID</code></td><td align="left">The attribute's value or "[attribute absent]" if
it has not been specified.</td></tr><tr><td align="center"><code class="literal">ELEMENT_TAG_NAME_ID</code></td><td align="left">The tag name with any Namespace information
stripped.</td></tr><tr><td align="center"><code class="literal">ELEMENT_NUM_ATTRIBUTES_ID</code></td><td align="left">The number of attributes present turned into a
<code class="literal">String</code>.</td></tr><tr><td align="center"><code class="literal">HAS_CHILD_NODES_ID</code></td><td align="left"><code class="literal">"true"</code> if the element has
child nodes, <code class="literal">"false"</code>
otherwise.</td></tr><tr><td align="center"><code class="literal">CHILD_NODELIST_LENGTH_ID</code></td><td align="left">The number of child nodes present turned into a
<code class="literal">String</code>.</td></tr><tr><td align="center"><code class="literal">CHILD_NODELIST_SEQUENCE_ID</code></td><td align="left">The sequence number of this child node turned into a
<code class="literal">String</code>.</td></tr><tr><td align="center"><code class="literal">CHILD_NODE_NOT_FOUND_ID</code></td><td align="left">The name of the unmatched node or
<code class="literal">"null"</code>. If the node is an element
inside an XML namespace the name will be
Java5-<code class="literal">QName</code>-like
<code class="literal">{NS-URI}LOCAL-NAME</code> - in all other
cases it is the node's local name.</td></tr><tr><td align="center"><code class="literal">ATTR_SEQUENCE_ID</code></td><td align="left">The attribute's name.</td></tr><tr><td align="center"><code class="literal">ATTR_VALUE_EXPLICITLY_SPECIFIED_ID</code></td><td align="left"><code class="literal">"true"</code> if the attribute has
been specified, <code class="literal">"false"</code>
otherwise.</td></tr><tr><td align="center"><code class="literal">ATTR_NAME_NOT_FOUND_ID</code></td><td align="left">The attribute's name or
<code class="literal">"null"</code>. If the attribute belongs to
an XML namespace the name will be
Java5-<code class="literal">QName</code>-like
<code class="literal">{NS-URI}LOCAL-NAME</code> - in all other
cases it is the attribute's local name.</td></tr><tr><td align="center"><code class="literal">ATTR_VALUE_ID</code></td><td align="left">The attribute's value.</td></tr><tr><td align="center"><code class="literal">COMMENT_VALUE_ID</code></td><td align="left">The actual comment.</td></tr><tr><td align="center"><code class="literal">PROCESSING_INSTRUCTION_TARGET_ID</code></td><td align="left">The processing instruction's target.</td></tr><tr><td align="center"><code class="literal">PROCESSING_INSTRUCTION_DATA_ID</code></td><td align="left">The processing instruction's data.</td></tr><tr><td align="center"><code class="literal">CDATA_VALUE_ID</code></td><td align="left">The content of the CDATA section.</td></tr><tr><td align="center"><code class="literal">TEXT_VALUE_ID</code></td><td align="left">The actual text.</td></tr></tbody></table>
</div></div><br class="table-break">
<p>As said in the first paragraph you won't deal with
<code class="literal">DifferenceEngine</code> directly in most cases. In
cases where <code class="literal">Diff</code> or
<code class="literal">DetailedDiff</code> don't provide what you need
you'd create an instance of <code class="literal">DifferenceEngine</code>
passing a <code class="literal">ComparisonController</code> in the
constructor and invoke <code class="literal">compare</code> with your DOM
trees to compare as well as a
<code class="literal">DifferenceListener</code> and
<code class="literal">ElementQualifier</code>. The listener will be
called on any differences while the <code class="literal">control</code>
method is executing.</p>
<div class="example"><a name="idp42875088"></a><p class="title"><b>Example16.Using <code class="literal">DifferenceEngine</code>
Directly</b></p><div class="example-contents">
<pre class="programlisting">
class MyDifferenceListener implements DifferenceListener {
private boolean calledFlag = false;
public boolean called() { return calledFlag; }
public int differenceFound(Difference difference) {
calledFlag = true;
return RETURN_ACCEPT_DIFFERENCE;
}
public void skippedComparison(Node control, Node test) {
}
}
DifferenceEngine engine = new DifferenceEngine(myComparisonController);
MyDifferenceListener listener = new MyDifferenceListener();
engine.compare(controlNode, testNode, listener,
myElementQualifier);
System.err.println("There have been "
+ (listener.called() ? "" : "no ")
+ "differences.");
</pre></div></div><br class="example-break">
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="ComparisonController"></a>3.2.<code class="literal">ComparisonController</code></h3></div></div></div>
<p>The <code class="literal">ComparisonController</code>'s job is to
decide whether a comparison should be halted after a difference
has been found. Its interface is:</p>
<pre class="programlisting">
/**
* Determine whether a Difference that the listener has been notified of
* should halt further XML comparison. Default behaviour for a Diff
* instance is to halt if the Difference is not recoverable.
* @see Difference#isRecoverable
* @param afterDifference the last Difference passed to <code>differenceFound</code>
* @return true to halt further comparison, false otherwise
*/
boolean haltComparison(Difference afterDifference);
</pre>
<p>Whenever a difference has been detected by the
<code class="literal">DifferenceEngine</code> the
<code class="literal">haltComparison</code> method will be called
immediately after the <code class="literal">DifferenceListener</code> has
been informed of the difference. This is true no matter what
type of <code class="literal">Difference</code> has been found or which
value the <code class="literal">DifferenceListener</code> has
returned.</p>
<p>The only implementations of
<code class="literal">ComparisonController</code> that ship with XMLUnit
are <code class="literal">Diff</code> and <code class="literal">DetailedDiff</code>,
see <a class="xref" href="ar01s03.html#Diff" title="3.5.Diff and DetailedDiff">Section3.5, “<code class="literal">Diff</code> and
<code class="literal">DetailedDiff</code>”</a> for details about them.</p>
<p>A <code class="literal">ComparisonController</code> that halted the
comparison on any non-recoverable difference could be
implemented as:</p>
<div class="example"><a name="idp42890832"></a><p class="title"><b>Example17.A Simple
<code class="literal">ComparisonController</code></b></p><div class="example-contents">
<pre class="programlisting">
public class HaltOnNonRecoverable implements ComparisonController {
public boolean haltComparison(Difference afterDifference) {
return !afterDifference.isRecoverable();
}
}
</pre></div></div><br class="example-break">
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="DifferenceListener"></a>3.3.<code class="literal">DifferenceListener</code></h3></div></div></div>
<p><code class="literal">DifferenceListener</code> contains two
callback methods that are invoked by the
<code class="literal">DifferenceEngine</code> when differences are
detected:</p>
<pre class="programlisting">
/**
* Receive notification that 2 nodes are different.
* @param difference a Difference instance as defined in {@link
* DifferenceConstants DifferenceConstants} describing the cause
* of the difference and containing the detail of the nodes that
* differ
* @return int one of the RETURN_... constants describing how this
* difference was interpreted
*/
int differenceFound(Difference difference);
/**
* Receive notification that a comparison between 2 nodes has been skipped
* because the node types are not comparable by the DifferenceEngine
* @param control the control node being compared
* @param test the test node being compared
* @see DifferenceEngine
*/
void skippedComparison(Node control, Node test);
</pre>
<p><code class="literal">differenceFound</code> is invoked by
<code class="literal">DifferenceEngine</code> as soon as a difference has
been detected. The return value of that method is completely
ignored by <code class="literal">DifferenceEngine</code>, it becomes
important when used together with <code class="literal">Diff</code>,
though (see <a class="xref" href="ar01s03.html#Diff" title="3.5.Diff and DetailedDiff">Section3.5, “<code class="literal">Diff</code> and
<code class="literal">DetailedDiff</code>”</a>). The return value should be
one of the four constants defined in the the
<code class="literal">DifferenceListener</code> interface:</p>
<pre class="programlisting">
/**
* Standard return value for the <code>differenceFound</code> method.
* Indicates that the <code>Difference</code> is interpreted as defined
* in {@link DifferenceConstants DifferenceConstants}.
*/
int RETURN_ACCEPT_DIFFERENCE;
/**
* Override return value for the <code>differenceFound</code> method.
* Indicates that the nodes identified as being different should be
* interpreted as being identical.
*/
int RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
/**
* Override return value for the <code>differenceFound</code> method.
* Indicates that the nodes identified as being different should be
* interpreted as being similar.
*/
int RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR;
/**
* Override return value for the <code>differenceFound</code> method.
* Indicates that the nodes identified as being similar should be
* interpreted as being different.
*/
int RETURN_UPGRADE_DIFFERENCE_NODES_DIFFERENT = 3;
</pre>
<p>The <code class="literal">skippedComparison</code> method is
invoked if the <code class="literal">DifferenceEngine</code> encounters
two <code class="literal">Node</code>s it cannot compare. Before invoking
<code class="literal">skippedComparison</code>
<code class="literal">DifferenceEngine</code> will have invoked
<code class="literal">differenceFound</code> with a
<code class="literal">Difference</code> of type
<code class="literal">NODE_TYPE</code>.</p>
<p>A custom <code class="literal">DifferenceListener</code> that
ignored any DOCTYPE related differences could be written
as:</p>
<div class="example"><a name="idp42913264"></a><p class="title"><b>Example18.A <code class="literal">DifferenceListener</code> that Ignores
DOCTYPE Differences</b></p><div class="example-contents">
<pre class="programlisting">
public class IgnoreDoctype implements DifferenceListener {
private static final int[] IGNORE = new int[] {
DifferenceConstants.HAS_DOCTYPE_DECLARATION_ID,
DifferenceConstants.DOCTYPE_NAME_ID,
DifferenceConstants.DOCTYPE_PUBLIC_ID_ID,
DifferenceConstants.DOCTYPE_SYSTEM_ID_ID
};
static {
Arrays.sort(IGNORE);
}
public int differenceFound(Difference difference) {
return Arrays.binarySearch(IGNORE, difference.getId()) >= 0
? RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL
: RETURN_ACCEPT_DIFFERENCE;
}
public void skippedComparison(Node control, Node test) {
}
}
</pre></div></div><br class="example-break">
<p>Apart from <code class="literal">Diff</code> and
<code class="literal">DetailedDiff</code> XMLUnit ships with an additional
implementation of <code class="literal">DifferenceListener</code>.</p>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="IgnoreTextAndAttributeValuesDifferenceListener"></a>3.3.1.<code class="literal">IgnoreTextAndAttributeValuesDifferenceListener</code></h4></div></div></div>
<p><code class="literal">IgnoreTextAndAttributeValuesDifferenceListener</code>
doesn't do anything in <code class="literal">skippedComparison</code>.
It "downgrades" <code class="literal">Difference</code>s of type
<code class="literal">ATTR_VALUE</code>,
<code class="literal">ATTR_VALUE_EXPLICITLY_SPECIFIED</code> and
<code class="literal">TEXT_VALUE</code> to recoverable
differences.</p>
<p>This means if instances of
<code class="literal">IgnoreTextAndAttributeValuesDifferenceListener</code>
are used together with <code class="literal">Diff</code> then two pieces
of XML will be considered similar if they have the same basic
structure. They are not considered identical, though.</p>
<p>Note that the list of ignored differences doesn't cover
all textual differences. You should configure XMLUnit to
ignore comments and whitespace and to consider CDATA sections
and text nodes to be the same (see <a class="xref" href="ar01s03.html#Comparing:%20Configuration" title="3.8.Configuration Options">Section3.8, “Configuration Options”</a>) in order to cover
<code class="literal">COMMENT_VALUE</code> and
<code class="literal">CDATA_VALUE</code> as well.</p>
</div>
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="ElementQualifier"></a>3.4.<code class="literal">ElementQualifier</code></h3></div></div></div>
<p>When <code class="literal">DifferenceEngine</code> encounters a list
of DOM <code class="literal">Element</code>s as children of another
<code class="literal">Element</code> it will ask the configured
<code class="literal">ElementQualifier</code> which
<code class="literal">Element</code> of the control piece of XML should be
compared to which of the test piece. Its contract is:</p>
<pre class="programlisting">
/**
* Determine whether two elements are comparable
* @param control an Element from the control XML NodeList
* @param test an Element from the test XML NodeList
* @return true if the elements are comparable, false otherwise
*/
boolean qualifyForComparison(Element control, Element test);
</pre>
<p>For any given <code class="literal">Element</code> in the control
piece of XML <code class="literal">DifferenceEngine</code> will cycle
through the corresponding list of <code class="literal">Element</code>s in
the test piece of XML until
<code class="literal">qualifyForComparison</code> has returned
<code class="literal">true</code> or the test document is
exhausted.</p>
<p>When using <code class="literal">DifferenceEngine</code> or
<code class="literal">Diff</code> it is completely legal to set the
<code class="literal">ElementQualifier</code> to <code class="literal">null</code>.
In this case any kind of <code class="literal">Node</code> is compared to
the test <code class="literal">Node</code> that appears at the same
position in the sequence.</p>
<div class="example"><a name="eq-nodelist-example"></a><p class="title"><b>Example19.Example Nodes for <code class="literal">ElementQualifier</code>
(the comments are not part of the example)</b></p><div class="example-contents">
<pre class="programlisting">
<!-- control piece of XML -->
<parent>
<child1/> <!-- control node 1 -->
<child2/> <!-- control node 2 -->
<child2 foo="bar">xyzzy</child2> <!-- control node 3 -->
<child2 foo="baz"/> <!-- control node 4 -->
</parent>
<!-- test piece of XML -->
<parent>
<child2 foo="baz"/> <!-- test node 1 -->
<child1/> <!-- test node 2 -->
<child2>xyzzy</child2> <!-- test node 3 -->
<child2 foo="bar"/> <!-- test node 4 -->
</parent>
</pre></div></div><br class="example-break">
<p>Taking <a class="xref" href="ar01s03.html#eq-nodelist-example" title="Example19.Example Nodes for ElementQualifier (the comments are not part of the example)">Example19, “Example Nodes for <code class="literal">ElementQualifier</code>
(the comments are not part of the example)”</a> without any
<code class="literal">ElementQualifier</code>
<code class="literal">DifferenceEngine</code> will compare control node
<code class="literal">n</code> to test node <code class="literal">n</code> for
<code class="literal">n</code> between 1 and 4. In many cases this is
exactly what is desired, but sometimes
<code class="literal"><a><b/><c/></a></code> should be similar
to <code class="literal"><a><c/><b/></a></code> because the
order of elements doesn't matter - this is when you'd use a
different <code class="literal">ElementQualifier</code>. XMLUnit ships
with several implementations.</p>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="ElementNameQualifier"></a>3.4.1.<code class="literal">ElementNameQualifier</code></h4></div></div></div>
<p>Only <code class="literal">Element</code>s with the same name -
and Namespace URI if present - qualify.</p>
<p>In <a class="xref" href="ar01s03.html#eq-nodelist-example" title="Example19.Example Nodes for ElementQualifier (the comments are not part of the example)">Example19, “Example Nodes for <code class="literal">ElementQualifier</code>
(the comments are not part of the example)”</a> this means
control node 1 will be compared to test node 2. Then control
node 2 will be compared to test node 3 because
<code class="literal">DifferenceEngine</code> will start to search for
the matching test <code class="literal">Element</code> at the second
test node, the same sequence number the control node is at.
Control node 3 is compared to test node 3 as well and control
node 4 to test node 4.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="ElementNameAndAttributeQualifier"></a>3.4.2.<code class="literal">ElementNameAndAttributeQualifier</code></h4></div></div></div>
<p>Only <code class="literal">Element</code>s with the same name -
and Namespace URI if present - as well as the same values for
all attributes given in
<code class="literal">ElementNameAndAttributeQualifier</code>'s
constructor qualify.</p>
<p>Let's say <code class="literal">"foo"</code> has been passed to
<code class="literal">ElementNameAndAttributeQualifier</code>'s
constructor when looking at <a class="xref" href="ar01s03.html#eq-nodelist-example" title="Example19.Example Nodes for ElementQualifier (the comments are not part of the example)">Example19, “Example Nodes for <code class="literal">ElementQualifier</code>
(the comments are not part of the example)”</a>. This again means control
node 1 will be compared to test node 2 since they do have the
same name and no value at all for attribute
<code class="literal">"foo"</code>. Then control node 2 will be
compared to test node 3 - again, no value for
<code class="literal">"foo"</code>. Control node 3 is compared to test
node 4 as they have the same value <code class="literal">"bar"</code>.
Finally control node 4 is compared to test node 1; here
<code class="literal">DifferenceEngine</code> searches from the
beginning of the test node list after test node 4 didn't
match.</p>
<p>There are three constructors in
<code class="literal">ElementNameAndAttributeQualifier</code>. The
no-arg constructor creates an instance that compares all
attributes while the others will compare a single attribute or
a given subset of all attributes.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="ElementNameAndTextQualifier"></a>3.4.3.<code class="literal">ElementNameAndTextQualifier</code></h4></div></div></div>
<p>Only <code class="literal">Element</code>s with the same name -
and Namespace URI if present - as well as the same text
content nested into them qualify.</p>
<p>In <a class="xref" href="ar01s03.html#eq-nodelist-example" title="Example19.Example Nodes for ElementQualifier (the comments are not part of the example)">Example19, “Example Nodes for <code class="literal">ElementQualifier</code>
(the comments are not part of the example)”</a> this means
control node 1 will be compared to test node 2 since they both
don't have any nested text at all. Then control node 2 will
be compared to test node 4. Control node 3 is compared to
test node 3 since they have the same nested text and control
node 4 to test node 4.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="RecursiveElementNameAndTextQualifier"></a>3.4.4.<code class="literal">org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier</code></h4></div></div></div>
<p>All <code class="literal">ElementQualifier</code>s seen so far
only looked at the <code class="literal">Element</code>s themselves and
not at the structure nested into them at a deeper level. A
frequent user question has been which
<code class="literal">ElementQualifier</code> should be used if the
pieces of XML in <a class="xref" href="ar01s03.html#htmltable" title="Example20.Example for RecursiveElementNameAndTextQualifier (the comments are not part of the example)">Example20, “Example for
<code class="literal">RecursiveElementNameAndTextQualifier</code>
(the comments are not part of the example)”</a> should be
considered similar.</p>
<div class="example"><a name="htmltable"></a><p class="title"><b>Example20.Example for
<code class="literal">RecursiveElementNameAndTextQualifier</code>
(the comments are not part of the example)</b></p><div class="example-contents">
<pre class="programlisting">
<!-- control -->
<table>
<tr> <!-- control row 1 -->
<td>foo</td>
</tr>
<tr> <!-- control row 2 -->
<td>bar</td>
</tr>
</table>
<!-- test -->
<table>
<tr> <!-- test row 1 -->
<td>bar</td>
</tr>
<tr> <!-- test row 2 -->
<td>foo</td>
</tr>
</table>
</pre></div></div><br class="example-break">
<p>At first glance
<code class="literal">ElementNameAndTextQualifier</code> should work but
it doesn't. When <code class="literal">DifferenceEngine</code>
processed the children of <code class="literal">table</code> it would
compare control row 1 to test row 1 since both
<code class="literal">tr</code> elements have the same name and both
have no textual content at all.</p>
<p>What is needed in this case is an
<code class="literal">ElementQualifier</code> that looks at the element's
name, as well as the name of the first child element and the
text nested into that first child element. This is what
<code class="literal">RecursiveElementNameAndTextQualifier</code>
does.</p>
<p><code class="literal">RecursiveElementNameAndTextQualifier</code>
ignores whitespace between the elements leading up to the
nested text.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="MultiLevelElementNameAndTextQualifier"></a>3.4.5.<code class="literal">org.custommonkey.xmlunit.examples.MultiLevelElementNameAndTextQualifier</code></h4></div></div></div>
<p>
<code class="literal">MultiLevelElementNameAndTextQualifier</code> has
in a way been the predecessor
of <a class="xref" href="ar01s03.html#RecursiveElementNameAndTextQualifier" title="3.4.4.org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier">Section3.4.4, “<code class="literal">org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier</code>”</a>.
It also matches element names and those of nested child
elements until it finds matches, but
unlike <code class="literal">RecursiveElementNameAndTextQualifier</code>,
you must
tell <code class="literal">MultiLevelElementNameAndTextQualifier</code>
at which nesting level it should expect the nested text.
</p>
<p>
<code class="literal">MultiLevelElementNameAndTextQualifier</code>'s
constructor expects a single argument which is the nesting
level of the expected text. If you use an argument of 1,
<code class="literal">MultiLevelElementNameAndTextQualifier</code> is
identical to <code class="literal">ElementNameAndTextQualifier</code>.
In <a class="xref" href="ar01s03.html#htmltable" title="Example20.Example for RecursiveElementNameAndTextQualifier (the comments are not part of the example)">Example20, “Example for
<code class="literal">RecursiveElementNameAndTextQualifier</code>
(the comments are not part of the example)”</a> a value of 2 would be
needed.</p>
<p>By default
<code class="literal">MultiLevelElementNameAndTextQualifier</code>
will not ignore whitespace between the elements leading up
to the nested text. If your piece of XML contains this sort
of whitespace (like <a class="xref" href="ar01s03.html#htmltable" title="Example20.Example for RecursiveElementNameAndTextQualifier (the comments are not part of the example)">Example20, “Example for
<code class="literal">RecursiveElementNameAndTextQualifier</code>
(the comments are not part of the example)”</a> which
contains a newline and several space characters between
<code class="literal"><tr></code> and
<code class="literal"><td></code>) you can either instruct
XMLUnit to ignore whitespace completely (see
<a class="xref" href="ar01s03.html#Whitespace%20Handling" title="3.8.1.Whitespace Handling">Section3.8.1, “Whitespace Handling”</a>) or use the two-arg
constructor of
<code class="literal">MultiLevelElementNameAndTextQualifier</code>
introduced with XMLUnit 1.2 and set the
<code class="literal">ignoreEmptyTexts</code> argument to
true.</p>
<p>In
general <code class="literal">RecursiveElementNameAndTextQualifier</code>
requires less knowledge upfront and its whitespace-handling
is more intuitive.</p>
</div>
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Diff"></a>3.5.<code class="literal">Diff</code> and
<code class="literal">DetailedDiff</code></h3></div></div></div>
<p><code class="literal">Diff</code> and
<code class="literal">DetailedDiff</code> provide simplified access to
<code class="literal">DifferenceEngine</code> by implementing the
<code class="literal">ComparisonController</code> and
<code class="literal">DifferenceListener</code> interfaces themselves.
They cover the two most common use cases for comparing two
pieces of XML: checking whether the pieces are different (this
is what <code class="literal">Diff</code> does) and finding all
differences between them (this is what
<code class="literal">DetailedDiff</code> does).</p>
<p><code class="literal">DetailedDiff</code> is a subclass of
<code class="literal">Diff</code> and can only be constructed by creating
a <code class="literal">Diff</code> instance first.</p>
<p>The major difference between them is their implementation
of the <code class="literal">ComparisonController</code> interface:
<code class="literal">DetailedDiff</code> will never stop the comparison
since it wants to collect all differences.
<code class="literal">Diff</code> in turn will halt the comparison as soon
as the first <code class="literal">Difference</code> is found that is not
recoverable. In addition <code class="literal">DetailedDiff</code>
collects all <code class="literal">Difference</code>s in a list and
provides access to it.</p>
<p>By default <code class="literal">Diff</code> will consider two
pieces of XML as identical if no differences have been found at
all, similar if all differences that have been found have been
recoverable (see <a class="xref" href="ar01s03.html#docleveldiff" title="Table1.Document level Differences detected by DifferenceEngine">Table1, “Document level <code class="literal">Difference</code>s detected by
<code class="literal">DifferenceEngine</code>”</a> to <a class="xref" href="ar01s03.html#otherdiff" title="Table4.Other Differences detected by DifferenceEngine">Table4, “Other <code class="literal">Difference</code>s detected by
<code class="literal">DifferenceEngine</code>”</a>) and different as soon as any
non-recoverable difference has been found.</p>
<p>It is possible to specify a
<code class="literal">DifferenceListener</code> to <code class="literal">Diff</code>
using the <code class="literal">overrideDifferenceListener</code> method.
In this case each <code class="literal">Difference</code> will be
evaluated by the passed in
<code class="literal">DifferenceListener</code>. By returning
<code class="literal">RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL</code> the
custom listener can make <code class="literal">Diff</code> ignore the
difference completely. Likewise any
<code class="literal">Difference</code> for which the custom listener
returns
<code class="literal">RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR</code> will
be treated as if the <code class="literal">Difference</code> was
recoverable.</p>
<p>There are several overloads of the <code class="literal">Diff</code>
constructor that allow you to specify your piece of XML in many
ways. There are overloads that accept additional
<code class="literal">DifferenceEngine</code> and
<code class="literal">ElementQualifier</code> arguments. Passing in a
<code class="literal">DifferenceEngine</code> of your own is the only way
to use a <code class="literal">ComparisonController</code> other than
<code class="literal">Diff</code>.</p>
<p>Note that <code class="literal">Diff</code> and
<code class="literal">DetailedDiff</code> use
<code class="literal">ElementNameQualifier</code> as their default
<code class="literal">ElementQualifier</code>. This is different from
<code class="literal">DifferenceEngine</code> which defaults to no
<code class="literal">ElementQualifier</code> at all.</p>
<p>To use a custom <code class="literal">ElementQualifier</code> you
can also use the <code class="literal">overrideElementQualifier</code>
method. Use this with an argument of <code class="literal">null</code> to
unset the default <code class="literal">ElementQualifier</code> as
well.</p>
<p>To compare two pieces of XML you'd create a
<code class="literal">Diff</code> instance from those two pieces and
invoke <code class="literal">identical</code> to check that there have
been no differences at all and <code class="literal">similar</code> to
check that any difference, if any, has been recoverable. If the
pieces are identical they are also similar. Likewise if they
are not similar they can't be identical either.</p>
<div class="example"><a name="idp43049808"></a><p class="title"><b>Example21.Comparing Two Pieces of XML Using
<code class="literal">Diff</code></b></p><div class="example-contents">
<pre class="programlisting">
Diff d = new Diff("<a><b/><c/></a>", "<a><c/><b/></a>");
assertFalse(d.identical()); // CHILD_NODELIST_SEQUENCE Difference
assertTrue(d.similar());
</pre></div></div><br class="example-break">
<p>The result of the comparison is cached in
<code class="literal">Diff</code>, repeated invocations of
<code class="literal">identical</code> or <code class="literal">similar</code> will
not reevaluate the pieces of XML.</p>
<p>Note: calling <code class="literal">toString</code> on an instance
of <code class="literal">Diff</code> or <code class="literal">DetailedDiff</code>
will perform the comparision and cache its result immediately.
If you change the <code class="literal">DifferenceListener</code> or
<code class="literal">ElementQualifier</code> after calling
<code class="literal">toString</code> it won't have any effect.</p>
<p><code class="literal">DetailedDiff</code> provides only a single
constructor that expects a <code class="literal">Diff</code> as argument.
Don't use <code class="literal">DetailedDiff</code> if all you need to
know is whether two pieces of XML are identical/similar - use
<code class="literal">Diff</code> directly since its short-cut
<code class="literal">ComparisonController</code> implementation will save
time in this case.</p>
<div class="example"><a name="idp43063888"></a><p class="title"><b>Example22.Finding All Differences Using
<code class="literal">DetailedDiff</code></b></p><div class="example-contents">
<pre class="programlisting">
Diff d = new Diff("<a><b/><c/></a>", "<a><c/><b/></a>");
DetailedDiff dd = new DetailedDiff(d);
dd.overrideElementQualifier(null);
assertFalse(dd.similar());
List l = dd.getAllDifferences();
assertEquals(2, l.size()); // expected <b/> but was <c/> and vice versa
</pre></div></div><br class="example-break">
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="MatchTracker"></a>3.6.<code class="literal">MatchTracker</code></h3></div></div></div>
<p>Sometimes you might be interested in any sort of
comparison result and want to get notified of successful matches
as well. Maybe you want to provide feedback on the amount of
differences and similarities between two documents, for
example.</p>
<p>The interface <code class="literal">MatchTracker</code> can be
implemented to get notified on each and every successful match,
note that there may be a lot more comparisons going on than you
might expect and that your callback gets notified a lot.</p>
<div class="example"><a name="idp43070192"></a><p class="title"><b>Example23.The <code class="literal">MatchTracker</code> interface</b></p><div class="example-contents">
<pre class="programlisting">
package org.custommonkey.xmlunit;
/**
* Listener for callbacks from a {@link DifferenceEngine#compare
* DifferenceEngine comparison} that is notified on each and every
* comparision that resulted in a match.
*/
public interface MatchTracker {
/**
* Receive notification that 2 match.
* @param match a Difference instance as defined in {@link
* DifferenceConstants DifferenceConstants} describing the test
* that matched and containing the detail of the nodes that have
* been compared
*/
void matchFound(Difference difference);
}
</pre></div></div><br class="example-break">
<p>Despite its name the <code class="literal">Difference</code>
instance passed into the <code class="literal">matchFound</code> method
really describes a match and not a difference. You can expect
that the <code class="literal">getValue</code> method on both the
control and the test <code class="literal">NodeDetail</code> will be
equal.</p>
<p><code class="literal">DifferenceEngine</code> provides a constructor
overload that allows you to pass in
a <code class="literal">MatchTracker</code> instance and also provides
a <code class="literal">setMatchTracker</code>
method. <code class="literal">Diff</code>
and <code class="literal">DetailedDiff</code>
provide <code class="literal">overrideMatchTracker</code> methods that
fill the same purpose.</p>
<p>Note that your <code class="literal">MatchTracker</code> won't
receive any callbacks once the
configured <code class="literal">ComparisonController</code> has decided
that <code class="literal">DifferenceEngine</code> should halt the
comparison.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Comparing:%20JUnit%203"></a>3.7.JUnit 3.x Convenience Methods</h3></div></div></div>
<p><code class="literal">XMLAssert</code> and
<code class="literal">XMLTestCase</code> contain quite a few overloads of
methods for comparing two pieces of XML.</p>
<p>The method's names use the word <code class="literal">Equal</code>
to mean the same as <code class="literal">similar</code> in the
<code class="literal">Diff</code> class (or throughout this guide). So
<code class="literal">assertXMLEqual</code> will assert that only
recoverable differences have been encountered where
<code class="literal">assertXMLNotEqual</code> asserts that some
differences have been non-recoverable.
<code class="literal">assertXMLIdentical</code> asserts that there haven't
been any differences at all while
<code class="literal">assertXMLNotIdentical</code> asserts that there have
been differences (recoverable or not).</p>
<p>Most of the overloads of <code class="literal">assertXMLEqual</code>
just provide different means to specify the pieces of XML as
<code class="literal">String</code>s, <code class="literal">InputSource</code>s,
<code class="literal">Reader</code>s<a href="#ftn.idp43096928" class="footnote" name="idp43096928"><sup class="footnote">[7]</sup></a> or <code class="literal">Document</code>s. For each
method there is a version that takes an additional
<code class="literal">err</code> argument which is used to create the
message if the assertion fails.</p>
<p>If you don't need any control over the
<code class="literal">ElementQualifier</code> or
<code class="literal">DifferenceListener</code> used by
<code class="literal">Diff</code> these methods will save some boilerplate
code. If <code class="literal">CONTROL</code> and <code class="literal">TEST</code>
are pieces of XML represented as one of the supported inputs
then</p>
<pre class="programlisting">
Diff d = new Diff(CONTROL, TEST);
assertTrue("expected pieces to be similar, " + d.toString(),
d.similar());
</pre>
<p>and</p>
<pre class="programlisting">
assertXMLEqual("expected pieces to be similar", CONTROL, TEST);
</pre>
<p>are equivalent.</p>
<p>If you need more control over the <code class="literal">Diff</code>
instance there is a version of <code class="literal">assertXMLEqual</code>
(and <code class="literal">assertXMLIdentical</code>) that accepts a
<code class="literal">Diff</code> instance as its argument as well as a
<code class="literal">boolean</code> indicating whether you expect the
<code class="literal">Diff</code> to be <code class="literal">similar</code>
(<code class="literal">identical</code>) or not.</p>
<p><code class="literal">XMLTestCase</code> contains a couple of
<code class="literal">compareXML</code> methods that really are only
shortcuts to <code class="literal">Diff</code>'s constructors.</p>
<p>There is no way to use <code class="literal">DifferenceEngine</code>
or <code class="literal">DetailedDiff</code> directly via the convenience
methods.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="Comparing:%20Configuration"></a>3.8.Configuration Options</h3></div></div></div>
<p>Unless you are using <code class="literal">Document</code> or
<code class="literal">DOMSource</code> overrides when specifying your
pieces of XML, XMLUnit will use the configured XML parsers (see
<a class="xref" href="ar01s02.html#JAXP" title="2.4.1.JAXP">Section2.4.1, “JAXP”</a>) and <code class="literal">EntityResolver</code>s
(see <a class="xref" href="ar01s02.html#EntityResolver" title="2.4.2.EntityResolver">Section2.4.2, “<code class="literal">EntityResolver</code>”</a>). There are configuration
options to use different settings for the control and test
pieces of XML.</p>
<p>In addition some of the other configuration settings may
lead to XMLUnit using the configured XSLT transformer (see <a class="xref" href="ar01s02.html#JAXP" title="2.4.1.JAXP">Section2.4.1, “JAXP”</a>) under the covers.</p>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Whitespace%20Handling"></a>3.8.1.Whitespace Handling</h4></div></div></div>
<p>Two different configuration options affect how XMLUnit
treats whitespace in comparisons:</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Element Content Whitespace (see <a class="xref" href="ar01s02.html#Basic:%20Element%20Content%20Whitespace" title="2.4.3.Element Content Whitespace">Section2.4.3, “Element Content Whitespace”</a>)
<p>If XMLUnit has been configured to ignore element
content whitespace it will trim any text nodes found by
the parser. This means that there won't appear to be any
textual content in element <code class="literal"><foo></code>
for the following example. If you don't set
<code class="literal">XMLUnit.setIgnoreWhitespace</code> there would
be textual content consisting of a new line
character.</p>
<pre class="programlisting">
<foo>
</foo>
</pre>
<p>At the same time the following two
<code class="literal"><foo></code> elements will be considered
identical if the option has been enabled, though.</p>
<pre class="programlisting">
<foo>bar</foo>
<foo> bar </foo>
</pre>
<p>When this option is set to <code class="literal">true</code>,
<code class="literal">Diff</code> will use the XSLT transformer
under the covers.</p>
</li><li class="listitem">"Normalizing" Whitespace
<p>If you set
<code class="literal">XMLUnit.setNormalizeWhitespace</code> to true
then XMLUnit will replace any kind of whitespace found in
character content with a SPACE character and collapse
consecutive whitespace characters to a single SPACE. It
will also trim the resulting character content on both
ends.</p>
<p>The following two <code class="literal"><foo></code>
elements will be considered identical if the option has
been set:</p>
<pre class="programlisting">
<foo>bar baz</foo>
<foo> bar
baz</foo>
</pre>
<p>Note that this is not related to "normalizing" the
document as a whole (see <a class="xref" href="ar01s03.html#Normalizing%20Documents" title='3.8.2."Normalizing" Documents'>Section3.8.2, “"Normalizing" <code class="literal">Document</code>s”</a>).</p>
</li></ul></div>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Normalizing%20Documents"></a>3.8.2."Normalizing" <code class="literal">Document</code>s</h4></div></div></div>
<p>"Normalize" in this context corresponds to the
<code class="literal">normalize</code> method in DOM's
<code class="literal">Document</code> class. It is the process of
merging adjacent <code class="literal">Text</code> nodes and is not
related to "normalizing whitespace" as described in the
previous section.</p>
<p>Usually you don't need to care about this option since
the XML parser is required to normalize the
<code class="literal">Document</code> when creating it. The only reason
you may want to change the option via
<code class="literal">XMLUnit.setNormalize</code> is that your
<code class="literal">Document</code> instances have not been created by
an XML parser but rather been put together in memory using the
DOM API directly.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Ignoring%20Comments"></a>3.8.3.Ignoring Comments</h4></div></div></div>
<p>Using <code class="literal">XMLUnit.setIgnoreComments</code> you
can make XMLUnit's difference engine ignore comments
completely.</p>
<p>When this option is set to <code class="literal">true</code>,
<code class="literal">Diff</code> will use the XSLT transformer under
the covers.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Treating%20CDATA%20Sections%20and%20Text%20Nodes%20Alike"></a>3.8.4.Treating CDATA Sections and Text Nodes Alike</h4></div></div></div>
<p>It is not always necessary to know whether a text has
been put into a CDATA section or not. Using
<code class="literal">XMLUnit.setIgnoreDiffBetweenTextAndCDATA</code>
you can make XMLUnit consider the following two pieces of XML
identical:</p>
<pre class="programlisting">
<foo>&lt;bar&gt;</foo>
</pre>
<pre class="programlisting">
<foo><![CDATA[<bar>]]></foo>
</pre>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Entity%20Reference%20Expansion"></a>3.8.5.Entity Reference Expansion</h4></div></div></div>
<p>Normally the XML parser will expand character references
to their Unicode equivalents but for more complex entity
definitions the parser may expand them or not.
Using <code class="literal">XMLUnit.setExpandEntityReferences</code> you
can control the parser's setting.</p>
</div>
<div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="Comparison%20of%20Unmatched%20Elements"></a>3.8.6.Comparison of Unmatched Elements</h4></div></div></div>
<p>When XMLUnit cannot match a control Element to a test
Element (the configured ElementQualifier - see
<a class="xref" href="ar01s03.html#ElementQualifier" title="3.4.ElementQualifier">Section3.4, “<code class="literal">ElementQualifier</code>”</a> - doesn't return true for
any of the test Elements) it will try to compare it against
the first unmatched test Element (if there is one).
Starting with XMLUnit 1.3 one can
use <code class="literal">XMLUnit.setCompareUnmatched</code> to
disable this behavior and
generate <code class="literal">CHILD_NODE_NOT_FOUND</code> differences
instead.</p>
<p>If the control document is
</p><pre class="programlisting">
<root>
<a/>
</root>
</pre><p>
and the test document is
</p><pre class="programlisting">
<root>
<b/>
</root>
</pre><p>
the default setting will create a
single <code class="literal">ELEMENT_TAG_NAME</code> Difference
("expected a but found b").
Setting <code class="literal">XMLUnit.setCompareUnmatched</code> to
false will create two Differences of
type <code class="literal">CHILD_NODE_NOT_FOUND</code> (one for "a" and
one for "b") instead.</p>
</div>
</div>
<div class="footnotes"><br><hr style="width:100; text-align:left;margin-left: 0"><div id="ftn.idp43096928" class="footnote"><p><a href="#idp43096928" class="para"><sup class="para">[7] </sup></a>See <a class="xref" href="ar01s02.html#Providing%20Input%20to%20XMLUnit" title="2.5.Providing Input to XMLUnit">Section2.5, “Providing Input to XMLUnit”</a> for some advice on choosing your input
format.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s02.html">Prev</a></td><td width="20%" align="center"></td><td width="40%" align="right"><a accesskey="n" href="ar01s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2.Using XMLUnit</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">4.Validating XML Documents</td></tr></table></div></body></html>
|