While adding child, this error is thrown :
Cannot add child. Parent is not a permanent member of the XML tree.
I cannot resolve this.
This is my code :
if($visited=='FIRST')
{
$xml=new SimpleXMLElement("<xml/>");
$topology=$xml->addChild("Topology_Configuration");
$flavor=$topology->addChild("Flavor");
$networks=$topology->addChild("Networks");
$vms=$topology->addChild("VMs");
$vnfs=$topology->addChild("VNFs");
$xml->asXML('saddening.xml');
}
else
{
$xml= simplexml_load_file('saddening.xml');
$Topology_Configuration = new SimpleXMLElement($xml->asXML());
$vmcount=$_POST['arguments']['vmcount'];
$flavor=$Topology_Configuration->Flavor;
$flavor_name=$flavor->addChild($_POST['arguments']['flavorName']);
$Topology_Configuration->asXML('saddening.xml');
}
When it is executed for the first time, the file is created(in if part). Otherwise else part is executed. It cannot add the child and is throwing the error in line :
$flavor_name=$flavor->addChild($_POST['arguments']['flavorName']);. Please help!!
The XML from your first run results in an XML like this:
<?xml version="1.0"?>
<xml>
<Topology_Configuration>
<Flavor/>
<Networks/>
<VMs/><VNFs/>
</Topology_Configuration>
</xml>
So if you strip down the problem you can reproduce it with:
$Topology_Configuration = simplexml_load_file($fileName);
$flavor=$Topology_Configuration->Flavor;
$flavor->addChild('abc');
echo $Topology_Configuration->asXml();
Results in:
Warning: SimpleXMLElement::addChild(): Cannot add child.
Parent is not a permanent member of the XML tree in
The message is a little wrong, you just try to add the element to an element that does not exists. $Topology_Configuration contains the xml element node, not the Topology_Configuration.
Here are two possible solutions:
Change the XML structure
Create the XML with the Topology_Configuration as the root element.
$topology =new SimpleXMLElement("<Topology_Configuration/>");
Change the access to the Flavor
$xml = simplexml_load_file($fileName);
$flavor=$xml->Topology_Configuration->Flavor;
$flavor->addChild('abc');
At the first time, you can use example to add child nodes
$new_xml = new SimpleXMLElement("<root></root>");
$new_xml->addAttribute('newAttr', 'value');
$newsIntro = $new_xml->addChild('content');
$newsIntro->addAttribute('type', 'value');
Header('Content-type: text/xml');
echo $new_xml->asXML();
and result
<?xml version="1.0"?>
<news newAttr="value">
<content type="value"/>
</news
Related
please help.
I have XML file which is not filled correctly (some values are missed)
Bad example of XML
<?xml version="1.0"?>
<csv_data>
<row>
<brand>Maxxis</brand>
<code>1126668/02</code>
<articul_brand></articul_brand>
<tiporazmer></tiporazmer>
<name>(26/9.00 R12) 6PR TL</name>
<model>M-966 Mudzilla</model>
<sklad_msk></sklad_msk>
<sklad_nahabino></sklad_nahabino>
<sklad_chelny>8</sklad_chelny>
<price_big_opt>6,786р.</price_big_opt>
<price_small_opt>7,100р.</price_small_opt>
<price_retail>8,170р.</price_retail>
</row>
</csv_data>
Good example of XML
<?xml version="1.0"?>
<csv_data>
<row>
<brand>Metzeler</brand>
<code>ЦО04257/21</code>
<articul_brand>2491500</articul_brand>
<tiporazmer>110/80R18</tiporazmer>
<name>(110/80 R18) 58W TL (M) Front</name>
<model>Roadtec Z8</model>
<sklad_msk></sklad_msk>
<sklad_nahabino>2</sklad_nahabino>
<sklad_chelny></sklad_chelny>
<price_big_opt>7,720р.</price_big_opt>
<price_small_opt>8,106р.</price_small_opt>
<price_retail>9,270р.</price_retail>
</row>
</csv_data>
The point is that values in <tiporazmer></tiporazmer> are missed in bad example but they can be found in <name>(26/9.00 R12) 6PR TL</name>
The question is how to update fields <tiporazmer></tiporazmer> using name filed? Copy that without brackets? How?
What I did, but i've got an error Fatal error: Call to a member function getElementsByTagName() on a non-object in
Code:
<?php
$xml = new DOMDocument('1.0', 'utf-8');
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$xml->load('test2.xml');
$new_tiporazmer="26/9.00 R12";
//Get item Element
$element = $xml->getElementsByTagName('rows')->item(0);
//Load child elements
$tiporazmer = $element->getElementsByTagName('tiporazmer')->item(0);
//Replace old elements with new
$element->replaceChild($tiporazmer, $new_tiporazmer);
?>
The error is caused because you're calling getElementsByTagName('rows'), but the name of your XML node is row, so there shouldn't be an s in rows
Then in order to Replace old elements with new, you will need to use nodeValue instead of replaceChild unless you already have a constructed DOMDocument object ready.
But a better way to achieve what you want is to simply find the element by name directly, replace its text, and then save as a new file. I saved to the "/tmp" folder because permissions are usually writeable there on unix systems, but you can write anywhere your php interpreter is allowed.
<?php
$xml = new DOMDocument('1.0', 'utf-8');
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$xml->load('test2.xml');
$new_tiporazmer="26/9.00 R12";
//Get item Element and Replace old elements with new
$xml->getElementsByTagName('tiporazmer')->item(0)->nodeValue = $new_tiporazmer;
//Save as new file
$xml->save("/tmp/good.xml");
This results in good.xml:
<?xml version="1.0"?>
<csv_data>
<row>
<brand>Maxxis</brand>
<code>1126668/02</code>
<articul_brand/>
<tiporazmer>26/9.00 R12</tiporazmer>
<name>(26/9.00 R12) 6PR TL</name>
<model>M-966 Mudzilla</model>
<sklad_msk/>
<sklad_nahabino/>
<sklad_chelny>8</sklad_chelny>
<price_big_opt>6,786р.</price_big_opt>
<price_small_opt>7,100р.</price_small_opt>
<price_retail>8,170р.</price_retail>
</row>
</csv_data>
So, what i am trying to achieve is to load variables from PHP into an XML file.
this is how my XML looks at the moment:
<?xml version="1.0" encoding="ISO-8859-1"?>
<firstname></firstname>
<lastname></lastname>
And this is my PHP where i try to save the variables into the XML
$file = simplexml_load_file("filename.xml");
$xml->firstname = "Mark";
$xml->lastname = "Zuckerberg";
file_put_contents($file, $xml->asXML());
If i try to print this i get following error message:
Call to undefined method stdClass::asXML() in ... on line 1374
Any suggestions?
You don't create the initial XML file, the library you are using creates it for you.
XML DOM is a fine choice for this job.
$xml = new DOMDocument(); # Create a document
$xml_firstname = $xml->createElement("firstname", "Over"); # Create an element
$xml_lastname = $xml->createElement("lastname", "Coder"); # Create an element
$xml->appendChild($xml_firstname); # Add the element to the document
$xml->appendChild($xml_lastname); # Add the element to the document
$xml->save("myfancy.xml"); # Save the document to a file
The output would be
<?xml version="1.0" encoding="utf-8"?>
<firstname>Over</firstname>
<lastname>Coder</lastname>
Enable error reporting (like error_reporting( E_ALL );) and you will understand quickly why it does not work:
Warning: simplexml_load_file(): xml.xml:3: parser error : Extra content at the end of the document
// your XML is not correctly formatted (XML requires a root node)
Warning: Creating default object from empty value
// $xml->firstname when $xml does not exists
To resolve that, your XML should looks like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<data><!-- here comes the root node -->
<firstname></firstname>
<lastname></lastname>
</data>
And the PHP should looks like previous answers:
$xml = simplexml_load_file("filename.xml");
$xml->firstname = "Mark";
$xml->lastname = "Zuckerberg";
file_put_contents("filename_copy.xml", $xml->asXML());
First off: where do you establish $xml?
You start with $file = ... but then refer to the object as $xml.
Either change the object name to $xml or change the references to $file:
$xml = simplexml_load_file("filename.xml"); /* note the object name change */
$xml->firstname = "Mark";
$xml->lastname = "Zuckerberg";
Next, your file_put_contents() command is incorrect. The first parameter is accepts is the filename, however in your example $file is not a name but a simplexml object.
file_put_contents("path/to/file.xml", $xml->asXML());
Alternatively, use the asXML() method with the path by doing this (thanks bassxzero):
$xml->asXML("path/to/file.xml");
Finally, your script is outputting the error:
Call to undefined method stdClass::asXML()
This implies that you can't call $xml->axXML() as (I'm assuming) either the method doesn't exist, or the object doesn't have the correct method.
Changing the name of the object initially (the first issue) should fix this!
From the code, you load the XML into $file.
But you edit $xml. The below code should work
$xml = simplexml_load_file("filename.xml");
$xml->firstname = "Mark";
$xml->lastname = "Zuckerberg";
file_put_contents("output.xml", $xml->asXML());
If I have the following structure in an XML File;
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CstmrDrctDbtInitn>
<GrpHdr>
<MsgID>rBYEqfjzEU</MsgID>
<CreDtTm>2014-07-01T12:36:15</CreDtTm>
<NbOfTxs>2</NbOfTxs>
<CtrlSum>400.4</CtrlSum>
<InitgPty>
<Id>
<PrvtId>
<Othr>
<Id>IA1234567</Id>
</Othr>
</PrvtId>
</Id>
</InitgPty>
</GrpHdr>
</CstmrDrctDbtInitn>
</Document>
The above code represents one transaction between the <CstmrDrctDbtInitn> and <\CstmrDrctDbtInitn> tags. This file will be appended to include more transactions which will all start and end with a <CstmrDrctDbtInitn> and <\CstmrDrctDbtInitn> tags. I need to count the number of transactions in the file, so i basically need to count the number of <CstmrDrctDbtInitn> tags in the file. Any suggestions? Sorry if I am explaining this badly, confused!
I altered the following PHP code as suggested but no luck :(
$filename = date('Y-W').'.xml'; //2014-26.xml
//Check if a file exists
if (file_exists($filename))
{
$dom = simplexml_load_string($xml);
global $NumberTransactions;
$NumberTransactions = count($dom->CstmrDrctDbtInitn);
// call xml appendFile function
appendFile($filename);
}
else
{
// call xml createFile function
createFile($filename);
}
Assuming you mean to count the number of child nodes under GrpHdr - you could use SimpleXML:
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CstmrDrctDbtInitn>
<GrpHdr>
<MsgID>rBYEqfjzEU</MsgID>
<CreDtTm>2014-07-01T12:36:15</CreDtTm>
<NbOfTxs>2</NbOfTxs>
<CtrlSum>400.4</CtrlSum>
<InitgPty>
<Id>
<PrvtId>
<Othr>
<Id>IA1234567</Id>
</Othr>
</PrvtId>
</Id>
</InitgPty>
</GrpHdr>
</CstmrDrctDbtInitn>
</Document>';
$dom = simplexml_load_string($xml);
// var_dump($dom->CstmrDrctDbtInitn->GrpHdr);
echo count($dom->CstmrDrctDbtInitn->GrpHdr->children());
If you meant a variation you should be able to get a good clue of the structure by uncommenting that var_dump line and working through the object structure.
If you meant something else - give us a clue by telling us in detail what you wanted the count value to be based on your example data.
===================== UPDATED FOLLOWING CLARIFICATION BELOW=============
To count the number of CstmrDrctDbtInitn groups you can use the original example, but instead the count line would be:
echo count($dom->CstmrDrctDbtInitn);
DOMXpath::evaluate() can use Xpath to count the nodes.
// create and load
$dom= new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
// register an alias/prefix for the namespace
$xpath->registerNamespace('iso', 'urn:iso:std:iso:20022:tech:xsd:pain.008.001.02');
// get the count
var_dump($xpath->evaluate('count(//iso:CstmrDrctDbtInitn)'));
Demo: https://eval.in/169122
I have problems to deal with XML in PHP. What i want is to remove a not needed element and replace it with a other one.
Let's say the XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<software>
<info>
<version>1.2</version>
<lasterror>1386680712</lasterror>
</info>
<decryption>
<funcgroup siglength="86">
<func>
<name>Mk</name>
<args>$a</args>
<code>XXXX</code>
</func>
<func>
<name>Nk</name>
<args>$a,$b</args>
<code>XXXX</code>
</func>
</funcgroup>
</decryption>
</software>
PHP Code:
$domtree = new DOMDocument('1.0', 'UTF-8');
$domtree->loadXML(file_get_contents('test.xml'));
$thedocument = $domtree->documentElement;
$list = $thedocument->getElementsByTagName('funcgroup');
foreach ($list as $domElement) {
$sig_length = $domElement->getAttribute('siglength');
if($sig_length == $signature_length) {
$domElement->parentNode->removeChild($domElement);
break;
}
}
$some_stuff = $domtree->getElementsByTagName('software');
$some_stuff = $domtree->getElementsByTagName('decryption');
$funcgroup = $domtree->appendChild($domtree->createElement('funcgroup'));
$funcgroup->setAttribute('siglength', $signature_length);
$func = $funcgroup->appendChild($domtree->createElement('func'));
$func->appendChild($domtree->createElement('name', $outer_element[0]));
$func->appendChild($domtree->createElement('args', $outer_element[1]));
$code = $func->appendChild($domtree->createElement('code'));
$code->appendChild($domtree->createTextNode($outer_element[2]));
Note: I removed some stuff otherwise it would get too complicated i guess. The above code shows what i do, but without some other loops and variables which are not needed in that question. Every variable (and array) is defined. So don't worry about that.
What i want is to remove the whole <funcgroup siglength="86"> in order to replace it with a different one.
The script works fine, but there is one problem in the output XML. It looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<software>
<info>
<version>6.3</version>
<lasterror>1386680712</lasterror>
</info>
<decryption/>
</software>
<funcgroup siglength="86">
<func>
<name>Nk</name>
<args>$a</args>
<code>YYYYY</code>
</func>
<func>
<name>Ok</name>
<args>$a,$b</args>
<code>YYYY</code>
</func>
</funcgroup>
As you can see, the closing software and decryption tags are on the wrong place now.
How can i fix that? I spent hours but can't find a working solution.
The problem is caused by the removeChild() since it works fine if i do not remove something.
You are adding your new child node to the document itself (instead of the decryption node), which is not what you want
$domtree->appendChild
Instead you should:
$decryption = $domtree->getElementsByTagName('decryption')->item(0);
$funcgroup = $decryption->appendChild($domtree->createElement('funcgroup'));
Edit:
You can edit the text value of the lasterror node by doin:
$domtree->getElementsByTagName('lasterror')->item(0)->firstChild->nodeValue = "New value";
Consult the documentation of the DOMNodeList and DOMNode class to see what else you can do with it.
I was tesing with a simple example of how to display XML in browser using PHP and found this example which works good
<?php
$xml = new DOMDocument("1.0");
$root = $xml->createElement("data");
$xml->appendChild($root);
$id = $xml->createElement("id");
$idText = $xml->createTextNode('1');
$id->appendChild($idText);
$title = $xml->createElement("title");
$titleText = $xml->createTextNode('Valid');
$title->appendChild($titleText);
$book = $xml->createElement("book");
$book->appendChild($id);
$book->appendChild($title);
$root->appendChild($book);
$xml->formatOutput = true;
echo "<xmp>". $xml->saveXML() ."</xmp>";
$xml->save("mybooks.xml") or die("Error");
?>
It produces the following output:
<?xml version="1.0"?>
<data>
<book>
<id>1</id>
<title>Valid</title>
</book>
</data>
Now I have got two questions regarding how the output should look like.
The first line in the xml file '', should not be displayed, that is it should be hidden
How can I display the TextNode in the next line. In total I am exepecting an output in this fashion
<data>
<book>
<id>1</id>
<title>
Valid
</title>
</book>
</data>
Is that possible to get the desired output, if so how can I accomplish that.
Thanks
To skip the XML declaration you can use the result of saveXML on the root node:
$xml_content = $xml->saveXML($root);
file_put_contents("mybooks.xml", $xml_content) or die("cannot save XML");
Please note that saveXML(node) has a different output from saveXML().
First question:
here is my post where all usable threads with answers are listed: How do you exclude the XML prolog from output?
Second question:
I don't know of any PHP function that outputs text nodes like that.
You could:
read xml using DomDocument and save each node as string
iterate trough nodes
detect text nodes and add new lines to xml string manually
At the end you would have the same XML with text node values in new line:
<node>
some text data
</node>