Simplexml: Append One Tree to Another

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.

Why php simplexml allow addChild in one of these examples but not the other?

In your first instance, you're thinking that $xml->RequestHeader refers to the <ns:RequestHeader/> node in your source, but it doesn't. You could have used any fake name with no change in the output of $xml->asXML(); So you get a warning when you try to add a child because $header is not actually a member of your $xml tree.

In the second instance, you're adding the child directly to the $xml tree that was parsed, so you get no warning:

$header = $xml->addChild('RequestHeader');

It seems that the SimpleXML -> operator is not designed to sort out your ns: flags. Your first code block works if you remove them from $base

$base = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
'<RootNode xmlns="http://www.bogus.com/bogus/">' .
'<RequestHeader/>' .
'<ContractInfo/>' .
'</RootNode>' . "\n";
$xml = simplexml_load_string($base);
$header = $xml->RequestHeader;

$header->addChild('SourceID', '123456');
echo $xml->asXML() . "\n\n";

This raises no warning

PHP SimpleXML: insert node at certain position

The following is a function to insert a new SimpleXMLElement after some other SimpleXMLElement. Since this isn't directly possible with SimpleXML, it uses some DOM classes/methods behind-the-scenes to get the job done.

function simplexml_insert_after(SimpleXMLElement $insert, SimpleXMLElement $target)
{
$target_dom = dom_import_simplexml($target);
$insert_dom = $target_dom->ownerDocument->importNode(dom_import_simplexml($insert), true);
if ($target_dom->nextSibling) {
return $target_dom->parentNode->insertBefore($insert_dom, $target_dom->nextSibling);
} else {
return $target_dom->parentNode->appendChild($insert_dom);
}
}

And an example of how it might be used (specific to your question):

$sxe = new SimpleXMLElement('<root><nodeA/><nodeA/><nodeA/><nodeC/><nodeC/><nodeC/></root>');
// New element to be inserted
$insert = new SimpleXMLElement("<nodeB/>");
// Get the last nodeA element
$target = current($sxe->xpath('//nodeA[last()]'));
// Insert the new element after the last nodeA
simplexml_insert_after($insert, $target);
// Peek at the new XML
echo $sxe->asXML();

If you want/need an explanation of how this works (the code is fairly simple but might include foreign concepts), just ask.

How to replace XML node with SimpleXMLElement PHP

Similar to what has been outlined in SimpleXML: append one tree to another you can import those nodes into DOMDocument because as you write:

"The class SimpleXMLElement dont have a method 'replaceChild' like the DOM."

So when you import into DOM you can use those:

$xml1 = simplexml_load_string($string1);
$xml2 = simplexml_load_string($string2);

$domToChange = dom_import_simplexml($xml1->map->operationallayers);
$domReplace = dom_import_simplexml($xml2);
$nodeImport = $domToChange->ownerDocument->importNode($domReplace, TRUE);
$domToChange->parentNode->replaceChild($nodeImport, $domToChange);

echo $xml1->asXML();

Which gives you the following output (non-beautified):

<?xml version="1.0"?>
<root>
<map>
<operationallayers>
<layer label="Teste1" type="feature" visible="false" useproxy="true" usePopUp="all" url="http://stackoverflow.com"/>
<layer label="Teste2" type="dynamic" visible="false" useproxy="true" usePopUp="all" url="http://google.com"/>
</operationallayers>
</map>
</root>

Additionally you can then take this and add the operation to your SimpleXMLElement so that it's easily wrapped. This works by extending from SimpleXMLElement:

/**
* Class MySimpleXMLElement
*/
class MySimpleXMLElement extends SimpleXMLElement
{
/**
* @param SimpleXMLElement $element
*/
public function replace(SimpleXMLElement $element) {
$dom = dom_import_simplexml($this);
$import = $dom->ownerDocument->importNode(
dom_import_simplexml($element),
TRUE
);
$dom->parentNode->replaceChild($import, $dom);
}
}

Usage Example:

$xml1 = simplexml_load_string($string1, 'MySimpleXMLElement');
$xml2 = simplexml_load_string($string2);

$xml1->map->operationallayers->replace($xml2);

Related: In SimpleXML, how can I add an existing SimpleXMLElement as a child element?.

Last time I extended SimpleXMLElement on Stackoverflow was in an answer to the "Read and take value of XML attributes" question.

append xml nodes inside another node in php

This is my solution:

if($xmlData->body){
$xmlIterator = new SimpleXMLIterator($xmlData->body->asXML());
$xmlIterator->rewind();
$txtBody = "";

for($i=0; $i < ($xmlIterator->count()); $i++){
$txtBody .= (trim($xmlIterator->current()) <> '') ? "<p>".trim($xmlIterator->current())."</p>" : "";
$xmlIterator->next();
}
#INSERT PULLQUOTE
foreach($xmlData->pullquote as $pull){
$txtBody .= $pull;

foreach ($pull->children() as $child){
$txtBody .= $child;
}

}

$data = $txtBody;
}

Issue appending to xml from html using SimpleXML

There are a couple of problems with your code. Firstly your XML is invalid, your close tag should be </tasks>.

When you try and get the <activities> tag in

$activities = $xml->activities;

this is trying to find the tag just off the root of the document, you could use the full path

$activities = $xml->taskList->tasks->activities;

or use (I have in this code) XPath to find it, this also allows you to pick out (if neccessary) which <tasks> tag you use depending of id.

$activities = $xml->xpath("//activities")[0];

$activity = $activities->addChild('activity');
$activity->addAttribute('id', '45678');
$activity->addChild('assigned', 'Jon');
$activity->addChild('priority', 'low');

You also use setAttribute() which doesn't exist - as the code shows it is addAttribute().



Related Topics



Leave a reply



Submit