From a1485df55ae314f1a0a5cd0d1e63583510fda1fd Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 23 Mar 2024 13:54:51 +0100 Subject: [PATCH] Implement Dom\Document::$body getter --- ext/dom/dom_properties.h | 1 + ext/dom/html_document.c | 25 +++++ ext/dom/php_dom.c | 1 + ext/dom/php_dom.stub.php | 2 + ext/dom/php_dom_arginfo.h | 9 +- .../html/interactions/Document_body.phpt | 98 +++++++++++++++++++ ...should_retain_properties_and_owner_01.phpt | 4 +- ...should_retain_properties_and_owner_02.phpt | 4 +- ...ocument_implementation_createDocument.phpt | 4 +- .../tests/modern/xml/XMLDocument_debug.phpt | 4 +- .../xml/XMLDocument_fromEmptyDocument_02.phpt | 4 +- ...MLDocument_node_ownerDocument_for_XML.phpt | 4 +- 12 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 ext/dom/tests/modern/html/interactions/Document_body.phpt diff --git a/ext/dom/dom_properties.h b/ext/dom/dom_properties.h index fc8e530b015..d5da955ebfe 100644 --- a/ext/dom/dom_properties.h +++ b/ext/dom/dom_properties.h @@ -62,6 +62,7 @@ zend_result dom_document_substitue_entities_write(dom_object *obj, zval *newval) /* html5 document properties */ zend_result dom_html_document_encoding_write(dom_object *obj, zval *retval); +zend_result dom_html_document_body_read(dom_object *obj, zval *retval); /* documenttype properties */ zend_result dom_documenttype_name_read(dom_object *obj, zval *retval); diff --git a/ext/dom/html_document.c b/ext/dom/html_document.c index 9fef8c25a8a..74a1800bbdf 100644 --- a/ext/dom/html_document.c +++ b/ext/dom/html_document.c @@ -1358,4 +1358,29 @@ zend_result dom_html_document_encoding_write(dom_object *obj, zval *newval) return SUCCESS; } +/* https://html.spec.whatwg.org/#dom-document-body */ +zend_result dom_html_document_body_read(dom_object *obj, zval *retval) +{ + DOM_PROP_NODE(const xmlDoc *, docp, obj); + + const xmlNode *root = xmlDocGetRootElement(docp); + if (root == NULL || !(php_dom_ns_is_fast(root, php_dom_ns_is_html_magic_token) && xmlStrEqual(root->name, BAD_CAST "html"))) { + ZVAL_NULL(retval); + return SUCCESS; + } + + xmlNodePtr cur = root->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE && php_dom_ns_is_fast(cur, php_dom_ns_is_html_magic_token) + && (xmlStrEqual(cur->name, BAD_CAST "body") || xmlStrEqual(cur->name, BAD_CAST "frameset"))) { + php_dom_create_object(cur, retval, obj); + return SUCCESS; + } + cur = cur->next; + } + + ZVAL_NULL(retval); + return SUCCESS; +} + #endif /* HAVE_LIBXML && HAVE_DOM */ diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 2d21a891ca5..7d0fda2918d 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -851,6 +851,7 @@ PHP_MINIT_FUNCTION(dom) DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "firstElementChild", dom_parent_node_first_element_child_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "lastElementChild", dom_parent_node_last_element_child_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "childElementCount", dom_parent_node_child_element_count, NULL); + DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "body", dom_html_document_body_read, NULL); zend_hash_merge(&dom_abstract_base_document_prop_handlers, &dom_modern_node_prop_handlers, NULL, false); /* No need to register in &classes because this is an abstract class handler. */ diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index 50fced8c466..34525d2158e 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -1580,6 +1580,8 @@ namespace Dom public function replaceChildren(Node|string ...$nodes): void {} public function importLegacyNode(\DOMNode $node, bool $deep = false): Node {} + + public ?Element $body; } final class HTMLDocument extends Document diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h index a9a61a4df79..ce7188d3952 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: c93643bad9675fddf31ca52f82f843218f208a5d */ + * Stub hash: 4d7d3a428304aa0544da0b1b57caa4e5948fa31b */ 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) @@ -3442,6 +3442,13 @@ static zend_class_entry *register_class_Dom_Document(zend_class_entry *class_ent zend_declare_typed_property(class_entry, property_childElementCount_name, &property_childElementCount_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_childElementCount_name); + zval property_body_default_value; + ZVAL_UNDEF(&property_body_default_value); + zend_string *property_body_name = zend_string_init("body", sizeof("body") - 1, 1); + zend_string *property_body_class_Dom_Element = zend_string_init("Dom\\Element", sizeof("Dom\\Element")-1, 1); + zend_declare_typed_property(class_entry, property_body_name, &property_body_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_body_class_Dom_Element, 0, MAY_BE_NULL)); + zend_string_release(property_body_name); + return class_entry; } diff --git a/ext/dom/tests/modern/html/interactions/Document_body.phpt b/ext/dom/tests/modern/html/interactions/Document_body.phpt new file mode 100644 index 00000000000..5010e6e168b --- /dev/null +++ b/ext/dom/tests/modern/html/interactions/Document_body.phpt @@ -0,0 +1,98 @@ +--TEST-- +Test Dom\Document::$body +--EXTENSIONS-- +dom +--FILE-- +foo

