mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Implement DOMNode::isEqualNode()
Since we still support obsoleted nodes in our implementation, this uses the old spec to match the old nodes; and this uses the new spec for nodes still defined in the living spec. When unclear, the behaviour was cross-verified with Firefox. References: https://dom.spec.whatwg.org/#dom-node-isequalnode (for everything still in the living spec) https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/DOM3-Core.html#core-Node3-isEqualNode (for old nodes removed from the living spec) Closes GH-11690.
This commit is contained in:
1
NEWS
1
NEWS
@@ -28,6 +28,7 @@ PHP NEWS
|
||||
. Added DOMNode::isConnected and DOMNameSpaceNode::isConnected. (nielsdos)
|
||||
. Added DOMNode::parentElement and DOMNameSpaceNode::parentElement.
|
||||
(nielsdos)
|
||||
. Added DOMNode::isEqualNode(). (nielsdos)
|
||||
|
||||
- FPM:
|
||||
. Added warning to log when fpm socket was not registered on the expected
|
||||
|
||||
@@ -270,6 +270,7 @@ PHP 8.3 UPGRADE NOTES
|
||||
. Added DOMParentNode::replaceChildren().
|
||||
. Added DOMNode::isConnected and DOMNameSpaceNode::isConnected.
|
||||
. Added DOMNode::parentElement and DOMNameSpaceNode::parentElement.
|
||||
. Added DOMNode::isEqualNode().
|
||||
|
||||
- JSON:
|
||||
. Added json_validate(), which returns whether the json is valid for
|
||||
|
||||
149
ext/dom/node.c
149
ext/dom/node.c
@@ -1471,6 +1471,155 @@ PHP_METHOD(DOMNode, isSameNode)
|
||||
}
|
||||
/* }}} end dom_node_is_same_node */
|
||||
|
||||
static bool php_dom_node_is_content_equal(const xmlNode *this, const xmlNode *other)
|
||||
{
|
||||
xmlChar *this_content = xmlNodeGetContent(this);
|
||||
xmlChar *other_content = xmlNodeGetContent(other);
|
||||
bool result = xmlStrEqual(this_content, other_content);
|
||||
xmlFree(this_content);
|
||||
xmlFree(other_content);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool php_dom_node_is_ns_uri_equal(const xmlNode *this, const xmlNode *other)
|
||||
{
|
||||
const xmlChar *this_ns = this->ns ? this->ns->href : NULL;
|
||||
const xmlChar *other_ns = other->ns ? other->ns->href : NULL;
|
||||
return xmlStrEqual(this_ns, other_ns);
|
||||
}
|
||||
|
||||
static bool php_dom_node_is_ns_prefix_equal(const xmlNode *this, const xmlNode *other)
|
||||
{
|
||||
const xmlChar *this_ns = this->ns ? this->ns->prefix : NULL;
|
||||
const xmlChar *other_ns = other->ns ? other->ns->prefix : NULL;
|
||||
return xmlStrEqual(this_ns, other_ns);
|
||||
}
|
||||
|
||||
static bool php_dom_node_is_equal_node(const xmlNode *this, const xmlNode *other);
|
||||
|
||||
#define PHP_DOM_FUNC_CAT(prefix, suffix) prefix##_##suffix
|
||||
/* xmlNode and xmlNs have incompatible struct layouts, i.e. the next field is in a different offset */
|
||||
#define PHP_DOM_DEFINE_LIST_EQUALITY_HELPER(type) \
|
||||
static size_t PHP_DOM_FUNC_CAT(php_dom_node_count_list_size, type)(const type *node) \
|
||||
{ \
|
||||
size_t counter = 0; \
|
||||
while (node) { \
|
||||
counter++; \
|
||||
node = node->next; \
|
||||
} \
|
||||
return counter; \
|
||||
} \
|
||||
static bool PHP_DOM_FUNC_CAT(php_dom_node_list_equality_check, type)(const type *list1, const type *list2) \
|
||||
{ \
|
||||
size_t count = PHP_DOM_FUNC_CAT(php_dom_node_count_list_size, type)(list1); \
|
||||
if (count != PHP_DOM_FUNC_CAT(php_dom_node_count_list_size, type)(list2)) { \
|
||||
return false; \
|
||||
} \
|
||||
for (size_t i = 0; i < count; i++) { \
|
||||
if (!php_dom_node_is_equal_node((const xmlNode *) list1, (const xmlNode *) list2)) { \
|
||||
return false; \
|
||||
} \
|
||||
list1 = list1->next; \
|
||||
list2 = list2->next; \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
PHP_DOM_DEFINE_LIST_EQUALITY_HELPER(xmlNode)
|
||||
PHP_DOM_DEFINE_LIST_EQUALITY_HELPER(xmlNs)
|
||||
|
||||
static bool php_dom_node_is_equal_node(const xmlNode *this, const xmlNode *other)
|
||||
{
|
||||
ZEND_ASSERT(this != NULL);
|
||||
ZEND_ASSERT(other != NULL);
|
||||
|
||||
if (this->type != other->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Notes:
|
||||
* - XML_DOCUMENT_TYPE_NODE is no longer created by libxml2, we only have to support XML_DTD_NODE.
|
||||
* - element and attribute declarations are not exposed as nodes in DOM, so no comparison is needed for those. */
|
||||
if (this->type == XML_ELEMENT_NODE) {
|
||||
return xmlStrEqual(this->name, other->name)
|
||||
&& php_dom_node_is_ns_prefix_equal(this, other)
|
||||
&& php_dom_node_is_ns_uri_equal(this, other)
|
||||
/* Check attributes first, then namespace declarations, then children */
|
||||
&& php_dom_node_list_equality_check_xmlNode((const xmlNode *) this->properties, (const xmlNode *) other->properties)
|
||||
&& php_dom_node_list_equality_check_xmlNs(this->nsDef, other->nsDef)
|
||||
&& php_dom_node_list_equality_check_xmlNode(this->children, other->children);
|
||||
} else if (this->type == XML_DTD_NODE) {
|
||||
/* Note: in the living spec entity declarations and notations are no longer compared because they're considered obsolete. */
|
||||
const xmlDtd *this_dtd = (const xmlDtd *) this;
|
||||
const xmlDtd *other_dtd = (const xmlDtd *) other;
|
||||
return xmlStrEqual(this_dtd->name, other_dtd->name)
|
||||
&& xmlStrEqual(this_dtd->ExternalID, other_dtd->ExternalID)
|
||||
&& xmlStrEqual(this_dtd->SystemID, other_dtd->SystemID);
|
||||
} else if (this->type == XML_PI_NODE) {
|
||||
return xmlStrEqual(this->name, other->name) && xmlStrEqual(this->content, other->content);
|
||||
} else if (this->type == XML_TEXT_NODE || this->type == XML_COMMENT_NODE || this->type == XML_CDATA_SECTION_NODE) {
|
||||
return xmlStrEqual(this->content, other->content);
|
||||
} else if (this->type == XML_ATTRIBUTE_NODE) {
|
||||
const xmlAttr *this_attr = (const xmlAttr *) this;
|
||||
const xmlAttr *other_attr = (const xmlAttr *) other;
|
||||
return xmlStrEqual(this_attr->name, other_attr->name)
|
||||
&& php_dom_node_is_ns_uri_equal(this, other)
|
||||
&& php_dom_node_is_content_equal(this, other);
|
||||
} else if (this->type == XML_ENTITY_REF_NODE) {
|
||||
return xmlStrEqual(this->name, other->name);
|
||||
} else if (this->type == XML_ENTITY_DECL || this->type == XML_NOTATION_NODE || this->type == XML_ENTITY_NODE) {
|
||||
const xmlEntity *this_entity = (const xmlEntity *) this;
|
||||
const xmlEntity *other_entity = (const xmlEntity *) other;
|
||||
return this_entity->etype == other_entity->etype
|
||||
&& xmlStrEqual(this_entity->name, other_entity->name)
|
||||
&& xmlStrEqual(this_entity->ExternalID, other_entity->ExternalID)
|
||||
&& xmlStrEqual(this_entity->SystemID, other_entity->SystemID)
|
||||
&& php_dom_node_is_content_equal(this, other);
|
||||
} else if (this->type == XML_NAMESPACE_DECL) {
|
||||
const xmlNs *this_ns = (const xmlNs *) this;
|
||||
const xmlNs *other_ns = (const xmlNs *) other;
|
||||
return xmlStrEqual(this_ns->prefix, other_ns->prefix) && xmlStrEqual(this_ns->href, other_ns->href);
|
||||
} else if (this->type == XML_DOCUMENT_FRAG_NODE || this->type == XML_HTML_DOCUMENT_NODE || this->type == XML_DOCUMENT_NODE) {
|
||||
return php_dom_node_list_equality_check_xmlNode(this->children, other->children);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* {{{ URL: https://dom.spec.whatwg.org/#dom-node-isequalnode (for everything still in the living spec)
|
||||
* URL: https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/DOM3-Core.html#core-Node3-isEqualNode (for old nodes removed from the living spec)
|
||||
Since: DOM Level 3
|
||||
*/
|
||||
PHP_METHOD(DOMNode, isEqualNode)
|
||||
{
|
||||
zval *id, *node;
|
||||
xmlNodePtr otherp, nodep;
|
||||
dom_object *unused_intern;
|
||||
|
||||
id = ZEND_THIS;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O!", &node, dom_node_class_entry) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (node == NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, unused_intern);
|
||||
DOM_GET_OBJ(otherp, node, xmlNodePtr, unused_intern);
|
||||
|
||||
if (nodep == otherp) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
|
||||
/* Empty fragments/documents only match if they're both empty */
|
||||
if (UNEXPECTED(nodep == NULL || otherp == NULL)) {
|
||||
RETURN_BOOL(nodep == NULL && otherp == NULL);
|
||||
}
|
||||
|
||||
RETURN_BOOL(php_dom_node_is_equal_node(nodep, otherp));
|
||||
}
|
||||
/* }}} end DOMNode::isEqualNode */
|
||||
|
||||
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Node3-lookupNamespacePrefix
|
||||
Since: DOM Level 3
|
||||
*/
|
||||
|
||||
@@ -381,6 +381,8 @@ class DOMNode
|
||||
/** @tentative-return-type */
|
||||
public function isSameNode(DOMNode $otherNode): bool {}
|
||||
|
||||
public function isEqualNode(?DOMNode $otherNode): bool {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function isSupported(string $feature, string $version): bool {}
|
||||
|
||||
|
||||
8
ext/dom/php_dom_arginfo.h
generated
8
ext/dom/php_dom_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 02e8c582a3a7d88fc32ef8931c23c0c6de5a94e2 */
|
||||
* Stub hash: 7070b07b2dee16222242b7e516372a6562d87036 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_dom_import_simplexml, 0, 1, DOMElement, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0)
|
||||
@@ -77,6 +77,10 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DOMNode_isSameNo
|
||||
ZEND_ARG_OBJ_INFO(0, otherNode, DOMNode, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_DOMNode_isEqualNode, 0, 1, _IS_BOOL, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, otherNode, DOMNode, 1)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DOMNode_isSupported, 0, 2, _IS_BOOL, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, feature, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, version, IS_STRING, 0)
|
||||
@@ -525,6 +529,7 @@ ZEND_METHOD(DOMNode, hasChildNodes);
|
||||
ZEND_METHOD(DOMNode, insertBefore);
|
||||
ZEND_METHOD(DOMNode, isDefaultNamespace);
|
||||
ZEND_METHOD(DOMNode, isSameNode);
|
||||
ZEND_METHOD(DOMNode, isEqualNode);
|
||||
ZEND_METHOD(DOMNode, isSupported);
|
||||
ZEND_METHOD(DOMNode, lookupNamespaceURI);
|
||||
ZEND_METHOD(DOMNode, lookupPrefix);
|
||||
@@ -713,6 +718,7 @@ static const zend_function_entry class_DOMNode_methods[] = {
|
||||
ZEND_ME(DOMNode, insertBefore, arginfo_class_DOMNode_insertBefore, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNode, isDefaultNamespace, arginfo_class_DOMNode_isDefaultNamespace, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNode, isSameNode, arginfo_class_DOMNode_isSameNode, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNode, isEqualNode, arginfo_class_DOMNode_isEqualNode, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNode, isSupported, arginfo_class_DOMNode_isSupported, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNode, lookupNamespaceURI, arginfo_class_DOMNode_lookupNamespaceURI, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNode, lookupPrefix, arginfo_class_DOMNode_lookupPrefix, ZEND_ACC_PUBLIC)
|
||||
|
||||
360
ext/dom/tests/DOMNode_isEqualNode.phpt
Normal file
360
ext/dom/tests/DOMNode_isEqualNode.phpt
Normal file
@@ -0,0 +1,360 @@
|
||||
--TEST--
|
||||
DOMNode::isEqualNode()
|
||||
--EXTENSIONS--
|
||||
dom
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$dom1 = new DOMDocument();
|
||||
$dom2 = new DOMDocument();
|
||||
|
||||
$dom1->loadXML(<<<XML
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" [
|
||||
<!ENTITY bar '<bar>bartext</bar>'>
|
||||
<!ENTITY foo '<foo/>'>
|
||||
<!NOTATION myNotation SYSTEM "test.dtd">
|
||||
]>
|
||||
<html>
|
||||
<body>
|
||||
<pi><?test 123?><?test2 123?><?test2 1234?><?test 123?></pi>
|
||||
<ps><p>text</p><p>text</p><p>other text</p></ps>
|
||||
<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>
|
||||
<comments><!-- comment 1 --><!-- comment 2 --><!-- comment 1 --></comments>
|
||||
<texts>abc<i/>def<i/>abc</texts>
|
||||
<cdatas><![CDATA[test]]> <![CDATA[test2]]> <![CDATA[test]]></cdatas>
|
||||
<tree>
|
||||
<div>
|
||||
<p>A</p>
|
||||
<div foo="bar">
|
||||
<p>B</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>A</p>
|
||||
</tree>
|
||||
</body>
|
||||
</html>
|
||||
XML);
|
||||
|
||||
$xpath = new DOMXPath($dom1);
|
||||
|
||||
function foreach_comparator($query) {
|
||||
global $xpath;
|
||||
$container = $xpath->query($query)[0];
|
||||
$childNodes = iterator_to_array($container->childNodes);
|
||||
$firstChild = $childNodes[0];
|
||||
foreach ($childNodes as $child) {
|
||||
var_dump($child->isEqualNode($firstChild));
|
||||
}
|
||||
}
|
||||
|
||||
function comparePairs($list1, $list2) {
|
||||
$list1 = iterator_to_array($list1);
|
||||
$list2 = iterator_to_array($list2);
|
||||
usort($list1, function ($a, $b) {
|
||||
return strcmp($a->nodeName, $b->nodeName);
|
||||
});
|
||||
usort($list2, function ($a, $b) {
|
||||
return strcmp($a->nodeName, $b->nodeName);
|
||||
});
|
||||
foreach ($list1 as $entity1) {
|
||||
foreach ($list2 as $entity2) {
|
||||
echo "Comparing {$entity1->nodeName} with {$entity2->nodeName}\n";
|
||||
var_dump($entity1->isEqualNode($entity2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo "--- Test edge cases ---\n";
|
||||
|
||||
var_dump($dom1->doctype->isEqualNode(null));
|
||||
var_dump((new DOMDocument())->isEqualNode(new DOMDocument()));
|
||||
|
||||
echo "--- Test doctype ---\n";
|
||||
|
||||
var_dump($dom1->doctype->isEqualNode($dom1->doctype));
|
||||
$dom2->loadXML('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/x.dtd"><html/>');
|
||||
var_dump($dom1->doctype->isEqualNode($dom2->doctype));
|
||||
$dom2->loadXML('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN2" "http://www.w3.org/TR/html4/strict.dtd"><html/>');
|
||||
var_dump($dom1->doctype->isEqualNode($dom2->doctype));
|
||||
$dom2->loadXML('<!DOCTYPE HTML2 PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html/>');
|
||||
var_dump($dom1->doctype->isEqualNode($dom2->doctype));
|
||||
$dom2->loadXML('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html/>');
|
||||
var_dump($dom1->doctype->isEqualNode($dom2->doctype));
|
||||
|
||||
echo "--- Test processing instruction ---\n";
|
||||
|
||||
foreach_comparator("//pi");
|
||||
|
||||
echo "--- Test comments ---\n";
|
||||
|
||||
foreach_comparator("//comments");
|
||||
|
||||
echo "--- Test texts ---\n";
|
||||
|
||||
foreach_comparator("//texts");
|
||||
|
||||
echo "--- Test CDATA ---\n";
|
||||
|
||||
foreach_comparator("//cdatas");
|
||||
|
||||
echo "--- Test attribute ---\n";
|
||||
|
||||
var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("name", "value")));
|
||||
var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("name", "value2")));
|
||||
var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("name2", "value")));
|
||||
var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("name2", "value2")));
|
||||
var_dump((new DOMAttr("name", "value"))->isEqualNode(new DOMAttr("ns:name", "value")));
|
||||
|
||||
echo "--- Test entity reference ---\n";
|
||||
|
||||
var_dump((new DOMEntityReference("ref"))->isEqualNode(new DOMEntityReference("ref")));
|
||||
var_dump((new DOMEntityReference("ref"))->isEqualNode(new DOMEntityReference("ref2")));
|
||||
|
||||
echo "--- Test entity declaration ---\n";
|
||||
|
||||
$dom2->loadXML(<<<XML
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" [
|
||||
<!ENTITY barbar '<bar>bartext</bar>'>
|
||||
<!ENTITY foo '<foo2/>'>
|
||||
<!ENTITY bar '<bar>bartext</bar>'>
|
||||
]>
|
||||
<html/>
|
||||
XML);
|
||||
|
||||
comparePairs($dom1->doctype->entities, $dom2->doctype->entities);
|
||||
|
||||
echo "--- Test notation declaration ---\n";
|
||||
|
||||
$dom2->loadXML(<<<XML
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" [
|
||||
<!NOTATION myNotation SYSTEM "test.dtd">
|
||||
<!NOTATION myNotation2 SYSTEM "test2.dtd">
|
||||
<!NOTATION myNotation3 SYSTEM "test.dtd">
|
||||
]>
|
||||
<html/>
|
||||
XML);
|
||||
|
||||
comparePairs($dom1->doctype->notations, $dom2->doctype->notations);
|
||||
|
||||
echo "--- Test element without attributes ---\n";
|
||||
|
||||
foreach_comparator("//ps");
|
||||
|
||||
echo "--- Test element with attributes ---\n";
|
||||
|
||||
foreach_comparator("//psattrs");
|
||||
|
||||
echo "--- Test element tree ---\n";
|
||||
|
||||
$tree = $xpath->query("//tree")[0];
|
||||
$dom2->loadXML(<<<XML
|
||||
<tree>
|
||||
<div>
|
||||
<p>A</p>
|
||||
<div foo="bar">
|
||||
<p>B</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>A</p>
|
||||
</tree>
|
||||
XML);
|
||||
var_dump($tree->isEqualNode($dom2->documentElement));
|
||||
$dom2->loadXML(<<<XML
|
||||
<tree>
|
||||
<p>A</p>
|
||||
<div>
|
||||
<p>A</p>
|
||||
<div foo="bar">
|
||||
<p>B</p>
|
||||
</div>
|
||||
</div>
|
||||
</tree>
|
||||
XML);
|
||||
var_dump($tree->isEqualNode($dom2->documentElement));
|
||||
$dom2->loadXML(<<<XML
|
||||
<tree>
|
||||
<div>
|
||||
<p>A</p>
|
||||
<div foo="bar">
|
||||
</div>
|
||||
</div>
|
||||
<p>A</p>
|
||||
</tree>
|
||||
XML);
|
||||
var_dump($tree->isEqualNode($dom2->documentElement));
|
||||
$dom2->loadXML(<<<XML
|
||||
<tree>
|
||||
<div>
|
||||
<p>A</p>
|
||||
<div foo="bar" extra="attr">
|
||||
<p>B</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>A</p>
|
||||
</tree>
|
||||
XML);
|
||||
var_dump($tree->isEqualNode($dom2->documentElement));
|
||||
|
||||
echo "--- Test documents ---\n";
|
||||
|
||||
$dom1Clone = clone $dom1;
|
||||
var_dump($dom1->documentElement->isEqualNode($dom1Clone->documentElement));
|
||||
var_dump($dom1->documentElement->isEqualNode($dom2->documentElement));
|
||||
var_dump($dom1->isEqualNode($dom1Clone));
|
||||
var_dump($dom1->isEqualNode($dom2));
|
||||
var_dump($dom1->documentElement->isEqualNode($dom1Clone));
|
||||
var_dump($dom1->documentElement->isEqualNode($dom2));
|
||||
|
||||
echo "--- Test document fragments ---\n";
|
||||
|
||||
$fragment1 = $dom1->createDocumentFragment();
|
||||
$fragment1->appendChild($dom1->createElement('em'));
|
||||
$fragment2 = $dom1->createDocumentFragment();
|
||||
$fragment2->appendChild($dom1->createElement('em'));
|
||||
$fragment3 = $dom1->createDocumentFragment();
|
||||
$fragment3->appendChild($dom1->createElement('b'));
|
||||
$emptyFragment1 = $dom1->createDocumentFragment();
|
||||
$emptyFragment2 = $dom1->createDocumentFragment();
|
||||
|
||||
var_dump($fragment1->isEqualNode($fragment2));
|
||||
var_dump($fragment1->isEqualNode($fragment3));
|
||||
var_dump($emptyFragment1->isEqualNode($fragment1));
|
||||
var_dump($emptyFragment1->isEqualNode($emptyFragment2));
|
||||
|
||||
echo "--- Test document fragments with multiple child nodes ---\n";
|
||||
|
||||
$fragment1 = $dom1->createDocumentFragment();
|
||||
$fragment1->appendChild($dom1->createElement('a'));
|
||||
$fragment1->appendChild($dom1->createElement('b'));
|
||||
$fragment1->appendChild($dom1->createElement('c'));
|
||||
$fragment2 = $dom2->createDocumentFragment();
|
||||
$fragment2->appendChild($dom2->createElement('a'));
|
||||
$fragment2->appendChild($dom2->createElement('b'));
|
||||
$fragment2->appendChild($dom2->createElement('c'));
|
||||
|
||||
var_dump($fragment1->isEqualNode($fragment2));
|
||||
|
||||
$fragment2->firstChild->nextSibling->nextSibling->remove();
|
||||
var_dump($fragment1->isEqualNode($fragment2));
|
||||
|
||||
echo "--- Test x:includes ---\n";
|
||||
|
||||
// Adapted from https://www.php.net/manual/en/domdocument.xinclude.php
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadXML(<<<XML
|
||||
<?xml version="1.0" ?>
|
||||
<chapter xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<p>Hello</p>
|
||||
<para>
|
||||
<xi:include href="book.xml">
|
||||
<xi:fallback>
|
||||
<p>xinclude: book.xml not found</p>
|
||||
</xi:fallback>
|
||||
</xi:include>
|
||||
</para>
|
||||
<para><p>xinclude: book.xml not found</p></para>
|
||||
</chapter>
|
||||
XML);
|
||||
@$dom->xinclude();
|
||||
$xpath = new DOMXPath($dom);
|
||||
|
||||
$firstPara = $dom->documentElement->firstElementChild->nextElementSibling;
|
||||
$secondPara = $dom->documentElement->firstElementChild->nextElementSibling->nextElementSibling;
|
||||
var_dump($firstPara->isEqualNode($secondPara));
|
||||
var_dump($firstPara->firstElementChild->isEqualNode($secondPara->firstElementChild));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--- Test edge cases ---
|
||||
bool(false)
|
||||
bool(true)
|
||||
--- Test doctype ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(true)
|
||||
--- Test processing instruction ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(true)
|
||||
--- Test comments ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(true)
|
||||
--- Test texts ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(true)
|
||||
--- Test CDATA ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(true)
|
||||
--- Test attribute ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
--- Test entity reference ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
--- Test entity declaration ---
|
||||
Comparing bar with bar
|
||||
bool(true)
|
||||
Comparing bar with barbar
|
||||
bool(false)
|
||||
Comparing bar with foo
|
||||
bool(false)
|
||||
Comparing foo with bar
|
||||
bool(false)
|
||||
Comparing foo with barbar
|
||||
bool(false)
|
||||
Comparing foo with foo
|
||||
bool(true)
|
||||
--- Test notation declaration ---
|
||||
Comparing myNotation with myNotation
|
||||
bool(true)
|
||||
Comparing myNotation with myNotation2
|
||||
bool(false)
|
||||
Comparing myNotation with myNotation3
|
||||
bool(false)
|
||||
--- Test element without attributes ---
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
--- Test element with attributes ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(true)
|
||||
--- Test element tree ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
--- Test documents ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
--- Test document fragments ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(true)
|
||||
--- Test document fragments with multiple child nodes ---
|
||||
bool(true)
|
||||
bool(false)
|
||||
--- Test x:includes ---
|
||||
bool(false)
|
||||
bool(true)
|
||||
Reference in New Issue
Block a user