5

I need to load an XML source using Simple XML, duplicate an existing node with all his children, then customize an attribute of this new node before rendering XML. Any suggestion?

2 Answers 2

23

SimpleXML can't do this, so you'll have to use DOM. The good news is that DOM and SimpleXML are two sides of the same coin, libxml. So no matter whether you're using SimpleXML or DOM, you're working on the same tree. Here's an example:

$thing = simplexml_load_string(
    '<thing>
        <node n="1"><child/></node>
    </thing>'
);

$dom_thing = dom_import_simplexml($thing);
$dom_node  = dom_import_simplexml($thing->node);
$dom_new   = $dom_thing->appendChild($dom_node->cloneNode(true));

$new_node  = simplexml_import_dom($dom_new);
$new_node['n'] = 2;

echo $thing->asXML();

If you're doing that kind of thing a lot, you can try SimpleDOM, which is an extension to SimpleXML that lets you use DOM's methods directly, without converting from and to DOM objects.

include 'SimpleDOM.php';
$thing = simpledom_load_string(
    '<thing>
        <node n="1"><child/></node>
    </thing>'
);

$new = $thing->appendChild($thing->node->cloneNode(true));
$new['n'] = 2;

echo $thing->asXML();
Sign up to request clarification or add additional context in comments.

2 Comments

+1 for recommending DOM. I have run into many problems with simpleXML. Never use SimpleXML, DOM is much more powerful and no harder to use.
I have to notice it also because this is so important. I'm not sorry for spending half an hour to rewrite my script with DOM. Now it is much more straight and easy to maintain.
7

With SimpleXML, the best way I've found is a workaround. It's pretty bobo, but it works:

// Strip it out so it's not passed by reference
$newNode = new SimpleXMLElement($xml->someNode->asXML());

// Modify your value
$newNode['attribute'] = $attValue;

// Create a dummy placeholder for it wherever you need it
$xml->addChild('replaceMe');

// Do a string replace on the empty fake node
$xml = str_replace('<replaceMe/>',$newNode->asXML(),$xml->asXML());

// Convert back to the object
$xml = new SimpleXMLElement($xml); # leave this out if you want the xml

Since it's a workaround for a feature that doesn't seem to be there in SimpleXML, you'll need to be aware that I expect this would break any object references you've defined up to this point, if any.

2 Comments

Love this answer, so simple and works great. I had to tweak the answer a bit as '$newNode->asXML()' was writing out the XML header instead of just the raw XML fragment: $domNode = dom_import_simplexml($newNode); $xml = str_replace('<replaceMe/>',$domNode->ownerDocument->saveXML($domNode),$xml->asXML());
You made a typo in $newnode['attribute'] = $attValue;, should be $newNode['attribute'] = $attValue;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.