Making SimpleXML more useful
| From: | Tom Samplonius | Date: | Tue, 26 Apr 2011 23:23:33 +0000 |
| Subject: | Making SimpleXML more useful | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-52013@lists.php.net to get a copy of this message | ||
It is not possible to use SimpleXML to add a child element without a namespace prefix to a parent
element that has a namespace element. Instead, the child element inherits the namespace prefix of
the parent. So this XML fragment:
<ns1:parent>
<child>abc</child>
</ns1:parent>
is impossible to construct with SimpleXML. The SimpleXML extension would add the <child>
element with the ns1 namespace prefix. This is a problem for me, as I have an XML schema that
specifies that the child elements must not namespace qualified.
I looked into the SimpleXML code, and I believe this is actually a bug, as the code goes through
some effort to distinguish between a set but blank namespace, and a set but not blank namespace. I
believe the design intent was that specifying a blank namespace, would mean that no namespace would
be used, rather than inheriting the namespace of the parent.
<?php
header('Content-Type: text/plain');
$r = new SimpleXMLElement('<r />');
$c1 = $r->addChild('ns1:child1', NULL, 'urn:myspace1');
$c1->addChild('child2');
echo $r->asXML(), "\n";
$r = new SimpleXMLElement('<r />');
$r->addChild('Thing1', 100, '');
echo $r->asXML(), "\n";
Expected result:
----------------
<?xml version="1.0"?>
<r><ns1:child1
xmlns:ns1="urn:myspace1"><ns1:child2/></ns1:child1></r>
<?xml version="1.0"?>
<r><Thing1>100</Thing1></r>
Actual result:
--------------
<?xml version="1.0"?>
<r><ns1:child1
xmlns:ns1="urn:myspace1"><ns1:child2/></ns1:child1></r>
<?xml version="1.0"?>
<r><Thing1 xmlns="">100</Thing1></r>
The current behavior of specifying a blank namespace, is to add a literal blank namespace
(xmlns=""), which isn't a useful result. No one would be depending on using a blank
namepspace to get xmlns="".
The patch is pretty simple:
--- simplexml.c.orig 2011-04-26 16:00:31.000000000 -0700
+++ simplexml.c 2011-04-26 16:00:41.000000000 -0700
@@ -1619,12 +1619,14 @@
localname = xmlStrdup((xmlChar *)qname);
}
+ /* Add new child with no namespace */
newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);
if (nsuri != NULL) {
+ /* If namespace is not NULL but blank, use no namespace
+ Use this to prevent inheriting the name space of the parent */
if (nsuri_len == 0) {
newnode->ns = NULL;
- nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
} else {
nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri);
if (nsptr == NULL) {
(see also http://bugs.php.net/bug.php?id=54354)
If this patch is accepted, I'll also submit patches to clarify the documentation and add some
tests. SimpleXML with the above patch, passes the existing tests. It is hard to know for sure what
the design intent was, as the code has few comments, few tests, and the documentation is pretty
thin. But I believe the above is correct.
Tom