1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Implement DOMNode::parentElement and DOMNameSpaceNode::parentElement

ref: https://dom.spec.whatwg.org/#parent-element

Closes GH-11679.
This commit is contained in:
Niels Dossche
2023-07-11 19:43:37 +02:00
parent d38cc9b9b6
commit d04f48b6ac
15 changed files with 138 additions and 21 deletions

2
NEWS
View File

@@ -26,6 +26,8 @@ PHP NEWS
. Added DOMElement::className and DOMElement::id. (nielsdos)
. Added DOMParentNode::replaceChildren(). (nielsdos)
. Added DOMNode::isConnected and DOMNameSpaceNode::isConnected. (nielsdos)
. Added DOMNode::parentElement and DOMNameSpaceNode::parentElement.
(nielsdos)
- FPM:
. Added warning to log when fpm socket was not registered on the expected

View File

@@ -269,6 +269,7 @@ PHP 8.3 UPGRADE NOTES
libxml2.
. Added DOMParentNode::replaceChildren().
. Added DOMNode::isConnected and DOMNameSpaceNode::isConnected.
. Added DOMNode::parentElement and DOMNameSpaceNode::parentElement.
- JSON:
. Added json_validate(), which returns whether the json is valid for

View File

@@ -99,6 +99,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);

View File

@@ -237,24 +237,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;
}
@@ -263,6 +256,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

View File

@@ -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);
@@ -664,6 +665,7 @@ PHP_MINIT_FUNCTION(dom)
dom_register_prop_handler(&dom_namespace_node_prop_handlers, "isConnected", sizeof("isConnected")-1, dom_node_is_connected_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);

View File

@@ -308,6 +308,9 @@ class DOMNode
/** @readonly */
public ?DOMNode $parentNode;
/** @readonly */
public ?DOMElement $parentElement;
/** @readonly */
public DOMNodeList $childNodes;
@@ -430,6 +433,9 @@ class DOMNameSpaceNode
/** @readonly */
public ?DOMNode $parentNode;
/** @readonly */
public ?DOMElement $parentElement;
}
class DOMImplementation

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 78e4089fa17aa0faa371917aeb48fa0dfe1819b0 */
* Stub hash: 02e8c582a3a7d88fc32ef8931c23c0c6de5a94e2 */
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)
@@ -1096,6 +1096,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);
@@ -1248,6 +1255,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;
}

View File

@@ -0,0 +1,57 @@
--TEST--
DOMNode::parentElement and DOMNameSpaceNode::parentElement
--EXTENSIONS--
dom
--FILE--
<?php
$dom = new DOMDocument();
$dom->loadXML(<<<XML
<!DOCTYPE HTML>
<html>
<body/>
</html>
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"

View File

@@ -28,9 +28,9 @@ foreach ($dataNodes AS $node) {
}
?>
--EXPECTF--
--EXPECT--
int(3)
object(DOMText)#%d (22) {
object(DOMText)#7 (23) {
["wholeText"]=>
string(3) "
"
@@ -52,6 +52,8 @@ object(DOMText)#%d (22) {
int(3)
["parentNode"]=>
NULL
["parentElement"]=>
NULL
["childNodes"]=>
string(22) "(object value omitted)"
["firstChild"]=>
@@ -80,7 +82,7 @@ object(DOMText)#%d (22) {
string(3) "
"
}
object(DOMElement)#7 (26) {
object(DOMElement)#7 (27) {
["schemaTypeInfo"]=>
NULL
["tagName"]=>
@@ -111,6 +113,8 @@ object(DOMElement)#7 (26) {
int(1)
["parentNode"]=>
NULL
["parentElement"]=>
NULL
["childNodes"]=>
string(22) "(object value omitted)"
["firstChild"]=>
@@ -142,7 +146,7 @@ object(DOMElement)#7 (26) {
Value C
"
}
object(DOMText)#%d (22) {
object(DOMText)#7 (23) {
["wholeText"]=>
string(1) "
"
@@ -164,6 +168,8 @@ object(DOMText)#%d (22) {
int(3)
["parentNode"]=>
NULL
["parentElement"]=>
NULL
["childNodes"]=>
string(22) "(object value omitted)"
["firstChild"]=>

