adding a namespace when using SimpleXMLElement

sleep-er picture sleep-er · Aug 3, 2011 · Viewed 16.9k times · Source

This is what I am after

<!-- language: lang-xml -->
<ws:Test>
    <ws:somename2>somevalue2</ws:somename2>
    <ws:make>
        <ws:model>foo</ws:model>
        <ws:model>bar</ws:model>
    </ws:make>
</ws:Test>

This is my current code

<!-- language: lang-php -->
$xmlTest = new SimpleXMLElement('<Test/>', 0, false, 'ws', true);
$xmlTest->addChild("ws:somename2", "somevalue2", 'http://microsoft.com/wsdl/types/');
$make = $xmlTest->addChild('ws:make', null, 'ws');
#$make->addAttribute('name','Ford');
$make->addChild('ws:model', 'foo', 'ws');
$make->addChild('ws:model', 'bar', 'ws');
header ("Content-Type:text/xml");
print_r($xmlTest->asXML());

but it outputs

<!-- language: lang-xml -->
<Test>
    <ws:somename2>somevalue2</ws:somename2>
    <ws:make>
        <ws:model>foo</ws:model>
        <ws:model>bar</ws:model>
    </ws:make>
</Test>

As you can see the ws: is missing from Test

Answer

Kyril picture Kyril · Aug 3, 2011

SimpleXML has an unusual quirk where the namespace prefixes are filtered from the root element. I'm not sure why it does this.

However, a workaround I've used has been to basically prefix the prefix, so that the parser only removes the first ones, and leaves the second

$xmlTest = new SimpleXMLElement('<xmlns:ws:Test></xmlns:ws:Test>', LIBXML_NOERROR, false, 'ws', true);
$xmlTest->addAttribute('xmlns:xmlns:ws', 'http://url.to.namespace');
$xmlTest->addAttribute('xmlns:xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');

This seems to work for me, though I'm interested to understand why SimpleXML does this exactly.