diff --git a/NEWS b/NEWS index 0fdaff6cb23..c35ca25dcd2 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ PHP NEWS - DOM: . Added DOMNode::contains() and DOMNameSpaceNode::contains(). (nielsdos) + . Added DOMElement::getAttributeNames(). (nielsdos) - Intl: . Fix memory leak in MessageFormatter::format() on failure. (Girgias) diff --git a/UPGRADING b/UPGRADING index 345947f45f0..d6fd8d6e74f 100644 --- a/UPGRADING +++ b/UPGRADING @@ -242,6 +242,7 @@ PHP 8.3 UPGRADE NOTES - DOM: . Added DOMNode::contains() and DOMNameSpaceNode::contains(). + . Added DOMElement::getAttributeNames(). - JSON: . Added json_validate(), which returns whether the json is valid for diff --git a/ext/dom/element.c b/ext/dom/element.c index e57871d3113..5df99a7b66b 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -242,6 +242,39 @@ PHP_METHOD(DOMElement, getAttribute) } /* }}} end dom_element_get_attribute */ +/* {{{ URL: https://dom.spec.whatwg.org/#dom-element-getattributenames +Since: +*/ +PHP_METHOD(DOMElement, getAttributeNames) +{ + zval *id; + xmlNode *nodep; + dom_object *unused_intern; + zval tmp; + + if (zend_parse_parameters_none() == FAILURE) { + RETURN_THROWS(); + } + + DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, unused_intern); + + array_init(return_value); + HashTable *ht = Z_ARRVAL_P(return_value); + zend_hash_real_init_packed(ht); + + for (xmlNsPtr nsptr = nodep->nsDef; nsptr; nsptr = nsptr->next) { + const char *prefix = (const char *) nsptr->prefix; + ZVAL_STR(&tmp, dom_node_concatenated_name_helper(strlen(prefix), prefix, strlen("xmlns"), (const char *) "xmlns")); + zend_hash_next_index_insert(ht, &tmp); + } + + for (xmlAttrPtr attr = nodep->properties; attr; attr = attr->next) { + ZVAL_STR(&tmp, dom_node_get_node_name_attribute_or_element((const xmlNode *) attr)); + zend_hash_next_index_insert(ht, &tmp); + } +} +/* }}} end DOMElement::getAttributeNames() */ + /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-F68F082 Since: */ diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index 3c3cf649293..521db1e632b 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -563,6 +563,8 @@ class DOMElement extends DOMNode implements DOMParentNode, DOMChildNode /** @tentative-return-type */ public function getAttribute(string $qualifiedName): string {} + public function getAttributeNames(): array {} + /** @tentative-return-type */ public function getAttributeNS(?string $namespace, string $localName): string {} diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h index cf47f1dae4f..16a20a3774e 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: fd3acd731f178c2f1034b206b46d53c236823b9f */ + * Stub hash: e3efd06d963e7a29d9869b7204133ccc8a22bf3b */ 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) @@ -193,6 +193,9 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DOMElement_getAt ZEND_ARG_TYPE_INFO(0, qualifiedName, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_DOMElement_getAttributeNames, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DOMElement_getAttributeNS, 0, 2, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, namespace, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, localName, IS_STRING, 0) @@ -541,6 +544,7 @@ ZEND_METHOD(DOMAttr, __construct); ZEND_METHOD(DOMAttr, isId); ZEND_METHOD(DOMElement, __construct); ZEND_METHOD(DOMElement, getAttribute); +ZEND_METHOD(DOMElement, getAttributeNames); ZEND_METHOD(DOMElement, getAttributeNS); ZEND_METHOD(DOMElement, getAttributeNode); ZEND_METHOD(DOMElement, getAttributeNodeNS); @@ -758,6 +762,7 @@ static const zend_function_entry class_DOMAttr_methods[] = { static const zend_function_entry class_DOMElement_methods[] = { ZEND_ME(DOMElement, __construct, arginfo_class_DOMElement___construct, ZEND_ACC_PUBLIC) ZEND_ME(DOMElement, getAttribute, arginfo_class_DOMElement_getAttribute, ZEND_ACC_PUBLIC) + ZEND_ME(DOMElement, getAttributeNames, arginfo_class_DOMElement_getAttributeNames, ZEND_ACC_PUBLIC) ZEND_ME(DOMElement, getAttributeNS, arginfo_class_DOMElement_getAttributeNS, ZEND_ACC_PUBLIC) ZEND_ME(DOMElement, getAttributeNode, arginfo_class_DOMElement_getAttributeNode, ZEND_ACC_PUBLIC) ZEND_ME(DOMElement, getAttributeNodeNS, arginfo_class_DOMElement_getAttributeNodeNS, ZEND_ACC_PUBLIC) diff --git a/ext/dom/tests/DOMElement_getAttributeNames.phpt b/ext/dom/tests/DOMElement_getAttributeNames.phpt new file mode 100644 index 00000000000..c4df228960b --- /dev/null +++ b/ext/dom/tests/DOMElement_getAttributeNames.phpt @@ -0,0 +1,38 @@ +--TEST-- +DOMElement::getAttributeNames() +--EXTENSIONS-- +dom +--FILE-- +loadXML($str); + var_dump($dom->documentElement->getAttributeNames()); + foreach ($dom->documentElement->getAttributeNames() as $name) { + assert($dom->documentElement->getAttributeNode($name)->nodeName === $name); + } +} + +test(''); +test(''); +test(''); + +?> +--EXPECT-- +array(3) { + [0]=> + string(10) "xmlns:some" + [1]=> + string(9) "some:test" + [2]=> + string(5) "test2" +} +array(2) { + [0]=> + string(4) "test" + [1]=> + string(5) "test3" +} +array(0) { +}