Given two SimpleXMLElement
objects structured as follows (identical):
$obj1
object SimpleXMLElement {
["@attributes"] =>
array(0) {
}
["event"] =>
array(1) {
[0] =>
object(SimpleXMLElement) {
["@attributes"] =>
array(1) {
["url"] =>
string "example.com"
}
}
}
}
$obj2
object SimpleXMLElement {
["@attributes"] =>
array(0) {
}
["event"] =>
array(1) {
[0] =>
object(SimpleXMLElement) {
["@attributes"] =>
array(1) {
["url"] =>
string "another-example.com"
}
}
}
}
I am trying to copy all the child event
items from the second object to the first as so:
foreach ($obj2->event as $event) {
$obj1->event[] = $event
}
They move, but the copied objects are now empty.
$obj1
object SimpleXMLElement {
["@attributes"] =>
array(0) {
}
["event"] =>
array(2) {
[0] =>
object(SimpleXMLElement) {
["@attributes"] =>
array(1) {
["url"] =>
string "example.com"
}
}
[1] =>
object(SimpleXMLElement) {
}
}
}
SimpleXML's editing functionality is rather limited, and in this case, both the assignment you're doing and ->addChild
can only set the text content of the new element, not its attributes and children.
This may be one case where you need the power of the more complex DOM API. Luckily, you can mix the two in PHP with almost no penalty, using dom_import_simplexml
and simplexml_import_dom
to switch to the other wrapper.
Once you have a DOM representation, you can use the appendChild
method of DOMNode
to add a full node, but there's a catch - you can only add nodes "owned by" the same document. So you have to first call the importNode
method on the document you're trying to edit.
Putting it all together, you get something like this:
// Set up the objects you're copying from and to
// These don't need to be complete documents, they could be any element
$obj1 = simplexml_load_string('<foo><event url="example.com" /></foo>');
$obj2 = simplexml_load_string('<foo><event url="another.example.com" /></foo>');
// Get a DOM representation of the root element we want to add things to
// Note that $obj1_dom will always be a DOMElement not a DOMDocument,
// because SimpleXML has no "document" object
$obj1_dom = dom_import_simplexml($obj1);
// Loop over the SimpleXML version of the source elements
foreach ($obj2->event as $event) {
// Get the DOM representation of the element we want to copy
$event_dom = dom_import_simplexml($event);
// Copy the element into the "owner document" of our target node
$event_dom_adopted = $obj1_dom->ownerDocument->importNode($event_dom, true);
// Add the node as a new child
$obj1_dom->appendChild($event_dom_adopted);
}
// Check that we have the right output, not trusting var_dump or print_r
// Note that we don't need to convert back to SimpleXML
// - $obj1 and $obj1_dom refer to the same data internally
echo $obj1->asXML();