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
Mongodb Aggregate Query Using PHP Driver
PHP Domdocument - Get HTML Source of Body
Php: How to Add Leading Zeros/Zero Padding to Float via Sprintf()
Yii2 Links Between Frontend and Backend (Advanced Template)
Pdo Bind Unknown Number of Parameters
How to Get Woocommerce Variation Id
How to Load the Requested Language File: Language/En/Form_Validation_Lang.Php
How to Create a Nested Array Out of an Array in PHP
Interview Question: How to Have an Echo Before Header
File Upload PHP $_Files Undefined Index Error
Appending a Value of a Variable to a Variable Name
Facebook Oauthexception: "User Hasn't Authorized the Application to Perform This Action"
Dompdf - Attach Created PDF to Email
Symfony: Change Database Dynamically
PHP Replace All Spaces with Hyphens