Skip to content

Commit 5101836

Browse files
committed
Implement extensions
1 parent 3d62a3a commit 5101836

12 files changed

+374
-6
lines changed

ext/dom/dom_properties.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ zend_result dom_element_class_name_write(dom_object *obj, zval *newval);
8080
zend_result dom_element_id_read(dom_object *obj, zval *retval);
8181
zend_result dom_element_id_write(dom_object *obj, zval *newval);
8282
zend_result dom_element_schema_type_info_read(dom_object *obj, zval *retval);
83+
zend_result dom_modern_element_substituted_node_value_read(dom_object *obj, zval *retval);
84+
zend_result dom_modern_element_substituted_node_value_write(dom_object *obj, zval *newval);
8385

8486
/* entity properties */
8587
zend_result dom_entity_public_id_read(dom_object *obj, zval *retval);

ext/dom/element.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,4 +1729,111 @@ PHP_METHOD(DOMElement, toggleAttribute)
17291729
}
17301730
/* }}} end DOMElement::prepend */
17311731

1732+
zend_result dom_modern_element_substituted_node_value_read(dom_object *obj, zval *retval)
1733+
{
1734+
xmlNodePtr nodep = dom_object_get_node(obj);
1735+
if (nodep == NULL) {
1736+
php_dom_throw_error(INVALID_STATE_ERR, true);
1737+
return FAILURE;
1738+
}
1739+
1740+
xmlChar *content = xmlNodeGetContent(nodep);
1741+
1742+
if (UNEXPECTED(content == NULL)) {
1743+
php_dom_throw_error(INVALID_STATE_ERR, true);
1744+
return FAILURE;
1745+
} else {
1746+
ZVAL_STRING(retval, (const char *) content);
1747+
xmlFree(content);
1748+
}
1749+
1750+
return SUCCESS;
1751+
}
1752+
1753+
zend_result dom_modern_element_substituted_node_value_write(dom_object *obj, zval *newval)
1754+
{
1755+
xmlNodePtr nodep = dom_object_get_node(obj);
1756+
if (nodep == NULL) {
1757+
php_dom_throw_error(INVALID_STATE_ERR, true);
1758+
return FAILURE;
1759+
}
1760+
1761+
php_libxml_invalidate_node_list_cache(obj->document);
1762+
dom_remove_all_children(nodep);
1763+
xmlNodeSetContentLen(nodep, (xmlChar *) Z_STRVAL_P(newval), Z_STRLEN_P(newval));
1764+
1765+
return SUCCESS;
1766+
}
1767+
1768+
PHP_METHOD(DOM_Element, getInScopeNamespaces)
1769+
{
1770+
zval *id;
1771+
xmlNode *nodep;
1772+
dom_object *intern;
1773+
1774+
if (zend_parse_parameters_none() != SUCCESS) {
1775+
RETURN_THROWS();
1776+
}
1777+
1778+
DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern);
1779+
1780+
php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(intern);
1781+
php_dom_in_scope_ns namespaces = php_dom_get_in_scope_ns(ns_mapper, nodep, true);
1782+
1783+
array_init_size(return_value, namespaces.count);
1784+
1785+
for (size_t i = 0; i < namespaces.count; i++) {
1786+
xmlNsPtr ns = namespaces.list[i];
1787+
if (ns == NULL) {
1788+
/* This case corresponds to xmlns="" */
1789+
add_assoc_null(return_value, "");
1790+
} else {
1791+
const char *prefix = (const char *) ns->prefix;
1792+
add_assoc_stringl(return_value, prefix == NULL ? "" : prefix, (const char *) ns->href, xmlStrlen(ns->href));
1793+
}
1794+
}
1795+
1796+
php_dom_in_scope_ns_destroy(&namespaces);
1797+
}
1798+
1799+
PHP_METHOD(DOM_Element, rename)
1800+
{
1801+
zend_string *namespace_uri, *qualified_name;
1802+
ZEND_PARSE_PARAMETERS_START(2, 2)
1803+
Z_PARAM_STR_OR_NULL(namespace_uri)
1804+
Z_PARAM_STR(qualified_name)
1805+
ZEND_PARSE_PARAMETERS_END();
1806+
1807+
zval *id;
1808+
dom_object *intern;
1809+
xmlNodePtr nodep;
1810+
DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern);
1811+
1812+
xmlChar *localname = NULL, *prefix = NULL;
1813+
int errorcode = dom_validate_and_extract(namespace_uri, qualified_name, &localname, &prefix);
1814+
if (UNEXPECTED(errorcode != 0)) {
1815+
php_dom_throw_error(errorcode, /* strict */ true);
1816+
goto cleanup;
1817+
}
1818+
1819+
php_libxml_invalidate_node_list_cache(intern->document);
1820+
1821+
php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(intern);
1822+
1823+
/* Update namespace uri + prefix by querying the namespace mapper */
1824+
/* prefix can be NULL here, but that is taken care of by the called APIs. */
1825+
nodep->ns = php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(ns_mapper, prefix, xmlStrlen(prefix), namespace_uri);
1826+
1827+
/* Change the local name */
1828+
if (xmlDictOwns(nodep->doc->dict, nodep->name) == 0) {
1829+
xmlFree((xmlChar *) nodep->name);
1830+
}
1831+
nodep->name = localname;
1832+
localname = NULL;
1833+
1834+
cleanup:
1835+
xmlFree(localname);
1836+
xmlFree(prefix);
1837+
}
1838+
17321839
#endif

