Search code examples
phpxmlsimplexml

SimpleXMLElement uses wrong xsd namespace when xmlns is absent


I'm trying to generate the following output:

<?xml version="1.0"?>
<foo:fooBar xmlns:foo="foo.xsd" xmlns:bar="bar.xsd"><foo:element/><bar:element>value</bar:element></foo:fooBar>

However, my code sets the prefix/namespace for the second element (the one with value) to foo, even though I used bar:element:

<?xml version="1.0"?>
<foo:fooBar xmlns:foo="foo.xsd" xmlns:bar="bar.xsd"><foo:element/><foo:element>value</foo:element></foo:fooBar>

Here's my code:

$base = "<foo:fooBar xmlns:foo=\"foo.xsd\" xmlns:bar=\"bar.xsd\"/>";

$xml = new SimpleXMLElement($base);
$foo = $xml->addChild("foo:element");
$bar = $xml->addChild("bar:element", "value");

echo($xml->asXML());

I've noticed that setting the third argument of addChild (the xmlns) to anything fixes the issue.

<?xml version="1.0"?>
<foo:fooBar xmlns:foo="foo.xsd" xmlns:bar="bar.xsd"><foo:element/><bar:element xmlns:bar="arbitrary string">value</bar:element></foo:fooBar>

How can I have the second element use the correct prefix/namespace without using xmlns?

Something like JSFiddle with my code


Solution

  • When you add the element bar:element using addchild() you need to pass as the third parameter the namespace - and this must match the original URI of the namespace you've already declared. If you pass a different URI, then it will assume you want to declare a new namespace. So using "bar.xsd" as the third parameter...

    $base = "<foo:fooBar xmlns:foo=\"foo.xsd\" xmlns:bar=\"bar.xsd\"/>";
    
    $xml = new SimpleXMLElement($base);
    $foo = $xml->addChild("foo:element");
    $bar = $xml->addChild("bar:element", "value", "bar.xsd");
    
    echo($xml->asXML());
    

    Will give...

    <?xml version="1.0"?>
    <foo:fooBar xmlns:foo="foo.xsd" xmlns:bar="bar.xsd">
        <foo:element/>
        <bar:element>value</bar:element>
    </foo:fooBar>