Skip to content

Commit 8637a3f

Browse files
committed
Fix getDocNamespaces() not working when only having xmlns attributes without an internal declaration in the document
1 parent fae25ca commit 8637a3f

File tree

2 files changed

+85
-6
lines changed

2 files changed

+85
-6
lines changed

ext/simplexml/simplexml.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,18 +1416,23 @@ PHP_METHOD(SimpleXMLElement, asXML)
14161416

14171417
#define SXE_NS_PREFIX(ns) (ns->prefix ? (char*)ns->prefix : "")
14181418

1419-
static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */
1419+
static inline void sxe_add_namespace_name_raw(zval *return_value, const char *prefix, const char *href)
14201420
{
1421-
char *prefix = SXE_NS_PREFIX(ns);
14221421
zend_string *key = zend_string_init(prefix, strlen(prefix), 0);
14231422
zval zv;
14241423

14251424
if (!zend_hash_exists(Z_ARRVAL_P(return_value), key)) {
1426-
ZVAL_STRING(&zv, (char*)ns->href);
1425+
ZVAL_STRING(&zv, href);
14271426
zend_hash_add_new(Z_ARRVAL_P(return_value), key, &zv);
14281427
}
14291428
zend_string_release_ex(key, 0);
14301429
}
1430+
1431+
static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */
1432+
{
1433+
char *prefix = SXE_NS_PREFIX(ns);
1434+
sxe_add_namespace_name_raw(return_value, prefix, (const char *) ns->href);
1435+
}
14311436
/* }}} */
14321437

14331438
static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, bool recursive, zval *return_value) /* {{{ */
@@ -1484,7 +1489,7 @@ PHP_METHOD(SimpleXMLElement, getNamespaces)
14841489
}
14851490
/* }}} */
14861491

1487-
static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, bool recursive, zval *return_value) /* {{{ */
1492+
static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, bool recursive, bool include_xmlns_attributes, zval *return_value) /* {{{ */
14881493
{
14891494
xmlNsPtr ns;
14901495

@@ -1494,10 +1499,24 @@ static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node,
14941499
sxe_add_namespace_name(return_value, ns);
14951500
ns = ns->next;
14961501
}
1502+
if (include_xmlns_attributes) {
1503+
for (const xmlAttr *attr = node->properties; attr; attr = attr->next) {
1504+
/* Attributes in the xmlns namespace should be treated as namespace declarations too. */
1505+
if (attr->ns && xmlStrEqual(attr->ns->href, (const xmlChar *) "http://www.w3.org/2000/xmlns/")) {
1506+
const char *prefix = attr->ns->prefix ? (const char *) attr->name : "";
1507+
bool free;
1508+
xmlChar *href = php_libxml_attr_value(attr, &free);
1509+
sxe_add_namespace_name_raw(return_value, prefix, (const char *) href);
1510+
if (free) {
1511+
xmlFree(href);
1512+
}
1513+
}
1514+
}
1515+
}
14971516
if (recursive) {
14981517
node = node->children;
14991518
while (node) {
1500-
sxe_add_registered_namespaces(sxe, node, recursive, return_value);
1519+
sxe_add_registered_namespaces(sxe, node, recursive, include_xmlns_attributes, return_value);
15011520
node = node->next;
15021521
}
15031522
}
@@ -1532,8 +1551,11 @@ PHP_METHOD(SimpleXMLElement, getDocNamespaces)
15321551
RETURN_FALSE;
15331552
}
15341553

1554+
/* Only do this for modern documents to keep BC. */
1555+
bool include_xmlns_attributes = sxe->document->class_type == PHP_LIBXML_CLASS_MODERN;
1556+
15351557
array_init(return_value);
1536-
sxe_add_registered_namespaces(sxe, node, recursive, return_value);
1558+
sxe_add_registered_namespaces(sxe, node, recursive, include_xmlns_attributes, return_value);
15371559
}
15381560
/* }}} */
15391561

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
getDocNamespaces() without internal namespace declaration in the document
3+
--EXTENSIONS--
4+
simplexml
5+
dom
6+
--FILE--
7+
<?php
8+
9+
$xml = <<<XML
10+
<root>
11+
<child xmlns="urn:a">
12+
<a/>
13+
<b xmlns=""/>
14+
<c xmlns:a="urn:a" xmlns="urn:c"/>
15+
</child>
16+
<child2 xmlns:d="urn:d"/>
17+
</root>
18+
XML;
19+
20+
$sxe = simplexml_load_string($xml);
21+
var_dump($sxe->getDocNamespaces(true));
22+
23+
$dom = new DOMDocument;
24+
$dom->loadXML($xml);
25+
$sxe = simplexml_import_dom($dom);
26+
var_dump($sxe->getDocNamespaces(true));
27+
28+
$dom = DOM\XMLDocument::createFromString($xml);
29+
$sxe = simplexml_import_dom($dom);
30+
var_dump($sxe->getDocNamespaces(true));
31+
32+
?>
33+
--EXPECT--
34+
array(3) {
35+
[""]=>
36+
string(5) "urn:a"
37+
["a"]=>
38+
string(5) "urn:a"
39+
["d"]=>
40+
string(5) "urn:d"
41+
}
42+
array(3) {
43+
[""]=>
44+
string(5) "urn:a"
45+
["a"]=>
46+
string(5) "urn:a"
47+
["d"]=>
48+
string(5) "urn:d"
49+
}
50+
array(3) {
51+
[""]=>
52+
string(5) "urn:a"
53+
["a"]=>
54+
string(5) "urn:a"
55+
["d"]=>
56+
string(5) "urn:d"
57+
}

0 commit comments

Comments
 (0)