ext/dom/namespace_compat.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ PHP_DOM_EXPORT void php_dom_libxml_reconcile_modern(php_dom_libxml_ns_mapper *ns
455455
zend_hash_destroy(&ctx.old_ns_to_new_ns_ptr);
456456
}
457457

458-
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns(php_dom_libxml_ns_mapper *ns_mapper, const xmlNode *node)
458+
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns(php_dom_libxml_ns_mapper *ns_mapper, const xmlNode *node, bool register_element_default_ns)
459459
{
460460
ZEND_ASSERT(node != NULL);
461461

@@ -472,9 +472,17 @@ PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns(php_dom_libxml_ns_map
472472
for (const xmlNode *cur = node; cur != NULL; cur = cur->parent) {
473473
if (cur->type == XML_ELEMENT_NODE) {
474474
/* Register namespace of element */
475-
if (cur->ns != NULL && cur->ns->prefix != NULL) {
475+
if (cur->ns != NULL) {
476476
const char *prefix = (const char *) cur->ns->prefix;
477-
zend_hash_str_add_ptr(&tmp_prefix_to_ns_table, prefix, strlen(prefix), cur->ns);
477+
if (register_element_default_ns || prefix != NULL) {
478+
if (prefix == NULL) {
479+
zend_hash_str_add_ptr(&tmp_prefix_to_ns_table, "", 0, cur->ns);
480+
} else {
481+
zend_hash_str_add_ptr(&tmp_prefix_to_ns_table, prefix, strlen(prefix), cur->ns);
482+
}
483+
}
484+
} else if (register_element_default_ns) {
485+
zend_hash_str_add_ptr(&tmp_prefix_to_ns_table, "", 0, NULL);
478486
}
479487

480488
/* Register xmlns attributes */

ext/dom/namespace_compat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ typedef struct _php_dom_in_scope_ns {
7070
bool origin_is_ns_compat;
7171
} php_dom_in_scope_ns;
7272

73-
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns(php_dom_libxml_ns_mapper *ns_mapper, const xmlNode *node);
73+
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns(php_dom_libxml_ns_mapper *ns_mapper, const xmlNode *node, bool register_element_default_ns);
7474
PHP_DOM_EXPORT php_dom_in_scope_ns php_dom_get_in_scope_ns_legacy(const xmlNode *node);
7575
PHP_DOM_EXPORT void php_dom_in_scope_ns_destroy(php_dom_in_scope_ns *in_scope_ns);
7676

ext/dom/php_dom.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,7 @@ PHP_MINIT_FUNCTION(dom)
10251025
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "childElementCount", dom_parent_node_child_element_count, NULL);
10261026
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "previousElementSibling", dom_node_previous_element_sibling_read, NULL);
10271027
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "nextElementSibling", dom_node_next_element_sibling_read, NULL);
1028+
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "substitutedNodeValue", dom_modern_element_substituted_node_value_read, dom_modern_element_substituted_node_value_write);
10281029
zend_hash_merge(&dom_modern_element_prop_handlers, &dom_modern_node_prop_handlers, NULL, false);
10291030
DOM_OVERWRITE_PROP_HANDLER(&dom_modern_element_prop_handlers, "textContent", dom_node_text_content_read, dom_node_text_content_write);
10301031
zend_hash_add_new_ptr(&classes, dom_modern_element_class_entry->name, &dom_modern_element_prop_handlers);

ext/dom/php_dom.stub.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,12 @@ public function append(Node|string ...$nodes): void {}
13851385
public function prepend(Node|string ...$nodes): void {}
13861386
/** @implementation-alias DOMElement::replaceChildren */
13871387
public function replaceChildren(Node|string ...$nodes): void {}
1388+
1389+
public string $substitutedNodeValue;
1390+
1391+
public function getInScopeNamespaces(): array {}
1392+
1393+
public function rename(?string $namespaceURI, string $qualifiedName): void {}
13881394
}
13891395

