summaryrefslogtreecommitdiff
path: root/ext/simplexml
diff options
context:
space:
mode:
authorMark A. Hershberger <mah@debian.(none)>2009-03-25 00:38:07 -0400
committerMark A. Hershberger <mah@debian.(none)>2009-03-25 00:38:07 -0400
commitbb01389fbd53ec1cbcb80d0681a37cca1267891a (patch)
tree4783178fca65a5d9071c8df34f2ddc3d31728673 /ext/simplexml
parenteddbbea4325e602ddc87c545531609132d4f0e3b (diff)
downloadphp-bb01389fbd53ec1cbcb80d0681a37cca1267891a.tar.gz
Imported Upstream version 5.2.4upstream/5.2.4
Diffstat (limited to 'ext/simplexml')
-rw-r--r--ext/simplexml/simplexml.c160
-rwxr-xr-xext/simplexml/tests/027.phpt14
-rwxr-xr-xext/simplexml/tests/bug35785.phpt17
-rwxr-xr-xext/simplexml/tests/bug37565.phpt2
-rw-r--r--ext/simplexml/tests/bug41582.phpt18
-rw-r--r--ext/simplexml/tests/bug41861.phpt38
-rw-r--r--ext/simplexml/tests/bug41867.phpt14
-rw-r--r--ext/simplexml/tests/bug41947.phpt14
8 files changed, 219 insertions, 58 deletions
diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c
index 620d31f7b..a4c7b138e 100644
--- a/ext/simplexml/simplexml.c
+++ b/ext/simplexml/simplexml.c
@@ -18,7 +18,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: simplexml.c,v 1.151.2.22.2.26 2007/04/24 14:11:28 iliaa Exp $ */
+/* $Id: simplexml.c,v 1.151.2.22.2.35 2007/07/31 15:40:49 rrichards Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -238,7 +238,7 @@ next_iter:
/* {{{ sxe_prop_dim_read()
*/
-static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, zend_bool silent TSRMLS_DC)
+static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, int type TSRMLS_DC)
{
zval *return_value;
php_sxe_object *sxe;
@@ -251,10 +251,14 @@ static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements,
sxe = php_sxe_fetch_object(object TSRMLS_CC);
- if (Z_TYPE_P(member) == IS_LONG) {
+ if (!member || Z_TYPE_P(member) == IS_LONG) {
if (sxe->iter.type != SXE_ITER_ATTRLIST) {
attribs = 0;
elements = 1;
+ } else if (!member) {
+ /* This happens when the user did: $sxe[]->foo = $value */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
+ return NULL;
}
name = NULL;
} else {
@@ -267,9 +271,6 @@ static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements,
name = Z_STRVAL_P(member);
}
- MAKE_STD_ZVAL(return_value);
- ZVAL_NULL(return_value);
-
GET_NODE(sxe, node);
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
@@ -282,8 +283,17 @@ static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements,
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
attr = node ? node->properties : NULL;
test = 0;
+ if (!member && node && node->parent &&
+ node->parent->type == XML_DOCUMENT_NODE) {
+ /* This happens when the user did: $sxe[]->foo = $value */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
+ return NULL;
+ }
}
+ MAKE_STD_ZVAL(return_value);
+ ZVAL_NULL(return_value);
+
if (node) {
if (attribs) {
if (Z_TYPE_P(member) != IS_LONG || sxe->iter.type == SXE_ITER_ATTRLIST) {
@@ -314,13 +324,30 @@ static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements,
if (!sxe->node) {
php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, node, NULL TSRMLS_CC);
}
- if (Z_TYPE_P(member) == IS_LONG) {
+ if (!member || Z_TYPE_P(member) == IS_LONG) {
+ long cnt = 0;
+ xmlNodePtr mynode = node;
+
if (sxe->iter.type == SXE_ITER_CHILD) {
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
}
- node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
+ if (sxe->iter.type == SXE_ITER_NONE) {
+ if (member && Z_LVAL_P(member) > 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
+ }
+ } else if (member) {
+ node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
+ } else {
+ node = NULL;
+ }
if (node) {
_node_as_zval(sxe, node, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
+ } else if (type == BP_VAR_W || type == BP_VAR_RW) {
+ if (member && cnt < Z_LVAL_P(member)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only %ld such elements exist", mynode->name, Z_LVAL_P(member), cnt);
+ }
+ node = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, NULL);
+ _node_as_zval(sxe, node, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC);
}
} else {
#if SXE_ELEMENT_BY_NAME
@@ -357,7 +384,7 @@ static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements,
*/
static zval * sxe_property_read(zval *object, zval *member, int type TSRMLS_DC)
{
- return sxe_prop_dim_read(object, member, 1, 0, type == BP_VAR_IS TSRMLS_CC);
+ return sxe_prop_dim_read(object, member, 1, 0, type TSRMLS_CC);
}
/* }}} */
@@ -365,7 +392,7 @@ static zval * sxe_property_read(zval *object, zval *member, int type TSRMLS_DC)
*/
static zval * sxe_dimension_read(zval *object, zval *offset, int type TSRMLS_DC)
{
- return sxe_prop_dim_read(object, offset, 0, 1, 0 TSRMLS_CC);
+ return sxe_prop_dim_read(object, offset, 0, 1, type TSRMLS_CC);
}
/* }}} */
@@ -425,7 +452,6 @@ static void change_node_zval(xmlNodePtr node, zval *value TSRMLS_DC)
static void sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool elements, zend_bool attribs, xmlNodePtr *pnewnode TSRMLS_DC)
{
php_sxe_object *sxe;
- char *name;
xmlNodePtr node;
xmlNodePtr newnode = NULL;
xmlNodePtr mynode;
@@ -439,22 +465,19 @@ static void sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_boo
long cnt = 0;
zval tmp_zv, trim_zv, value_copy;
- if (!member) {
- /* This happens when the user did: $sxe[] = $value
- * and could also be E_PARSE, but we use this only during parsing
- * and this is during runtime.
- */
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
- return;
- }
-
-
sxe = php_sxe_fetch_object(object TSRMLS_CC);
- if (Z_TYPE_P(member) == IS_LONG) {
+ if (!member || Z_TYPE_P(member) == IS_LONG) {
if (sxe->iter.type != SXE_ITER_ATTRLIST) {
attribs = 0;
elements = 1;
+ } else if (!member) {
+ /* This happens when the user did: $sxe[] = $value
+ * and could also be E_PARSE, but we use this only during parsing
+ * and this is during runtime.
+ */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
+ return;
}
} else {
if (Z_TYPE_P(member) != IS_STRING) {
@@ -475,8 +498,6 @@ static void sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_boo
}
}
- name = Z_STRVAL_P(member);
-
GET_NODE(sxe, node);
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
@@ -490,6 +511,15 @@ static void sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_boo
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
attr = node ? node->properties : NULL;
test = 0;
+ if (!member && node && node->parent &&
+ node->parent->type == XML_DOCUMENT_NODE) {
+ /* This happens when the user did: $sxe[] = $value
+ * and could also be E_PARSE, but we use this only during parsing
+ * and this is during runtime.
+ */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
+ return;
+ }
if (attribs && !node && sxe->iter.type == SXE_ITER_ELEMENT) {
node = xmlNewChild(mynode, mynode->ns, sxe->iter.name, NULL);
attr = node->properties;
@@ -546,7 +576,7 @@ static void sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_boo
}
} else {
while (attr) {
- if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)name) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
+ if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
is_attr = 1;
++counter;
break;
@@ -558,17 +588,30 @@ static void sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_boo
}
if (elements) {
- if (Z_TYPE_P(member) == IS_LONG) {
- newnode = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
- if (newnode) {
+ if (!member || Z_TYPE_P(member) == IS_LONG) {
+ if (node->type == XML_ATTRIBUTE_NODE) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create duplicate attribute");
+ return;
+ }
+
+ if (sxe->iter.type == SXE_ITER_NONE) {
+ newnode = node;
++counter;
+ if (member && Z_LVAL_P(member) > 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only 0 such elements exist", mynode->name, Z_LVAL_P(member));
+ }
+ } else if (member) {
+ newnode = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt);
+ if (newnode) {
+ ++counter;
+ }
}
} else {
node = node->children;
while (node) {
SKIP_TEXT(node);
- if (!xmlStrcmp(node->name, (xmlChar *)name)) {
+ if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) {
newnode = node;
++counter;
}
@@ -594,15 +637,23 @@ next_iter:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)");
} else if (elements) {
if (!node) {
- newnode = xmlNewTextChild(mynode, mynode->ns, (xmlChar *)name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
- } else if (Z_TYPE_P(member) == IS_LONG) {
- if (cnt < Z_LVAL_P(member)) {
+ if (!member || Z_TYPE_P(member) == IS_LONG) {
+ newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
+ } else {
+ newnode = xmlNewTextChild(mynode, mynode->ns, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
+ }
+ } else if (!member || Z_TYPE_P(member) == IS_LONG) {
+ if (member && cnt < Z_LVAL_P(member)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only %ld such elements exist", mynode->name, Z_LVAL_P(member), cnt);
}
newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
}
} else if (attribs) {
- newnode = (xmlNodePtr)xmlNewProp(node, (xmlChar *)name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
+ if (Z_TYPE_P(member) == IS_LONG) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot change attribute number %ld when only %d attributes exist", Z_LVAL_P(member), nodendx);
+ } else {
+ newnode = (xmlNodePtr)xmlNewProp(node, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL);
+ }
}
}
@@ -736,6 +787,11 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
attr = attr->next;
}
}
+ if (exists && check_empty == 1 &&
+ (!attr->children || !attr->children->content || !attr->children->content[0] || !xmlStrcmp(attr->children->content, "0")) ) {
+ /* Attribute with no content in it's text node */
+ exists = 0;
+ }
}
if (elements) {
@@ -758,6 +814,11 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
}
if (node) {
exists = 1;
+ if (check_empty == 1 &&
+ (!node->children || (node->children->type == XML_TEXT_NODE && !node->children->next &&
+ (!node->children->content || !node->children->content[0] || !xmlStrcmp(node->children->content, "0")))) ) {
+ exists = 0;
+ }
}
}
}
@@ -1345,15 +1406,12 @@ SXE_METHOD(getNamespaces)
GET_NODE(sxe, node);
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
- while (node) {
- SKIP_TEXT(node)
+ if (node) {
if (node->type == XML_ELEMENT_NODE) {
sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC);
} else if (node->type == XML_ATTRIBUTE_NODE && node->ns) {
sxe_add_namespace_name(return_value, node->ns);
}
-next_iter:
- node = node->next;
}
}
/* }}} */
@@ -1437,9 +1495,13 @@ SXE_METHOD(getName)
sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
GET_NODE(sxe, node);
-
- namelen = xmlStrlen(node->name);
- RETURN_STRINGL((char*)node->name, namelen, 1);
+ node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
+ if (node) {
+ namelen = xmlStrlen(node->name);
+ RETURN_STRINGL((char*)node->name, namelen, 1);
+ } else {
+ RETURN_EMPTY_STRING();
+ }
}
/* }}} */
@@ -1501,6 +1563,11 @@ SXE_METHOD(addChild)
node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
+ if (node == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
+ return;
+ }
+
localname = xmlSplitQName2((xmlChar *)qname, &prefix);
if (localname == NULL) {
localname = xmlStrdup((xmlChar *)qname);
@@ -1509,11 +1576,16 @@ SXE_METHOD(addChild)
newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);
if (nsuri != NULL) {
- nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
- if (nsptr == NULL) {
+ if (nsuri_len == 0) {
+ newnode->ns = NULL;
nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
+ } else {
+ nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
+ if (nsptr == NULL) {
+ nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
+ }
+ newnode->ns = nsptr;
}
- newnode->ns = nsptr;
}
_node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, (char *)localname, prefix, 0 TSRMLS_CC);
@@ -2368,7 +2440,7 @@ PHP_MINFO_FUNCTION(simplexml)
{
php_info_print_table_start();
php_info_print_table_header(2, "Simplexml support", "enabled");
- php_info_print_table_row(2, "Revision", "$Revision: 1.151.2.22.2.26 $");
+ php_info_print_table_row(2, "Revision", "$Revision: 1.151.2.22.2.35 $");
php_info_print_table_row(2, "Schema support",
#ifdef LIBXML_SCHEMAS_ENABLED
"enabled");
diff --git a/ext/simplexml/tests/027.phpt b/ext/simplexml/tests/027.phpt
index 105f99066..a531ccad4 100755
--- a/ext/simplexml/tests/027.phpt
+++ b/ext/simplexml/tests/027.phpt
@@ -40,7 +40,7 @@ $people->person[3] = 'Minni-me';
$people->person[2]['gender'] = 'male';
traverse_xml($people);
$people->person[3]['gender'] = 'error';
-
+traverse_xml($people);
?>
===DONE===
--EXPECTF--
@@ -70,6 +70,14 @@ Warning: main(): Cannot add element person number 3 when only 2 such elements ex
<person gender="male">Minni-me
</person>
</people>
-
-Notice: Indirect modification of overloaded element of SimpleXMLElement has no effect in %s027.php on line %d
+<people>
+ <person gender="female">Jane
+ </person>
+ <person gender="male">Joe
+ </person>
+ <person gender="male">Minni-me
+ </person>
+ <person gender="error">
+ </person>
+</people>
===DONE===
diff --git a/ext/simplexml/tests/bug35785.phpt b/ext/simplexml/tests/bug35785.phpt
index 4156a7c9f..0e03f07c5 100755
--- a/ext/simplexml/tests/bug35785.phpt
+++ b/ext/simplexml/tests/bug35785.phpt
@@ -8,13 +8,13 @@ Bug #35785 (SimpleXML memory read error)
$xml = simplexml_load_string("<root></root>");
$xml->bla->posts->name = "FooBar";
echo $xml->asXML();
-
-echo "===FAIL===\n";
-
$xml = simplexml_load_string("<root></root>");
$count = count($xml->bla->posts);
var_dump($count);
-$xml->bla->posts[++$count]->name = "FooBar";
+$xml->bla->posts[$count]->name = "FooBar";
+echo $xml->asXML();
+$xml = simplexml_load_string("<root></root>");
+$xml->bla->posts[]->name = "FooBar";
echo $xml->asXML();
?>
===DONE===
@@ -22,12 +22,9 @@ echo $xml->asXML();
--EXPECTF--
<?xml version="1.0"?>
<root><bla><posts><name>FooBar</name></posts></bla></root>
-===FAIL===
int(0)
-
-Notice: Indirect modification of overloaded element of SimpleXMLElement has no effect in %sbug35785.php on line %d
-
-Strict Standards: Creating default object from empty value in %sbug35785.php on line %d
<?xml version="1.0"?>
-<root><bla><posts/></bla></root>
+<root><bla><posts><name>FooBar</name></posts></bla></root>
+<?xml version="1.0"?>
+<root><bla><posts><name>FooBar</name></posts></bla></root>
===DONE===
diff --git a/ext/simplexml/tests/bug37565.phpt b/ext/simplexml/tests/bug37565.phpt
index 019fc7169..c1e51040b 100755
--- a/ext/simplexml/tests/bug37565.phpt
+++ b/ext/simplexml/tests/bug37565.phpt
@@ -1,7 +1,7 @@
--TEST--
Bug #37565 (Using reflection::export with simplexml causing a crash)
--SKIPIF--
-<?php if (!extension_loaded("simplexml")) print "skip"; ?>
+<?php if (!extension_loaded("simplexml") || !extension_loaded('reflection')) print "skip"; ?>
--FILE--
<?php
diff --git a/ext/simplexml/tests/bug41582.phpt b/ext/simplexml/tests/bug41582.phpt
new file mode 100644
index 000000000..b689607d0
--- /dev/null
+++ b/ext/simplexml/tests/bug41582.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #41582 (SimpleXML crashes when accessing newly created element)
+--FILE--
+<?php
+
+$xml = new SimpleXMLElement('<?xml version="1.0" standalone="yes"?>
+<collection></collection>');
+
+$xml->movie[]->characters->character[0]->name = 'Miss Coder';
+
+echo($xml->asXml());
+
+echo "Done\n";
+?>
+--EXPECT--
+<?xml version="1.0" standalone="yes"?>
+<collection><movie><characters><character><name>Miss Coder</name></character></characters></movie></collection>
+Done
diff --git a/ext/simplexml/tests/bug41861.phpt b/ext/simplexml/tests/bug41861.phpt
new file mode 100644
index 000000000..07622ebbd
--- /dev/null
+++ b/ext/simplexml/tests/bug41861.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Bug #41861 (getNamespaces() returns the namespaces of a node's siblings)
+--FILE--
+<?php
+
+$xml = simplexml_load_string('<root>
+ <first_node_no_ns />
+ <ns1:node1 xmlns:ns1="#ns1" />
+ <ns2:node2 xmlns:ns2="#ns2" />
+ <ns3:node3 xmlns:ns3="#ns3" />
+ <last_node_no_ns />
+</root>');
+
+$name = $xml->getName();
+$namespaces = $xml->getNamespaces(True);
+echo "root(recursive): '$name' -- namespaces: ", implode(', ', $namespaces), "\n";
+$namespaces = $xml->getNamespaces(False);
+echo "root(non-recursive): '$name' -- namespaces: ", implode(', ', $namespaces), "\n";
+
+foreach (array(null, '#ns1', '#ns2', '#ns3') as $ns)
+{
+ foreach ($xml->children($ns) as $child)
+ {
+ $name = $child->getName();
+ $namespaces = $child->getNamespaces(false);
+
+ echo "children($ns): '$name' -- namespaces: ", implode(', ', $namespaces), "\n";
+ }
+}
+?>
+--EXPECT--
+root(recursive): 'root' -- namespaces: #ns1, #ns2, #ns3
+root(non-recursive): 'root' -- namespaces:
+children(): 'first_node_no_ns' -- namespaces:
+children(): 'last_node_no_ns' -- namespaces:
+children(#ns1): 'node1' -- namespaces: #ns1
+children(#ns2): 'node2' -- namespaces: #ns2
+children(#ns3): 'node3' -- namespaces: #ns3
diff --git a/ext/simplexml/tests/bug41867.phpt b/ext/simplexml/tests/bug41867.phpt
new file mode 100644
index 000000000..f530f95dc
--- /dev/null
+++ b/ext/simplexml/tests/bug41867.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug #41867 (getName is broken)
+--FILE--
+<?php
+
+$a = simplexml_load_string("<a><b><c/></b></a>");
+echo $a->getName()."\n";
+echo $a->b->getName()."\n";
+echo $a->b->c->getName();
+?>
+--EXPECT--
+a
+b
+c
diff --git a/ext/simplexml/tests/bug41947.phpt b/ext/simplexml/tests/bug41947.phpt
new file mode 100644
index 000000000..7af9ff8e7
--- /dev/null
+++ b/ext/simplexml/tests/bug41947.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug #41947 (addChild incorrectly registers empty strings as namespaces)
+--FILE--
+<?php
+$xml = simplexml_load_string('<?xml version="1.0" encoding="utf-8"?><root xmlns:myns="http://myns" />');
+$grandchild = $xml->addChild('child', null, 'http://myns')->addChild('grandchild', 'hello', '');
+
+$gchild = $xml->xpath("//grandchild");
+if (count($gchild) > 0) {
+ echo $gchild[0];
+}
+?>
+--EXPECT--
+hello