From b0f416a07a076c85159643b3388ef98573fe1377 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 11 Jul 2023 19:43:37 +0200 Subject: [PATCH] Implement DOMNode::parentElement and DOMNameSpaceNode::parentElement ref: https://dom.spec.whatwg.org/#parent-element --- ext/dom/dom_properties.h | 1 + ext/dom/node.c | 37 ++++++++---- ext/dom/php_dom.c | 2 + ext/dom/php_dom.stub.php | 6 ++ ext/dom/php_dom_arginfo.h | 16 +++++- ...OMNode_DOMNameSpaceNode_parentElement.phpt | 57 +++++++++++++++++++ ext/dom/tests/bug69846.phpt | 14 +++-- ext/dom/tests/bug70359.phpt | 2 + ext/dom/tests/bug78577.phpt | 4 +- ext/dom/tests/bug80602_3.phpt | 8 ++- ext/dom/tests/clone_nodes.phpt | 4 +- ext/dom/tests/domobject_debug_handler.phpt | 1 + ext/dom/tests/xpath_domnamespacenode.phpt | 4 +- 13 files changed, 135 insertions(+), 21 deletions(-) create mode 100644 ext/dom/tests/DOMNode_DOMNameSpaceNode_parentElement.phpt diff --git a/ext/dom/dom_properties.h b/ext/dom/dom_properties.h index 32f2419323833..d5bee5e7c2f19 100644 --- a/ext/dom/dom_properties.h +++ b/ext/dom/dom_properties.h @@ -95,6 +95,7 @@ int dom_node_node_value_read(dom_object *obj, zval *retval); int dom_node_node_value_write(dom_object *obj, zval *newval); int dom_node_node_type_read(dom_object *obj, zval *retval); int dom_node_parent_node_read(dom_object *obj, zval *retval); +zend_result dom_node_parent_element_read(dom_object *obj, zval *retval); int dom_node_child_nodes_read(dom_object *obj, zval *retval); int dom_node_first_child_read(dom_object *obj, zval *retval); int dom_node_last_child_read(dom_object *obj, zval *retval); diff --git a/ext/dom/node.c b/ext/dom/node.c index 14fa030ccda8b..c744a15e51424 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -225,24 +225,17 @@ int dom_node_node_type_read(dom_object *obj, zval *retval) /* }}} */ -/* {{{ parentNode DomNode -readonly=yes -URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1060184317 -Since: -*/ -int dom_node_parent_node_read(dom_object *obj, zval *retval) +static zend_result dom_node_parent_get(dom_object *obj, zval *retval, bool only_element) { - xmlNode *nodep, *nodeparent; - - nodep = dom_object_get_node(obj); + xmlNodePtr nodep = dom_object_get_node(obj); if (nodep == NULL) { php_dom_throw_error(INVALID_STATE_ERR, 1); return FAILURE; } - nodeparent = nodep->parent; - if (!nodeparent) { + xmlNodePtr nodeparent = nodep->parent; + if (!nodeparent || (only_element && nodeparent->type != XML_ELEMENT_NODE)) { ZVAL_NULL(retval); return SUCCESS; } @@ -251,6 +244,28 @@ int dom_node_parent_node_read(dom_object *obj, zval *retval) return SUCCESS; } +/* {{{ parentNode ?DomNode +readonly=yes +URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1060184317 +Since: +*/ +int dom_node_parent_node_read(dom_object *obj, zval *retval) +{ + return dom_node_parent_get(obj, retval, false); +} + +/* }}} */ + +/* {{{ parentElement ?DomElement +readonly=yes +URL: https://dom.spec.whatwg.org/#parent-element +Since: +*/ +zend_result dom_node_parent_element_read(dom_object *obj, zval *retval) +{ + return dom_node_parent_get(obj, retval, true); +} + /* }}} */ /* {{{ childNodes DomNodeList diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 453b4d95ecc91..a4b4202ae7d66 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -636,6 +636,7 @@ PHP_MINIT_FUNCTION(dom) dom_register_prop_handler(&dom_node_prop_handlers, "nodeValue", sizeof("nodeValue")-1, dom_node_node_value_read, dom_node_node_value_write); dom_register_prop_handler(&dom_node_prop_handlers, "nodeType", sizeof("nodeType")-1, dom_node_node_type_read, NULL); dom_register_prop_handler(&dom_node_prop_handlers, "parentNode", sizeof("parentNode")-1, dom_node_parent_node_read, NULL); + dom_register_prop_handler(&dom_node_prop_handlers, "parentElement", sizeof("parentElement")-1, dom_node_parent_element_read, NULL); dom_register_prop_handler(&dom_node_prop_handlers, "childNodes", sizeof("childNodes")-1, dom_node_child_nodes_read, NULL); dom_register_prop_handler(&dom_node_prop_handlers, "firstChild", sizeof("firstChild")-1, dom_node_first_child_read, NULL); dom_register_prop_handler(&dom_node_prop_handlers, "lastChild", sizeof("lastChild")-1, dom_node_last_child_read, NULL); @@ -662,6 +663,7 @@ PHP_MINIT_FUNCTION(dom) dom_register_prop_handler(&dom_namespace_node_prop_handlers, "namespaceURI", sizeof("namespaceURI")-1, dom_node_namespace_uri_read, NULL); dom_register_prop_handler(&dom_namespace_node_prop_handlers, "ownerDocument", sizeof("ownerDocument")-1, dom_node_owner_document_read, NULL); dom_register_prop_handler(&dom_namespace_node_prop_handlers, "parentNode", sizeof("parentNode")-1, dom_node_parent_node_read, NULL); + dom_register_prop_handler(&dom_namespace_node_prop_handlers, "parentElement", sizeof("parentElement")-1, dom_node_parent_element_read, NULL); zend_hash_add_ptr(&classes, dom_namespace_node_class_entry->name, &dom_namespace_node_prop_handlers); dom_documentfragment_class_entry = register_class_DOMDocumentFragment(dom_node_class_entry, dom_parentnode_class_entry); diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index 741f7bf1d9e10..db05df93848aa 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -305,6 +305,9 @@ class DOMNode /** @readonly */ public ?DOMNode $parentNode; + /** @readonly */ + public ?DOMElement $parentElement; + /** @readonly */ public DOMNodeList $childNodes; @@ -417,6 +420,9 @@ class DOMNameSpaceNode /** @readonly */ public ?DOMNode $parentNode; + + /** @readonly */ + public ?DOMElement $parentElement; } class DOMImplementation diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h index 1459a9891bb08..590fc7048c376 100644 --- a/ext/dom/php_dom_arginfo.h +++ b/ext/dom/php_dom_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 00d59fd45c44eb14bbf8f51ee4f61e0464786d69 */ + * Stub hash: 1178fd913f9d1dbc919d76985bddd8c98e560711 */ 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) @@ -1064,6 +1064,13 @@ static zend_class_entry *register_class_DOMNode(void) zend_declare_typed_property(class_entry, property_parentNode_name, &property_parentNode_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_parentNode_class_DOMNode, 0, MAY_BE_NULL)); zend_string_release(property_parentNode_name); + zval property_parentElement_default_value; + ZVAL_UNDEF(&property_parentElement_default_value); + zend_string *property_parentElement_name = zend_string_init("parentElement", sizeof("parentElement") - 1, 1); + zend_string *property_parentElement_class_DOMElement = zend_string_init("DOMElement", sizeof("DOMElement")-1, 1); + zend_declare_typed_property(class_entry, property_parentElement_name, &property_parentElement_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_parentElement_class_DOMElement, 0, MAY_BE_NULL)); + zend_string_release(property_parentElement_name); + zval property_childNodes_default_value; ZVAL_UNDEF(&property_childNodes_default_value); zend_string *property_childNodes_name = zend_string_init("childNodes", sizeof("childNodes") - 1, 1); @@ -1204,6 +1211,13 @@ static zend_class_entry *register_class_DOMNameSpaceNode(void) zend_declare_typed_property(class_entry, property_parentNode_name, &property_parentNode_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_parentNode_class_DOMNode, 0, MAY_BE_NULL)); zend_string_release(property_parentNode_name); + zval property_parentElement_default_value; + ZVAL_UNDEF(&property_parentElement_default_value); + zend_string *property_parentElement_name = zend_string_init("parentElement", sizeof("parentElement") - 1, 1); + zend_string *property_parentElement_class_DOMElement = zend_string_init("DOMElement", sizeof("DOMElement")-1, 1); + zend_declare_typed_property(class_entry, property_parentElement_name, &property_parentElement_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_parentElement_class_DOMElement, 0, MAY_BE_NULL)); + zend_string_release(property_parentElement_name); + return class_entry; } diff --git a/ext/dom/tests/DOMNode_DOMNameSpaceNode_parentElement.phpt b/ext/dom/tests/DOMNode_DOMNameSpaceNode_parentElement.phpt new file mode 100644 index 0000000000000..dec4ac227f74c --- /dev/null +++ b/ext/dom/tests/DOMNode_DOMNameSpaceNode_parentElement.phpt @@ -0,0 +1,57 @@ +--TEST-- +DOMNode::parentElement and DOMNameSpaceNode::parentElement +--EXTENSIONS-- +dom +--FILE-- +loadXML(<< + + + +XML); + +echo "--- body test ---\n"; + +$body = $dom->documentElement->firstElementChild; +var_dump($body->parentNode->localName); +var_dump($body->parentElement->localName); + +echo "--- document test ---\n"; + +var_dump(get_class($dom->documentElement->parentNode)); +var_dump($dom->documentElement->parentElement); + +var_dump(get_class($dom->doctype->parentNode)); +var_dump($dom->doctype->parentElement); + +echo "--- fragment test ---\n"; + +$fragment = $dom->createDocumentFragment(); +$p = $fragment->appendChild($dom->createElement('p')); + +var_dump(get_class($p->parentNode)); +var_dump($p->parentElement); + +$body->appendChild($fragment); + +var_dump($p->parentNode->localName); +var_dump($p->parentElement->localName); + +?> +--EXPECT-- +--- body test --- +string(4) "html" +string(4) "html" +--- document test --- +string(11) "DOMDocument" +NULL +string(11) "DOMDocument" +NULL +--- fragment test --- +string(19) "DOMDocumentFragment" +NULL +string(4) "body" +string(4) "body" diff --git a/ext/dom/tests/bug69846.phpt b/ext/dom/tests/bug69846.phpt index 7655d203fa22f..37448307778b8 100644 --- a/ext/dom/tests/bug69846.phpt +++ b/ext/dom/tests/bug69846.phpt @@ -28,9 +28,9 @@ foreach ($dataNodes AS $node) { } ?> ---EXPECTF-- +--EXPECT-- int(3) -object(DOMText)#%d (21) { +object(DOMText)#7 (22) { ["wholeText"]=> string(3) " " @@ -52,6 +52,8 @@ object(DOMText)#%d (21) { int(3) ["parentNode"]=> NULL + ["parentElement"]=> + NULL ["childNodes"]=> string(22) "(object value omitted)" ["firstChild"]=> @@ -78,7 +80,7 @@ object(DOMText)#%d (21) { string(3) " " } -object(DOMElement)#7 (23) { +object(DOMElement)#7 (24) { ["schemaTypeInfo"]=> NULL ["tagName"]=> @@ -105,6 +107,8 @@ object(DOMElement)#7 (23) { int(1) ["parentNode"]=> NULL + ["parentElement"]=> + NULL ["childNodes"]=> string(22) "(object value omitted)" ["firstChild"]=> @@ -134,7 +138,7 @@ object(DOMElement)#7 (23) { Value C " } -object(DOMText)#%d (21) { +object(DOMText)#7 (22) { ["wholeText"]=> string(1) " " @@ -156,6 +160,8 @@ object(DOMText)#%d (21) { int(3) ["parentNode"]=> NULL + ["parentElement"]=> + NULL ["childNodes"]=> string(22) "(object value omitted)" ["firstChild"]=> diff --git a/ext/dom/tests/bug70359.phpt b/ext/dom/tests/bug70359.phpt index 697097bf88287..3dd86a075aa02 100644 --- a/ext/dom/tests/bug70359.phpt +++ b/ext/dom/tests/bug70359.phpt @@ -59,6 +59,7 @@ DOMNameSpaceNode Object [namespaceURI] => http://www.sitemaps.org/schemas/sitemap/0.9 [ownerDocument] => (object value omitted) [parentNode] => (object value omitted) + [parentElement] => (object value omitted) ) -- Test with parent and non-ns attribute -- int(2) @@ -75,5 +76,6 @@ DOMNameSpaceNode Object [namespaceURI] => fooooooooooooooooooooo [ownerDocument] => (object value omitted) [parentNode] => (object value omitted) + [parentElement] => (object value omitted) ) string(3) "url" diff --git a/ext/dom/tests/bug78577.phpt b/ext/dom/tests/bug78577.phpt index 2631efc1e206c..4d140f5ca5a60 100644 --- a/ext/dom/tests/bug78577.phpt +++ b/ext/dom/tests/bug78577.phpt @@ -13,7 +13,7 @@ var_dump($attr); ?> --EXPECT-- -object(DOMNameSpaceNode)#3 (8) { +object(DOMNameSpaceNode)#3 (9) { ["nodeName"]=> string(5) "xmlns" ["nodeValue"]=> @@ -30,4 +30,6 @@ object(DOMNameSpaceNode)#3 (8) { string(22) "(object value omitted)" ["parentNode"]=> string(22) "(object value omitted)" + ["parentElement"]=> + string(22) "(object value omitted)" } diff --git a/ext/dom/tests/bug80602_3.phpt b/ext/dom/tests/bug80602_3.phpt index f9bf67e778da5..72b60b80c11cc 100644 --- a/ext/dom/tests/bug80602_3.phpt +++ b/ext/dom/tests/bug80602_3.phpt @@ -21,7 +21,7 @@ var_dump($target); ?> --EXPECTF-- barfoobaz -object(DOMElement)#3 (23) { +object(DOMElement)#3 (24) { ["schemaTypeInfo"]=> NULL ["tagName"]=> @@ -44,6 +44,8 @@ object(DOMElement)#3 (23) { int(1) ["parentNode"]=> string(22) "(object value omitted)" + ["parentElement"]=> + string(22) "(object value omitted)" ["childNodes"]=> string(22) "(object value omitted)" ["firstChild"]=> @@ -70,7 +72,7 @@ object(DOMElement)#3 (23) { string(0) "" } barfoobaz -object(DOMElement)#2 (23) { +object(DOMElement)#2 (24) { ["schemaTypeInfo"]=> NULL ["tagName"]=> @@ -93,6 +95,8 @@ object(DOMElement)#2 (23) { int(1) ["parentNode"]=> string(22) "(object value omitted)" + ["parentElement"]=> + string(22) "(object value omitted)" ["childNodes"]=> string(22) "(object value omitted)" ["firstChild"]=> diff --git a/ext/dom/tests/clone_nodes.phpt b/ext/dom/tests/clone_nodes.phpt index 1841c702caf8d..647b95da04462 100644 --- a/ext/dom/tests/clone_nodes.phpt +++ b/ext/dom/tests/clone_nodes.phpt @@ -44,7 +44,7 @@ var_dump($barClone->parentNode); ?> --EXPECT-- -- Clone DOMNameSpaceNode -- -object(DOMNameSpaceNode)#3 (8) { +object(DOMNameSpaceNode)#3 (9) { ["nodeName"]=> string(5) "xmlns" ["nodeValue"]=> @@ -61,6 +61,8 @@ object(DOMNameSpaceNode)#3 (8) { string(22) "(object value omitted)" ["parentNode"]=> string(22) "(object value omitted)" + ["parentElement"]=> + string(22) "(object value omitted)" } string(19) "http://php.net/test" string(3) "foo" diff --git a/ext/dom/tests/domobject_debug_handler.phpt b/ext/dom/tests/domobject_debug_handler.phpt index 8318fc70ed17e..e90cfa0d8615c 100644 --- a/ext/dom/tests/domobject_debug_handler.phpt +++ b/ext/dom/tests/domobject_debug_handler.phpt @@ -48,6 +48,7 @@ DOMDocument Object [nodeValue] => [nodeType] => 9 [parentNode] => + [parentElement] => [childNodes] => (object value omitted) [firstChild] => (object value omitted) [lastChild] => (object value omitted) diff --git a/ext/dom/tests/xpath_domnamespacenode.phpt b/ext/dom/tests/xpath_domnamespacenode.phpt index 97059c18e54da..1d483284b3c8b 100644 --- a/ext/dom/tests/xpath_domnamespacenode.phpt +++ b/ext/dom/tests/xpath_domnamespacenode.phpt @@ -17,7 +17,7 @@ var_dump($nodes->item(0)); ?> --EXPECT-- -object(DOMNameSpaceNode)#4 (8) { +object(DOMNameSpaceNode)#4 (9) { ["nodeName"]=> string(9) "xmlns:xml" ["nodeValue"]=> @@ -34,4 +34,6 @@ object(DOMNameSpaceNode)#4 (8) { string(22) "(object value omitted)" ["parentNode"]=> string(22) "(object value omitted)" + ["parentElement"]=> + string(22) "(object value omitted)" }