Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to add namespace to an attribute with PHP's SimpleXML

I am creating an Atom feed, when I tried below to add xmlns:i as an attribute -

$node->addAttribute("xmlns:i","http://www.w3.org/2001/XMLSchema-instance"); 

I got this as an output -

i="http://www.w3.org/2001/XMLSchema-instance"

"xmlns:" part was cut off. do I need to escape the :-character? Or is they any other way to add this namespace?

like image 867
Sourabh Avatar asked Oct 20 '09 05:10

Sourabh


3 Answers

If you don’t want to have to add a dummy attribute to your root element, you can declare the namespace manually on it by adding an xmlns attribute for your i prefix:

<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

In order to do so, and as hinted in an existing answer (Unable to add Attribute with Namespace Prefix using PHP Simplexml), you have to prefix the new attribute with xmlns: (since the xmlns: namespace prefic is not declared in your document). And since xmlns: is part of the name of that attribute, you therfore need two occurrences of xmlns:

$uri = 'http://www.w3.org/2001/XMLSchema-instance';

$root = new SimpleXMLElement('<root/>');
$root->addAttribute( 'xmlns:xmlns:i', $uri );
                      ######

$child = $root->addChild('foo');
$child->addAttribute( 'xmlns:i:bar', 'baz');
                       ######

echo $root->asXml();

Gives (formatted manually for readability):

<?xml version="1.0"?>
<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <foo i:bar="baz"/>
</root>

So this xmlns: prefixing seems to cheat it. Note that if you reload the element after setting that attribute, it is possible to use the namespace uri as well when adding children, and this without specifying the prefix:

$root = new SimpleXMLElement( $root->asXML() );

$child = $root->addChild('foo');
$child->addAttribute( 'i:bar', 'bazy', $uri );
                                       ####

echo $root->asXml();

Gives (again, formatted manually):

<?xml version="1.0"?>
<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <foo i:bar="baz"/>
    <foo i:bar="bazy"/>
</root>

This second example seems to be closer to the intended (or at least expected) use.

Note that the only way to do this properly would be to use the more complete (but unfortunately also more complex and more verbose) DOMDocument classes. This is outlined in How to declare an XML namespace prefix with DOM/PHP?.

like image 147
Olivier 'Ölbaum' Scherler Avatar answered Sep 19 '22 12:09

Olivier 'Ölbaum' Scherler


I found this looking for the same thing, and none of the answers really worked for me. So, I tried a different route. If SimpleXML isn't managing namespace correctly, use DOM instead.

So, something like this should work:

$s = new simplexmlelement('<root/>');
$d = dom_import_simplexml($s);
$d->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:i", "http://www.w3.org/2001/XMLSchema-instance");
$s->addChild("bar", "bazy", "http://www.w3.org/2001/XMLSchema-instance");
$f = $s->addChild("foo", "quux");
$f->addAttribute("i:corge", "grault", "http://www.w3.org/2001/XMLSchema-instance");

That will result in this:

<?xml version="1.0"?>
<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
   <i:bar>bazy</i:bar>
   <foo i:corge="grault">quux</foo>
</root>
like image 22
Dan Jones Avatar answered Sep 18 '22 12:09

Dan Jones


If you want to add an attribute from the namespace/prefix i to $node don't bother declaring the namespace beforehand. Just use the third parameter of addAttribute() to provide the namespace uri for the prefix you're using in the first parameter.

$node = new SimpleXMLElement('<root></root>');
$node->addAttribute("i:somename", "somevalue", 'http://www.w3.org/2001/XMLSchema-instance'); 
echo $node->asXml();

prints

<?xml version="1.0"?>
<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance" i:somename="somevalue"/>

If the attribute itself isn't needed, you can then remove it with unset(), leaving the namespace declaration.

unset($node->attributes('i', TRUE)['somename']);
like image 29
VolkerK Avatar answered Sep 18 '22 12:09

VolkerK