1--TEST-- 2DOMNode::isEqualNode() 3--EXTENSIONS-- 4dom 5--SKIPIF-- 6<?php 7if (LIBXML_VERSION >= 21200 && LIBXML_VERSION <= 21201) { 8 die("xfail Broken for libxml2 2.12.0 - 2.12.1 see https://gitlab.gnome.org/GNOME/libxml2/-/issues/634"); 9} 10?> 11--FILE-- 12<?php 13 14$dom1 = new DOMDocument(); 15$dom2 = new DOMDocument(); 16 17$dom1->loadXML(<<<XML 18<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" [ 19 <!ENTITY bar '<bar>bartext</bar>'> 20 <!ENTITY foo '<foo/>'> 21 <!NOTATION myNotation SYSTEM "test.dtd"> 22]> 23<html> 24 <body> 25 <pi><?test 123?><?test2 123?><?test2 1234?><?test 123?></pi> 26 <ps><p>text</p><p>text</p><p>other text</p></ps> 27 <psattrs><p align="center" xmlns:foo="some:bar">text</p><p xmlns:foo="some:bar">text</p><p align="center">text</p><p align="left" xmlns:foo="some:bar">text</p><p align="center" xmlns:foo="some:bar2">text</p><p align="center" xmlns:foo="some:bar">text</p></psattrs> 28 <comments><!-- comment 1 --><!-- comment 2 --><!-- comment 1 --></comments> 29 <texts>abc<i/>def<i/>abc</texts> 30 <cdatas><![CDATA[test]]> <![CDATA[test2]]> <![CDATA[test]]></cdatas> 31 <tree> 32 <div> 33 <p>A</p> 34 <div foo="bar"> 35 <p>B</p> 36 </div> 37 </div> 38 <p>A</p> 39 </tree> 40 </body> 41</html> 42XML); 43 44$xpath = new DOMXPath($dom1); 45 46function foreach_comparator($query) { 47 global $xpath; 48 $container = $xpath->query($query)[0]; 49 $childNodes = iterator_to_array($container->childNodes); 50 $firstChild = $childNodes[0]; 51 foreach ($childNodes as $child) { 52 var_dump($child->isEqualNode($firstChild)); 53 } 54} 55 56function comparePairs($list1, $list2) { 57 $list1 = iterator_to_array($list1); 58 $list2 = iterator_to_array($list2); 59 usort($list1, function ($a, $b) { 60 return strcmp($a->nodeName, $b->nodeName); 61 }); 62 usort($list2, function ($a, $b) { 63 return strcmp($a->nodeName, $b->nodeName); 64 }); 65 foreach ($list1 as $entity1) { 66 foreach ($list2 as $entity2) { 67 echo "Comparing {$entity1->nodeName} with {$entity2->nodeName}\n"; 68 var_dump($entity1->isEqualNode($entity2)); 69 } 70 } 71} 72 73echo "--- Test edge cases ---\n"; 74 75var_dump($dom1->doctype->isEqualNode(null)); 76var_dump((new DOMDocument())->isEqualNode(new DOMDocument())); 77 78echo "--- Test doctype ---\n"; 79 80var_dump($dom1->doctype->isEqualNode($dom1->doctype)); 81$dom2->loadXML('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/x.dtd"><html/>'); 82var_dump($dom1->doctype->isEqualNode($dom2->doctype)); 83$dom2->loadXML('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN2" "http://www.w3.org/TR/html4/strict.dtd"><html/>'); 84var_dump($dom1->doctype->isEqualNode($dom2->doctype)); 85$dom2->loadXML('<!DOCTYPE HTML2 PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html/>'); 86var_dump($dom1->doctype->isEqualNode($dom2->doctype)); 87$dom2->loadXML('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html/>'); 88var_dump($dom1->doctype->isEqualNode($dom2->doctype)); 89 90echo "--- Test processing instruction ---\n"; 91 92foreach_comparator("//pi"); 93 94echo "--- Test comments ---\n"; 95 96foreach_comparator("//comments"); 97 98echo "--- Test texts ---\n"; 99 100foreach_comparator("//texts"); 101 102echo "--- Test CDATA ---\n"; 103 104foreach_comparator("//cdatas"); 105 106echo "--- Test attribute ---\n"; 107 108var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("name", "value"))); 109var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("name", "value2"))); 110var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("name2", "value"))); 111var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("name2", "value2"))); 112var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("ns:name", "value"))); 113 114echo "--- Test entity reference ---\n"; 115 116var_dump((new DOMEntityReference("ref"))->isEqualNode(new DOMEntityReference("ref"))); 117var_dump((new DOMEntityReference("ref"))->isEqualNode(new DOMEntityReference("ref2"))); 118 119echo "--- Test entity declaration ---\n"; 120 121$dom2->loadXML(<<<XML 122<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" [ 123 <!ENTITY barbar '<bar>bartext</bar>'> 124 <!ENTITY foo '<foo2/>'> 125 <!ENTITY bar '<bar>bartext</bar>'> 126]> 127<html/> 128XML); 129 130comparePairs($dom1->doctype->entities, $dom2->doctype->entities); 131 132echo "--- Test notation declaration ---\n"; 133 134$dom2->loadXML(<<<XML 135<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" [ 136 <!NOTATION myNotation SYSTEM "test.dtd"> 137 <!NOTATION myNotation2 SYSTEM "test2.dtd"> 138 <!NOTATION myNotation3 SYSTEM "test.dtd"> 139]> 140<html/> 141XML); 142 143comparePairs($dom1->doctype->notations, $dom2->doctype->notations); 144 145echo "--- Test element without attributes ---\n"; 146 147foreach_comparator("//ps"); 148 149echo "--- Test element with attributes ---\n"; 150 151foreach_comparator("//psattrs"); 152 153echo "--- Test element tree ---\n"; 154 155$tree = $xpath->query("//tree")[0]; 156$dom2->loadXML(<<<XML 157 <tree> 158 <div> 159 <p>A</p> 160 <div foo="bar"> 161 <p>B</p> 162 </div> 163 </div> 164 <p>A</p> 165 </tree> 166XML); 167var_dump($tree->isEqualNode($dom2->documentElement)); 168$dom2->loadXML(<<<XML 169 <tree> 170 <p>A</p> 171 <div> 172 <p>A</p> 173 <div foo="bar"> 174 <p>B</p> 175 </div> 176 </div> 177 </tree> 178XML); 179var_dump($tree->isEqualNode($dom2->documentElement)); 180$dom2->loadXML(<<<XML 181 <tree> 182 <div> 183 <p>A</p> 184 <div foo="bar"> 185 </div> 186 </div> 187 <p>A</p> 188 </tree> 189XML); 190var_dump($tree->isEqualNode($dom2->documentElement)); 191$dom2->loadXML(<<<XML 192 <tree> 193 <div> 194 <p>A</p> 195 <div foo="bar" extra="attr"> 196 <p>B</p> 197 </div> 198 </div> 199 <p>A</p> 200 </tree> 201XML); 202var_dump($tree->isEqualNode($dom2->documentElement)); 203 204echo "--- Test documents ---\n"; 205 206$dom1Clone = clone $dom1; 207var_dump($dom1->documentElement->isEqualNode($dom1Clone->documentElement)); 208var_dump($dom1->documentElement->isEqualNode($dom2->documentElement)); 209var_dump($dom1->isEqualNode($dom1Clone)); 210var_dump($dom1->isEqualNode($dom2)); 211var_dump($dom1->documentElement->isEqualNode($dom1Clone)); 212var_dump($dom1->documentElement->isEqualNode($dom2)); 213 214echo "--- Test document fragments ---\n"; 215 216$fragment1 = $dom1->createDocumentFragment(); 217$fragment1->appendChild($dom1->createElement('em')); 218$fragment2 = $dom1->createDocumentFragment(); 219$fragment2->appendChild($dom1->createElement('em')); 220$fragment3 = $dom1->createDocumentFragment(); 221$fragment3->appendChild($dom1->createElement('b')); 222$emptyFragment1 = $dom1->createDocumentFragment(); 223$emptyFragment2 = $dom1->createDocumentFragment(); 224 225var_dump($fragment1->isEqualNode($fragment2)); 226var_dump($fragment1->isEqualNode($fragment3)); 227var_dump($emptyFragment1->isEqualNode($fragment1)); 228var_dump($emptyFragment1->isEqualNode($emptyFragment2)); 229 230echo "--- Test document fragments with multiple child nodes ---\n"; 231 232$fragment1 = $dom1->createDocumentFragment(); 233$fragment1->appendChild($dom1->createElement('a')); 234$fragment1->appendChild($dom1->createElement('b')); 235$fragment1->appendChild($dom1->createElement('c')); 236$fragment2 = $dom2->createDocumentFragment(); 237$fragment2->appendChild($dom2->createElement('a')); 238$fragment2->appendChild($dom2->createElement('b')); 239$fragment2->appendChild($dom2->createElement('c')); 240 241var_dump($fragment1->isEqualNode($fragment2)); 242 243$fragment2->firstChild->nextSibling->nextSibling->remove(); 244var_dump($fragment1->isEqualNode($fragment2)); 245 246echo "--- Test x:includes ---\n"; 247 248// Adapted from https://www.php.net/manual/en/domdocument.xinclude.php 249$dom = new DOMDocument(); 250$dom->loadXML(<<<XML 251<?xml version="1.0" ?> 252<chapter xmlns:xi="http://www.w3.org/2001/XInclude"> 253 <p>Hello</p> 254 <para> 255 <xi:include href="book.xml"> 256 <xi:fallback> 257 <p>xinclude: book.xml not found</p> 258 </xi:fallback> 259 </xi:include> 260 </para> 261 <para><p>xinclude: book.xml not found</p></para> 262</chapter> 263XML); 264@$dom->xinclude(); 265$xpath = new DOMXPath($dom); 266 267$firstPara = $dom->documentElement->firstElementChild->nextElementSibling; 268$secondPara = $dom->documentElement->firstElementChild->nextElementSibling->nextElementSibling; 269var_dump($firstPara->isEqualNode($secondPara)); 270var_dump($firstPara->firstElementChild->isEqualNode($secondPara->firstElementChild)); 271 272?> 273--EXPECT-- 274--- Test edge cases --- 275bool(false) 276bool(true) 277--- Test doctype --- 278bool(true) 279bool(false) 280bool(false) 281bool(false) 282bool(true) 283--- Test processing instruction --- 284bool(true) 285bool(false) 286bool(false) 287bool(true) 288--- Test comments --- 289bool(true) 290bool(false) 291bool(true) 292--- Test texts --- 293bool(true) 294bool(false) 295bool(false) 296bool(false) 297bool(true) 298--- Test CDATA --- 299bool(true) 300bool(false) 301bool(false) 302bool(false) 303bool(true) 304--- Test attribute --- 305bool(true) 306bool(false) 307bool(false) 308bool(false) 309bool(false) 310--- Test entity reference --- 311bool(true) 312bool(false) 313--- Test entity declaration --- 314Comparing bar with bar 315bool(true) 316Comparing bar with barbar 317bool(false) 318Comparing bar with foo 319bool(false) 320Comparing foo with bar 321bool(false) 322Comparing foo with barbar 323bool(false) 324Comparing foo with foo 325bool(true) 326--- Test notation declaration --- 327Comparing myNotation with myNotation 328bool(true) 329Comparing myNotation with myNotation2 330bool(false) 331Comparing myNotation with myNotation3 332bool(false) 333--- Test element without attributes --- 334bool(true) 335bool(true) 336bool(false) 337--- Test element with attributes --- 338bool(true) 339bool(false) 340bool(false) 341bool(false) 342bool(false) 343bool(true) 344--- Test element tree --- 345bool(true) 346bool(false) 347bool(false) 348bool(false) 349--- Test documents --- 350bool(true) 351bool(false) 352bool(true) 353bool(false) 354bool(false) 355bool(false) 356--- Test document fragments --- 357bool(true) 358bool(false) 359bool(false) 360bool(true) 361--- Test document fragments with multiple child nodes --- 362bool(true) 363bool(false) 364--- Test x:includes --- 365bool(false) 366bool(true) 367