", LIBXML_NOERROR); +var_dump($dom->body?->nodeName); + +echo "--- After body removal ---\n"; + +$dom->body->remove(); +var_dump($dom->body?->nodeName); + +echo "--- body in no namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("", "body")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- frameset in no namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("", "frameset")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- body in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "body")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- frameset in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "frameset")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- prefixed body in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix:body")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- prefixed frameset in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix:frameset")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- multiple body-like elements in right namespace ---\n"; + +$tmp1 = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix1:body")); +var_dump($dom->body?->nodeName); +$tmp2 = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix2:frameset")); +var_dump($dom->body?->nodeName); +$tmp1->remove(); +var_dump($dom->body?->nodeName); +$tmp2->remove(); +var_dump($dom->body?->nodeName); + +echo "--- html element in no namespace ---\n"; + +$dom = Dom\XMLDocument::createFromString(<< + + +XML); +var_dump($dom->body); + +?> +--EXPECT-- +--- From parsing --- +string(4) "BODY" +--- After body removal --- +NULL +--- body in no namespace --- +NULL +--- frameset in no namespace --- +NULL +--- body in right namespace --- +string(4) "BODY" +--- frameset in right namespace --- +string(8) "FRAMESET" +--- prefixed body in right namespace --- +string(11) "PREFIX:BODY" +--- prefixed frameset in right namespace --- +string(15) "PREFIX:FRAMESET" +--- multiple body-like elements in right namespace --- +string(12) "PREFIX1:BODY" +string(12) "PREFIX1:BODY" +string(16) "PREFIX2:FRAMESET" +NULL +--- html element in no namespace --- +NULL diff --git a/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_01.phpt b/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_01.phpt index 2931aebab28..a82d882cd36 100644 --- a/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_01.phpt +++ b/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_01.phpt @@ -23,7 +23,7 @@ var_dump(get_class($dom->getElementsByTagName("p")->item(0))); ?> --EXPECT-- -object(Dom\HTMLDocument)#1 (25) { +object(Dom\HTMLDocument)#1 (26) { ["implementation"]=> string(22) "(object value omitted)" ["URL"]=> @@ -46,6 +46,8 @@ object(Dom\HTMLDocument)#1 (25) { string(22) "(object value omitted)" ["childElementCount"]=> int(1) + ["body"]=> + string(22) "(object value omitted)" ["nodeType"]=> int(13) ["nodeName"]=> diff --git a/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_02.phpt b/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_02.phpt index c356cf7ba92..67565b13fbc 100644 --- a/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_02.phpt +++ b/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_02.phpt @@ -23,7 +23,7 @@ var_dump(get_class($dom->getElementsByTagName("p")->item(0))); ?> --EXPECT-- -object(Dom\HTMLDocument)#1 (25) { +object(Dom\HTMLDocument)#1 (26) { ["implementation"]=> string(22) "(object value omitted)" ["URL"]=> @@ -46,6 +46,8 @@ object(Dom\HTMLDocument)#1 (25) { string(22) "(object value omitted)" ["childElementCount"]=> int(1) + ["body"]=> + string(22) "(object value omitted)" ["nodeType"]=> int(13) ["nodeName"]=> diff --git a/ext/dom/tests/modern/spec/Document_implementation_createDocument.phpt b/ext/dom/tests/modern/spec/Document_implementation_createDocument.phpt index 5384cf6331f..57313e42602 100644 --- a/ext/dom/tests/modern/spec/Document_implementation_createDocument.phpt +++ b/ext/dom/tests/modern/spec/Document_implementation_createDocument.phpt @@ -37,7 +37,7 @@ echo $dom->implementation->createDocument(null, "", $dtd)->saveXml(), "\n"; ?> --EXPECT-- --- (null, "") --- -object(Dom\XMLDocument)#3 (29) { +object(Dom\XMLDocument)#3 (30) { ["xmlEncoding"]=> string(5) "UTF-8" ["xmlStandalone"]=> @@ -68,6 +68,8 @@ object(Dom\XMLDocument)#3 (29) { NULL ["childElementCount"]=> int(0) + ["body"]=> + NULL ["nodeType"]=> int(9) ["nodeName"]=> diff --git a/ext/dom/tests/modern/xml/XMLDocument_debug.phpt b/ext/dom/tests/modern/xml/XMLDocument_debug.phpt index c9ae2afa95f..2d09e93e147 100644 --- a/ext/dom/tests/modern/xml/XMLDocument_debug.phpt +++ b/ext/dom/tests/modern/xml/XMLDocument_debug.phpt @@ -10,7 +10,7 @@ var_dump($dom); ?> --EXPECT-- -object(Dom\XMLDocument)#1 (29) { +object(Dom\XMLDocument)#1 (30) { ["xmlEncoding"]=> string(5) "UTF-8" ["xmlStandalone"]=> @@ -41,6 +41,8 @@ object(Dom\XMLDocument)#1 (29) { NULL ["childElementCount"]=> int(0) + ["body"]=> + NULL ["nodeType"]=> int(9) ["nodeName"]=> diff --git a/ext/dom/tests/modern/xml/XMLDocument_fromEmptyDocument_02.phpt b/ext/dom/tests/modern/xml/XMLDocument_fromEmptyDocument_02.phpt index a804394bc84..8b8fd9d2003 100644 --- a/ext/dom/tests/modern/xml/XMLDocument_fromEmptyDocument_02.phpt +++ b/ext/dom/tests/modern/xml/XMLDocument_fromEmptyDocument_02.phpt @@ -10,7 +10,7 @@ var_dump($dom); ?> --EXPECT-- -object(Dom\XMLDocument)#1 (29) { +object(Dom\XMLDocument)#1 (30) { ["xmlEncoding"]=> string(5) "UTF-8" ["xmlStandalone"]=> @@ -41,6 +41,8 @@ object(Dom\XMLDocument)#1 (29) { NULL ["childElementCount"]=> int(0) + ["body"]=> + NULL ["nodeType"]=> int(9) ["nodeName"]=> diff --git a/ext/dom/tests/modern/xml/XMLDocument_node_ownerDocument_for_XML.phpt b/ext/dom/tests/modern/xml/XMLDocument_node_ownerDocument_for_XML.phpt index 946f9495114..ee2d5b0116b 100644 --- a/ext/dom/tests/modern/xml/XMLDocument_node_ownerDocument_for_XML.phpt +++ b/ext/dom/tests/modern/xml/XMLDocument_node_ownerDocument_for_XML.phpt @@ -13,7 +13,7 @@ var_dump($element->ownerDocument); ?> --EXPECTF-- -object(Dom\XMLDocument)#1 (29) { +object(Dom\XMLDocument)#1 (30) { ["xmlEncoding"]=> string(5) "UTF-8" ["xmlStandalone"]=> @@ -44,6 +44,8 @@ object(Dom\XMLDocument)#1 (29) { string(22) "(object value omitted)" ["childElementCount"]=> int(1) + ["body"]=> + NULL ["nodeType"]=> int(9) ["nodeName"]=>