In SimpleXML, how can I add an existing SimpleXMLElement as a child element?
I know this isn't the most helpful answer, but especially since you're creating/modifying XML, I'd switch over to using the DOM functions. SimpleXML's good for accessing simple documents, but pretty poor at changing them.
If SimpleXML is treating you kindly in all other places and you want to stick with it, you still have the option of jumping over to the DOM functions temporarily to perform what you need to and then jump back again, using dom_import_simplexml()
and simplexml_import_dom()
. I'm not sure how efficient this is, but it might help you out.
How to add SimpleXMLElement node as a child element?
SimpleXML is good for basic things, but lacks the control (and complications) of DOMDocument.
When copying content from one document to another, you have to do three things (for SimpleXML), first is convert it to a DOMElement
, then import it into the target document using importNode()
with true
as the second argument to say do a deep copy. This just makes it available to the target document and doesn't actually place the content. This is done using appendChild()
with the newly imported node...
// Convert target SimpleXMLElement to DOMElement
$targetImport = dom_import_simplexml($target_body);
foreach ($source_body as $source_child) {
foreach ($source_child as $p) {
// Convert SimpleXMLElement to DOMElement
$sourceImport = dom_import_simplexml($p);
// Import the new node into the target document
$import = $targetImport->ownerDocument->importNode($sourceImport, true);
// Add the new node to the correct part of the target
$targetImport->appendChild($import);
}
}
PHP - SimpleXML - AddChild with another SimpleXMLElement
As far as I know, you can't do it with SimpleXML because addChild
doesn't make a deep copy of the element (being necessary to specify the tag name can easily be overcome by calling SimpleXMLElement::getName()
).
One solution would be to use DOM instead:
With this function:
function sxml_append(SimpleXMLElement $to, SimpleXMLElement $from) {
$toDom = dom_import_simplexml($to);
$fromDom = dom_import_simplexml($from);
$toDom->appendChild($toDom->ownerDocument->importNode($fromDom, true));
}
We have for
<?php
header("Content-type: text/plain");
$sxml = simplexml_load_string("<root></root>");
$n1 = simplexml_load_string("<child>one</child>");
$n2 = simplexml_load_string("<child><k>two</k></child>");
sxml_append($sxml, $n1);
sxml_append($sxml, $n2);
echo $sxml->asXML();
the output
<?xml version="1.0"?>
<root><child>one</child><child><k>two</k></child></root>
See also some user comments that use recursive functions and addChild
, e.g. this one.
Insert XML structure as a child of another XML Element using PHP
You can't with SimpleXML, but if you really need manipulate your DOM or create it from scratch consider DOMDocument.
$xmlObject = new \DOMDocument();
$xml = $xmlObject->createElement('root');
$xml_a = $xmlObject->createElement('parent');
$xml_b = $xmlObject->createElement('child');
$xml_b->setAttribute('attribute','value');
$xml_b->appendChild(new \DOMElement('item', 'itemValue'));
$xml_a->appendChild($xml_b);
$xml->appendChild($xml_a);
$xmlObject->appendChild($xml);
echo $xmlObject->saveXML();
Add child to xml with PHP simpleXml
then, you should not create new items node:
$xml = simplexml_load_file("myxml.xml");
$sxe = new SimpleXMLElement($xml->asXML());
$itemsNode = $sxe->items[0];
$itemsNode->addChild("item", $newValue);
$sxe->asXML("myxml.xml");
Adding a block of XML as child of a SimpleXMLElement object
Two solutions. First, you do it with the help of libxml / DOMDocument / SimpleXML: you have to import your $sx
object to DOM, create a DOMDocumentFragment
and use DOMDocumentFragment::appendXML()
:
$doc = dom_import_simplexml($sx)->ownerDocument;
$fragment = $doc->createDocumentFragment();
$fragment->appendXML($book->genXML());
$doc->documentElement->appendChild($fragment);
// your original $sx is now already modified.
See the Online Demo.
You can also extend from SimpleXMLElement and add a method that is providing this. Using this specialized object then would allow you to create the following easily:
$sx = new MySimpleXMLElement($xml);
$sx->addXML($book->genXML());
Another solution is to use an XML library that already has this feature built-in like SimpleDOM. You grab SimpleDOM and you use insertXML(), which works like the addXMLChild() method you were describing.
include 'SimpleDOM.php';
$books = simpledom_load_string(
'<books>
<book>
<name>ABCD</name>
</book>
</books>'
);
$books->insertXML(
'<book>
<name>EFGH</name>
</book>'
);
SimpleXML: append one tree to another
You can't add a "tree" directly using SimpleXML, as you have seen. However, you can use some DOM methods to do the heavy lifting for you whilst still working on the same underlying XML.
$xmldict = new SimpleXMLElement('<dictionary><a/><b/><c/></dictionary>');
$kitty = new SimpleXMLElement('<cat><sound>meow</sound><texture>fuzzy</texture></cat>');
// Create new DOMElements from the two SimpleXMLElements
$domdict = dom_import_simplexml($xmldict->c);
$domcat = dom_import_simplexml($kitty);
// Import the <cat> into the dictionary document
$domcat = $domdict->ownerDocument->importNode($domcat, TRUE);
// Append the <cat> to <c> in the dictionary
$domdict->appendChild($domcat);
// We can still use SimpleXML! (meow)
echo $xmldict->c->cat->sound;
How to add existing elements from XML file B to XML file A
This is easier in DOM because you have access to the nodes and can copy them from one document to another. Use Xpath to fetch parts of a document.
// load the XML into DOM document and create Xpath instances
$personsDocument = new DOMDocument;
$personsDocument->preserveWhiteSpace = FALSE;
$personsDocument->loadXML($xmlPersons);
$personsXpath = new DOMXpath($personsDocument);
$favoritesDocument = new DOMDocument;
$favoritesDocument->preserveWhiteSpace = FALSE;
$favoritesDocument->loadXML($xmlFavorites);
$favoritesXpath = new DOMXpath($favoritesDocument);
// iterate the personN nodes in the favorties XML
foreach ($favoritesXpath->evaluate('.//personN') as $personFavorites) {
$personId = (int)$personFavorites->getAttribute('number');
// find the matching personL node in the persons XML
foreach ($personsXpath->evaluate('.//personN[@number='.$personId.']/personL') as $personNode) {
// check if it has a 'favourites' child already
$favoritesNode = $personsXpath->evaluate('favourites', $personNode)->item(0);
if (!$favoritesNode) {
// otherwise create one
$favoritesNode = $personNode->appendChild(
$personsDocument->createElement('favourites')
);
}
// now iterate the different favorites of a person
foreach ($personFavorites->childNodes as $favorite) {
// import and add
$favoritesNode->appendChild($personsDocument->importNode($favorite, TRUE));
}
}
}
$personsDocument->formatOutput = TRUE;
echo $personsDocument->saveXML();
Output:
<?xml version="1.0"?>
<personinfo>
<personN number="1">
<personL letter="A">
<fullname>
<firstname>Summer</firstname>
<lastname>Smith</lastname>
</fullname>
<favourites>
<color>pink</color>
<animal>cat</animal>
</favourites>
</personL>
</personN>
<personN number="2">
<personL letter="B">
<fullname>
<firstname>Autumn</firstname>
<lastname>Smith</lastname>
</fullname>
<favourites>
<color>blue</color>
<animal>dog</animal>
</favourites>
</personL>
</personN>
</personinfo>
Adding a favourites
parent for each favorite does not make much sense. So I added a check to my example. If you really want the parent nodes, you can remove it:
foreach ($personsXpath->evaluate('.//personN[@number='.$personId.']/personL') as $personNode) {
//create 'favourites' child
$favoritesNode = $personNode->appendChild(
$personsDocument->createElement('favourites')
);
foreach ($personFavorites->childNodes as $favorite) {
//...
Nod added into xml as child, wanted sibling (SimpleXMLElement)
The XML output is:
<?xml version="1.0"?>
<Request RequestType="1"><Data/><Data2/></Request>
In other words the Data
and Data2
elements are siblings, but short empty tags. If the browser loads it as HTML it will try to repair the missing closing tags. This will not happen if it is parsed as XML. Make sure that you send the correct content type header:
header('Content-type: application/xml; charset=utf-8');
If you import the SimpleXMLElements into DOM (or better generate the document using DOM in the first place) you get a more options for saving the XML.
$element = dom_import_simplexml($request_xml);
echo $element->ownerDocument->saveXml(NULL, LIBXML_NOEMPTYTAG);
Output:
<?xml version="1.0"?>
<Request RequestType="1"><Data></Data><Data2></Data2></Request>
Related Topics
Pdo Bind Unknown Number of Parameters
Variable Variables in PHP - What Is Their Purpose
How to Parse This Table and Extract Data from It
Wrapping a Div Around Every Third Item in a Foreach Loop PHP
Calling a Controller Function in Another Controller in Codeigniter
Trouble Passing Variables to PHP Script on Image Upload
How to Store a Class Instance in a $_Session Space
Convert Hex Code into Readable String in PHP
Can Mongodb and Its Drivers Preserve the Ordering of Document Elements
Change Today's Date and Time in PHP
Error 1366 (Hy000): Incorrect String Value: '\Xf0\X9F\X98\X9C' for Column 'Comment' at Row 1
Replace the Last Comma with an & Sign
Getting PHP to Run a Python Script
How to Fix Server Status Code: 302 Found by SQL Inject Me Firefox Addon