I have a little problem with creating an complex XML structure with PHP and Dom Document.
I want the structure to be like this:
<page PathToWeb="www.mysite.com">
<Questions>
<Question id="my id" member="true">
<Question id="my id2" member="true">
<Question id="my id3" member="true">
</Questions>
</page>
and the code i have so far is
<?php
/*Create DOM*/
$xml = new DOMDocument;
$xml->load('myxml.xml'); /* wich is just just blank <?xml?\> <page> </page>*/
$xpath = new DOMXPath($xml);
/*Set the base path*/
$hrefs = $xpath->evaluate("/page");
/*Add Path to web to the root /page*/
$href = $hrefs->item(0);
$href->setAttribute("PathToWeb",$PathToWeb);
/*Complex XML Creation with Xpath*/
/*ELEMENT APPEND (create questions into /page)*/
$href = $hrefs->item(0);
$element = $xml->createElement('Questions');
$href->appendChild($element);
/*XPATH EVALUATE*/
$hrefs = $xpath->evaluate("/page/Questions");
/*ELEMENT 1 APPEND*/
$href = $hrefs->item(0);
$element = $xml->createElement('Question');
$href->appendChild($element);
$hrefs = $xpath->evaluate("/page/Questions/Question");
$href = $hrefs->item(0);
$href->setAttribute("id","my id");
/*ELEMENT 2 APPEND*/
$href = $hrefs->item(0);
$element = $xml->createElement('Question');
$href->appendChild($element);
$hrefs = $xpath->evaluate("/page/Questions/Question");
$href = $hrefs->item(0);
$href->setAttribute("id","my id");
/*ELEMENT 3 APPEND*/
$href = $hrefs->item(0);
$element = $xml->createElement('Question');
$href->appendChild($element);
$hrefs = $xpath->evaluate("/page/Questions/Question");
$href = $hrefs->item(0);
$href->setAttribute("id","my id");
$href = $hrefs->item(0);
$href->setAttribute("member","true");
$string2 = $xml->saveXML();
?>
What is creating is:
<page PathToWeb="www.mysite.com">
<Questions><Question id="my id" member="true"><Question/></Question></Questions>
</page>
Editing only the first Question ...
How can i solve this?
Your code looks somewhat more complicated than it needs to be.
Because appendChild returns the appended node and setAttribute returns the set Attribute Node, you could also create the entire tree without any temp variables and also without any Xpath simply by chaining method calls and traversing the DOM tree:
$dom = new DOMDocument('1.0', 'utf-8');
$dom->appendChild($dom->createElement('page'))
->setAttribute('PathToWeb', 'www.mysite.com')
->parentNode
->appendChild($dom->createElement('Questions'))
->appendChild($dom->createElement('Question'))
->setAttribute('id', 'my_id')
->parentNode
->setAttribute('member', 'true')
->parentNode
->parentNode
->appendChild($dom->createElement('Question'))
->setAttribute('id', 'my_id2')
->parentNode
->setAttribute('member', 'true')
->parentNode
->parentNode
->appendChild($dom->createElement('Question'))
->setAttribute('id', 'my_id3')
->parentNode
->setAttribute('member', 'true');
$dom->formatOutput = true;
echo $dom->saveXml();
Understanding that DOM is a tree hierarchy of DOMNodes is essential when wanting to work with DOM. See DOMDocument in php for some explanation on that.
$xml = new DOMDocument('1.0','UTF-8');
$root = $xml->createElement('page');
$root->setAttribute("PathToWeb",$PathToWeb);
$wrap = $xml->createElement('Questions');
$root->appendChild($wrap);
for ($i = 1;$i<4;$i++)
{
$element = $xml->createElement('question');
$element->setAttribute("id","my id" . $i);
$element->setAttribute("member","true");
$wrap->appendChild($element);
}
$xml->appendChild($root);
$xml->formatOutput = true;
$xml->save('myxml.xml');// Thanks to Gordon
<?php
$xml = new DOMDocument;
$xml->load('myxml.xml'); /* wich is just just blank <?xml?> <page> </page>*/
$xpath = new DOMXPath($xml);
/*Set the base path*/
$base = $xpath->evaluate("/page")->item(0);
$base->setAttrubute("PathToWeb", $PathToWeb);
$questions = $xml->createElement('Questions');
$base->appendChild($questions);
for($i = 0; $i < 2; $i++) {
$question= $xml->createElement('Question');
$questions->appendChild($question);
$question->setAttribute("id","my id");
$question->setAttribute("member", "true");
}
$string2 = $xml->saveXML();
?>
This might help you to solve your problem and make your code much more compact and easier to deal with:
appendChild PHP Manual returns the new node. You can then directly work with it. No need to use xpath after appending the child to get access to it.
And if you add/set the attributes you want to set before adding the element node to the document, you most often don't even need to:
/*ELEMENT APPEND (create questions into /page)*/
$href = $hrefs->item(0);
$element = $xml->createElement('Questions');
$questions = $href->appendChild($element);
# ^^^
/*ELEMENT 1 APPEND*/
$element = $xml->createElement('Question');
$element->setAttribute("id","my id"); # prepare before adding
$questions->appendChild($element);
...
It's quite the same for the root element of your document (<page>). You do not need to use xpath to access it and manipulate it. It's documentElement PHP Manual:
/*Create DOM*/
$xml = new DOMDocument;
$xml->load('myxml.xml'); /* wich is just just blank <?xml?> <page> </page>*/
/*Add Path to web to the root /page*/
$href = $xml->documentElement;
$href->setAttribute("PathToWeb",$PathToWeb);
Related
How do I change the outerHtml of an element using PHP DomDocument class? Make sure, no third party library is used such as Simple PHP Dom or else.
For example:
I want to do something like this.
$dom = new DOMDocument;
$dom->loadHTML($html);
$tag = $dom->getElementsByTagName('h3');
foreach ($tag as $e) {
$e->outerHTML = '<h5>Hello World</h5>';
}
libxml_clear_errors();
$html = $dom->saveHTML();
echo $html;
And the output should be like this:
Old Output: <h3>Hello World</h3>
But I need this new output: <p>Hello World</p>
You can create a copy of the element content and attributes in a new node (with the new name you need), and use the function replaceChild().
The current code will work only with simple elements (a text inside a node), if you have nested elements, you will need to write a recursive function.
$dom = new DOMDocument;
$dom->loadHTML($html);
$titles = $dom->getElementsByTagName('h3');
for($i = $titles->length-1 ; $i >= 0 ; $i--)
{
$title = $titles->item($i);
$titleText = $title->textContent ; // get original content of the node
$newTitle = $dom->createElement('h5'); // create a new node with the correct name
$newTitle->textContent = $titleText ; // copy the content of the original node
// copy the attribute (class, style, ...)
$attributes = $title->attributes ;
for($j = $attributes->length-1 ; $j>= 0 ; --$j)
{
$attributeName = $attributes->item($j)->nodeName ;
$attributeValue = $attributes->item($j)->nodeValue ;
$newAttribute = $dom->createAttribute($attributeName);
$newAttribute->nodeValue = $attributeValue ;
$newTitle->appendChild($newAttribute);
}
$title->parentNode->replaceChild($newTitle, $title); // replace original node per our copy
}
libxml_clear_errors();
$html = $dom->saveHTML();
echo $html;
Have tried numerous examples on SO but none have worked.
Goal: Remove a node (unit) and it's children, by specific id=
filename.xml
<archive>
<unit id="0424670018">
<data>Blah blah blah #1</data>
<gdate>2018-05-28 00:42:46</gdate>
</unit>
<unit id="0450170018">
<data>Blah blah blah #2</data>
<gdate>2018-05-28 00:45:01</gdate>
</unit>
</archive>
Code used, not sure why it does not work when loaded:
$id = '0450170018';
$file = 'filename.xml';
$xml = simplexml_load_string($file);
foreach($xml->archive as $fileload){
if($fileload->unit['#id'] == $id){
$dom = dom_import_simplexml($fileload);
$dom->parentNode->removeChild($dom);
}
}
You can fetch the node using Xpath. It allows to fetch the matching node(s) directly.
$id = '0450170018';
$document = new DOMDocument();
$document->load('filename.xml');
$xpath = new DOMXpath($document);
foreach ($xpath->evaluate("//unit[#id='$id']") as $unitNode) {
$unitNode->parentNode->removeChild($unitNode);
}
$document->save('filename.xml');
You need to use "DOMDocument" class
$doc = new DOMDocument;
$doc->load('filename.xml');
$xml = $doc->documentElement;
$id = '0450170018';
$domNodeList = $xml->getElementsByTagname('unit');
foreach ( $domNodeList as $domElement ) {
$valueID = $domElement->getAttribute('id');
if($valueID == $id)
{
$xml->removeChild($domElement);
}
}
$doc->save('filename.xml');
the code below successfully helps me to create a div.
$dom = new DOMDocument();
$ele = $dom->createElement('div', $textcon);
$dom->appendChild($ele);
$html = $dom->saveXML();
fwrite($myfile,$html);
I am having trouble creating a child div in the code below once the primary div is created
$file = "http://dd/showcase.php";
$doc = new DOMDocument();
$doc->loadHTMLFile($file);
$element = $doc->getElementsByTagName('div');
$dom = $element;
$ele = $dom->createElement('div', $textcon);
$dom->appendChild($ele);
$html = $dom->saveXML();
fwrite($myfile,$html);
The method
getElementsByTagName('div')
returns a list of all the elements named 'div', not a single element. Hence you need to add the child div to the first element of the list returned by the above method.
$dom = $element[0];
This might solve the problem
<?php
$file = "http://dd/showcase.php";
$doc = new DOMDocument();
$doc->loadHTMLFile($file);
$ele = $doc->createElement('div', $textcon);
$element = $doc->getElementsByTagName('div')->item(0);
$element->appendChild($ele);
$ele ->setAttribute('id', $divname);
$ele ->setAttribute('style', 'background: '.$divbgcolor.'; color :'.$divfontcolor.' ;display : table-col; width :100%;');
$doc->appendChild($element);
$html = $doc->saveXML();
fwrite($myfile,$html);
?>
Try this out.
Thanks
I have this XML file and I need to replace te value of qteStock using the php DOM,but I still can't get the concept.Can anyone help me please?
<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="Marque.xsl" ?>
<Marques xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="Marques.xsd">
<Marque>
<codeMarque>00003</codeMarque>
<nomMarque>Diesel</nomMarque>
<paysOrigine>USA</paysOrigine>
<qteStock>50</qteStock>
<qteLimite>5</qteLimite>
</Marque>
</Marques>
This is the php code I've been trying to manipulate:
<?php
$marque=$_POST['nomMarque'];
$qte=$_POST['qte'];
$xmlstring = 'entities/Marques.xml';
$dom = new DOMDocument;
$dom->load($xmlstring);
$xpath = new DOMXPath($dom);
$query = "//Marque[nomMarque='".$marque."']/qteStock";
$qteStock = $xpath->query($query);
$query = "//Marque[nomMarque='".$marque."']/qteLimite";
$qteLimite = $xpath->query($query);
$nouvelleQuantite = $qteStock->item(0)->nodeValue-$qte ;
$newQuantity = $dom->createTextNode($nouvelleQuantite);
$return = ($qteStock->replaceChild($newQuantity,$qteStock);
$dom->save('entities/Marques.xml');
?>
You can set the nodeValue property of the element node - integers do not need escaping in XML. If you need to write text that could contain &, set the nodeValue to an empty string (deletes all child nodes) and insert a new text node.
$changeValue = 5;
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
$nodes = $xpath->evaluate('/Marques/Marque[1]/qteStock');
// node found?
if ($nodes->length > 0) {
$stock = $nodes->item(0);
$newValue = $stock->nodeValue - $changeValue;
// just set the content (an int does not need any escaping)
$stock->nodeValue = (int)$newValue;
}
echo $dom->saveXml();
Demo: https://eval.in/149098
Following is my XML File content
Now I want to remove < text > element from xml, how can I do it.
$doc = new DOMDocument;
$doc->load("XML FILE");
$thedocument = $doc->documentElement;
$list = $thedocument->getElementsByTagName('text');
foreach ($list as $domElement){
//Code to remove current text element...
}
Did you check the manual? You can use removeChild. the manual has an example.
<?php
$doc = new DOMDocument;
$doc->load('book.xml');
$book = $doc->documentElement;
// we retrieve the chapter and remove it from the book
$chapter = $book->getElementsByTagName('chapter')->item(0);
$oldchapter = $book->removeChild($chapter);
echo $doc->saveXML();
?>