Search code examples
phpxmlsimplexml

Prepending raw XML using PHP's SimpleXML


Given a base $xml and a file containing a <something> tag with attributes, children and children of its children, I would like to append it as first child and all of its children as raw XML.

Original XML:

<root>
    <people>
        <person>
            <name>John Doe</name>
            <age>47</age>
        </person>
        <person>
            <name>James Johnson</name>
            <age>13</age>
        </person>
    </people>
</root>

XML in file:

<something someval="x" otherthing="y">
    <child attr="val"  ..> { some children and values ... }</child>
    <child attr="val2" ..> { some children and values ... }</child>
            ...
</something>

Result XML:

<root>
    <something someval="x" otherthing="y">
        <child attr="val"  ..> { some children and values ... }</child>
        <child attr="val2" ..> { some children and values ... }</child>
            ...
    </something>
    <people>
        <person>
            <name>John Doe</name>
            <age>47</age>
        </person>
        <person>
            <name>James Johnson</name>
            <age>13</age>
        </person>
    </people>
</root>

This tag would contain several children both direct and recursively, so it would not be practical to build the XML via the SimpleXML operations. Besides, keeping it in a file would result in lower maintenance costs.

Technically it would simply be prepending one child. The problem is that this child would have other children and so on.

On the PHP addChild page there's a comment that says:

$x = new SimpleXMLElement('<root name="toplevel"></root>');
$f1 = new SimpleXMLElement('<child pos="1">alpha</child>');

$x->{$f1->getName()} = $f1; // adds $f1 to $x

However, this does not seem to treat my XML as raw XML therefore causing &lt; and &gt; escaped tags to appear. Several warnings concerning namespaces seem to appear as well.

I suppose I could do a quick replace of such tags but I am not sure whether it could cause future problems and it certainly does not feel right.

Manually hacking the XML is not an option and neither is adding children one by one. Choosing a different library could be.

Any clues on how to get this working?

Thanks!


Solution

  • I'm really not sure if that will work. Try this or downvote this, but I hope it helps. Using DOMDocument (Reference)

    <?php
    $xml = new DOMDocument();
    $xml->loadHTML($yourOriginalXML);
    $newNode = DOMDocument::createElement($someXMLtoPrepend);
    $nodeRoot = $xml->getElementsByTagName('root')->item(0);
    $nodeOriginal = $xml->getElementsByTagName('people')->item(0);
    $nodeRoot->insertBefore($newNode,$nodeOriginal);
    
    $finalXmlAsString = $xml->saveXML();
    ?>
    

    Sometimes UTF-8 can make problems, then try this:

    <?php
    $xml = new DOMDocument();
    $xml->loadHTML(mb_convert_encoding($yourOriginalXML, 'HTML-ENTITIES', 'UTF-8'));
    $newNode = DOMDocument::createElement(mb_convert_encoding($someXMLtoPrepend, 'HTML-ENTITIES', 'UTF-8'));
    $nodeRoot = $xml->getElementsByTagName('root')->item(0);
    $nodeOriginal = $xml->getElementsByTagName('people')->item(0);
    $nodeRoot->insertBefore($newNode,$nodeOriginal);
    
    $finalXmlAsString = $xml->saveXML();
    ?>