Search code examples
phpxmldomsimplexmldomdocument

DOMDocument with Namespace


I've been working for a couple hours trying to get the output XML to match the spec I was given, and I just can't find the right code to do it. I'm using DOMDocument because I read that it is more flexible than SimpleXML.

The desired end result:

<?xml version="1.0" encoding="UTF-8"?>
<retail xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <partnerid>XYZ</partnerid>
    <customer xmlns:a="http://schemas.datacontract.org/2004/07/DealerTrack.DataContracts.CreditApp">
        <a:info>
            <a:FirstName>Bob</a:FirstName>
            <a:LastName>Hoskins</a:LastName>
        </a:info>
    </customer>
    <refnum i:nil="true"/>
</retail>

...and the code I'm using to get there (abbreviated):

$node = new DOMDocument('1.0', 'UTF-8');
$root = $node->createElementNS( 'http://www.w3.org/2001/XMLSchema-instance', 'retail' );
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xmlns:i', 'test');

$capp = $node->appendChild($root);

$cnode = $node->createElement("partnerid", 'XYZ');
$capp->appendChild($cnode);

...which isn't getting me what I want. I've tried at least a dozen combinations of createElementNS, setAttributeNS, looked at several examples and can't find anything that gets me close to what I'm after. I can already do this in SimpleXML, but I'd like to understand what's going on and how to use the DOM in this instance.


Solution

  • In addition to alex blex answer: for the root element (and only for it) you can also simply create an attribute namespace without appending it to the root element.

    $dom = new DOMDocument('1.0', 'UTF-8');
    
    $namespaceURIs = [
      'xmlns' => 'http://www.w3.org/2000/xmlns/',
      'i' => 'http://www.w3.org/2001/XMLSchema-instance',
      'a' => 'http://schemas.datacontract.org/2004/07/DealerTrack.DataContracts.CreditApp'
    ];
    
    $root = $dom->createElement('retail');
    $dom->appendChild($root);
    $dom->createAttributeNS($namespaceURIs['i'], 'i:attr');
    // note that you don't have to append it: `CreateAttributeNS` defines a namespace for
    // the entire document and will be automatically attached to the root element.
    
    $root->appendChild($dom->createElement('partnerid', 'XYZ'));
    
    $customer = $dom->createElement('customer');
    $customer->setAttributeNS($namespaceURIs['xmlns'], 'xmlns:a', $namespaceURIs['a']);
    // `setAttributeNS` allows to define local namespaces, that's why it needs to be
    // attached to a particular element.
    $root->appendChild($customer);
    
    $info = $dom->createElementNS($namespaceURIs['a'], 'a:info');
    $customer->appendChild($info);
    // etc.
    
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = true;
    
    echo $dom->saveXML();
    

    demo

    Also, feel free to test the other php XML build-in api: XMLWriter