13901396
class Attr extends Node
@@ -1407,6 +1413,9 @@ class Attr extends Node
14071413

14081414
/** @implementation-alias DOMAttr::isId */
14091415
public function isId(): bool {}
1416+
1417+
/** @implementation-alias DOM\Element::rename */
1418+
public function rename(?string $namespaceURI, string $qualifiedName): void {}
14101419
}
14111420

14121421
class CharacterData extends Node implements ChildNode

ext/dom/php_dom_arginfo.h

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
DOM\Element::getInScopeNamespaces()
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
8+
$dom = DOM\XMLDocument::createFromString(<<<XML
9+
<root xmlns="urn:a">
10+
<child xmlns="">
11+
<c:child xmlns:c="urn:c"/>
12+
</child>
13+
<b:sibling xmlns:b="urn:b" xmlns:d="urn:d" d:foo="bar">
14+
<d:child xmlns:d="urn:d2"/>
15+
</b:sibling>
16+
</root>
17+
XML);
18+
19+
var_dump($dom->getElementsByTagName('c:child')[0]->getInScopeNamespaces());
20+
var_dump($dom->getElementsByTagName('child')[0]->getInScopeNamespaces());
21+
var_dump($dom->getElementsByTagName('b:sibling')[0]->getInScopeNamespaces());
22+
var_dump($dom->getElementsByTagName('d:child')[0]->getInScopeNamespaces());
23+
var_dump($dom->documentElement->getInScopeNamespaces());
24+
25+
?>
26+
--EXPECT--
27+
array(2) {
28+
["c"]=>
29+
string(5) "urn:c"
30+
[""]=>
31+
NULL
32+
}
33+
array(1) {
34+
[""]=>
35+
NULL
36+
}
37+
array(3) {
38+
["b"]=>
39+
string(5) "urn:b"
40+
["d"]=>
41+
string(5) "urn:d"
42+
[""]=>
43+
string(5) "urn:a"
44+
}
45+
array(3) {
46+
["d"]=>
47+
string(6) "urn:d2"
48+
["b"]=>
49+
string(5) "urn:b"
50+
[""]=>
51+
string(5) "urn:a"
52+
}
53+
array(1) {
54+
[""]=>
55+
string(5) "urn:a"
56+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
Element::$substitutedNodeValue
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
8+
$dom = DOM\XMLDocument::createFromString('<root/>');
9+
10+
$dom->documentElement->substitutedNodeValue = "&#x31;";
11+
var_dump($dom->documentElement->substitutedNodeValue);
12+
var_dump($dom->documentElement->nodeValue); // Should always be NULL for elements
13+
echo $dom->saveXML(), "\n";
14+
15+
$dom->documentElement->substitutedNodeValue = "&lt;&gt;";
16+
var_dump($dom->documentElement->substitutedNodeValue);
17+
var_dump($dom->documentElement->nodeValue); // Should always be NULL for elements
18+
echo $dom->saveXML(), "\n";
19+
20+
$dom->documentElement->substitutedNodeValue = "";
21+
var_dump($dom->documentElement->substitutedNodeValue);
22+
var_dump($dom->documentElement->nodeValue); // Should always be NULL for elements
23+
echo $dom->saveXML(), "\n";
24+
25+
?>
26+
--EXPECT--
27+
string(1) "1"
28+
NULL
29+
<?xml version="1.0" encoding="UTF-8"?>
30+
<root>1</root>
31+
string(2) "<>"
32+
NULL
33+
<?xml version="1.0" encoding="UTF-8"?>
34+
<root>&lt;&gt;</root>
35+
string(0) ""
36+
NULL
37+
<?xml version="1.0" encoding="UTF-8"?>
38+
<root></root>

0 commit comments

Comments
 (0)