View File

@@ -60,6 +60,7 @@ DOMNameSpaceNode Object
[isConnected] => 1
[ownerDocument] => (object value omitted)
[parentNode] => (object value omitted)
[parentElement] => (object value omitted)
)
-- Test with parent and non-ns attribute --
int(2)
@@ -77,5 +78,6 @@ DOMNameSpaceNode Object
[isConnected] => 1
[ownerDocument] => (object value omitted)
[parentNode] => (object value omitted)
[parentElement] => (object value omitted)
)
string(3) "url"

View File

@@ -13,7 +13,7 @@ var_dump($attr);
?>
--EXPECT--
object(DOMNameSpaceNode)#3 (9) {
object(DOMNameSpaceNode)#3 (10) {
["nodeName"]=>
string(5) "xmlns"
["nodeValue"]=>
@@ -32,4 +32,6 @@ object(DOMNameSpaceNode)#3 (9) {
string(22) "(object value omitted)"
["parentNode"]=>
string(22) "(object value omitted)"
["parentElement"]=>
string(22) "(object value omitted)"
}

View File

@@ -21,7 +21,7 @@ var_dump($target);
?>
--EXPECTF--
<a>barfoobaz<last/></a>
object(DOMElement)#3 (26) {
object(DOMElement)#3 (27) {
["schemaTypeInfo"]=>
NULL
["tagName"]=>
@@ -48,6 +48,8 @@ object(DOMElement)#3 (26) {
int(1)
["parentNode"]=>
string(22) "(object value omitted)"
["parentElement"]=>
string(22) "(object value omitted)"
["childNodes"]=>
string(22) "(object value omitted)"
["firstChild"]=>
@@ -76,7 +78,7 @@ object(DOMElement)#3 (26) {
string(0) ""
}
<a><last/>barfoobaz</a>
object(DOMElement)#2 (26) {
object(DOMElement)#2 (27) {
["schemaTypeInfo"]=>
NULL
["tagName"]=>
@@ -103,6 +105,8 @@ object(DOMElement)#2 (26) {
int(1)
["parentNode"]=>
string(22) "(object value omitted)"
["parentElement"]=>
string(22) "(object value omitted)"
["childNodes"]=>
string(22) "(object value omitted)"
["firstChild"]=>

View File

@@ -44,7 +44,7 @@ var_dump($barClone->parentNode);
?>
--EXPECT--
-- Clone DOMNameSpaceNode --
object(DOMNameSpaceNode)#3 (9) {
object(DOMNameSpaceNode)#3 (10) {
["nodeName"]=>
string(5) "xmlns"
["nodeValue"]=>
@@ -63,6 +63,8 @@ object(DOMNameSpaceNode)#3 (9) {
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"

View File

@@ -48,6 +48,7 @@ DOMDocument Object
[nodeValue] =>
[nodeType] => 9
[parentNode] =>
[parentElement] =>
[childNodes] => (object value omitted)
[firstChild] => (object value omitted)
[lastChild] => (object value omitted)

View File

@@ -17,7 +17,7 @@ var_dump($nodes->item(0));
?>
--EXPECT--
object(DOMNameSpaceNode)#4 (9) {
object(DOMNameSpaceNode)#4 (10) {
["nodeName"]=>
string(9) "xmlns:xml"
["nodeValue"]=>
@@ -36,4 +36,6 @@ object(DOMNameSpaceNode)#4 (9) {
string(22) "(object value omitted)"
["parentNode"]=>
string(22) "(object value omitted)"
["parentElement"]=>
string(22) "(object value omitted)"
}