In Simplexml, How to Add an Existing Simplexmlelement as a Child Element

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



Leave a reply



Submit