How to delete and edit specific xml node using PHP? - php

I am practicing on XML and PHP. I can not find out how to delete the whole xml node. Here is my XML:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<playlist_name>Channel List</playlist_name>
<category>
<category_id>1</category_id>
<category_title>HD</category_title>
</category>
<channel>
<title>VTC HD1</title>
<stream_url><![CDATA[http://203.162.16.22:80/lives/origin01/vtchd1.isml/vtchd1.m3u8]]></stream_url>
<logo_30x30>vtchd1.jpg</logo_30x30>
<category_id>1</category_id>
</channel>
<channel>
<title>VTC HD2</title>
<stream_url><![CDATA[http://203.162.16.22:80/lives/origin01/vtchd2.isml/vtchd2.m3u8]]></stream_url>
<logo_30x30>vtchd2.jpg</logo_30x30>
<category_id>1</category_id>
</channel>
</items>
And here is the code of two function which I am having problem, delete() and edit()
<?php
function delete_channel()
{
$file = "nStream.xml";
$fp = fopen($file, "rb") or die("cannot open file");
$str = fread($fp, filesize($file));
$xml = new DOMDocument();
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$xml->loadXML($str) or die("Error");
// original
// echo "<xmp>OLD:\n". $xml->saveXML() ."</xmp>";
// get document element
$root = $xml->documentElement;
$fnode = $root->firstChild;
//get a node
$ori = $fnode->childNodes->item(0);
// remove
$fnode->removeChild($ori);
// echo "<xmp>NEW:\n". $xml->saveXML() ."</xmp>";
}
function edit_channel()
{
echo 'Go Edit';
}
For the delete_channel(), nothing is deleted when I run that function. I want each time I use that function, one in xml file ll be deleted.

delete a <channel> with simplexml:
$xml = simplexml_load_file($filename);
// select the channel to be deleted by title
$channel = $xml->xpath("//channel[title='VTC HD2']");
// delete it!
unset($channel[0][0]);
// save it
$xml->asXML($filename);
see it working: https://eval.in/37084

Related

How to append multiple XML files

I have a large XML file which takes forever to load on external FTP editor so I would like to split it into several files.
I use simplexml_load_file but couldn't make it load multiple files into same array.
XML files has the same structure, here's a sample of each file:
a.xml:
<?xml version="1.0"?>
<queries>
<query>
<admin_user_type>user</admin_user_type>
<show_in_menu>True</show_in_menu>
<title>Dashboard</title>
<vertical_report>True</vertical_report>
</query>
</queries>
b.xml:
<?xml version="1.0"?>
<queries>
<query>
<admin_user_type>admin</admin_user_type>
<show_in_menu>false</show_in_menu>
<title>Profile Element</title>
<input_name>Id</input_name>
<input_type>hidden</input_type>
</query>
</queries>
There are about 200 queries in 7,000 lines between the two files.
The code fails on the foreach below:
$xml = read_xml_files();
foreach($xml->children() as $xml) {
...
...
}
Below is what I've taken from Nigel's suggestion:
function read_xml_files() {
$target = new DOMDocument();
$target->loadXML('<base />');
mergeFile($target, XML_FILES_FOLDER."a.xml");
mergeFile($target, XML_FILES_FOLDER."b.xml");
$xml = simplexml_import_dom($target);
return $xml->asXML();
}
function mergeFile ( DOMDocument $target, $fileName ) {
$source = new DOMDocument();
$source->load($fileName);
foreach ( $source->childNodes as $row ) {
$import = $target->importNode($row, true);
$target->documentElement->appendChild($import);
}
}
Thanks for any suggestion!
If you use DOMDocument to do the main merging part...
function mergeFile ( DOMDocument $target, $fileName ) {
$source = new DOMDocument();
$source->load($fileName);
foreach ( $source->childNodes as $row ) {
$import = $target->importNode($row, true);
$target->documentElement->appendChild($import);
}
}
$target = new DOMDocument();
$target->loadXML('<base />');
mergeFile($target, "file1.xml");
mergeFile($target, "file2.xml");
$xml = simplexml_import_dom($target);
echo $xml->asXML();
At the end $xml contains the merged files.
Note that this adds another level to the document (unless I know the type of contents it's difficult to do anything else). So in this case you will get something like...
file1.xml
<?xml version="1.0" encoding="UTF-8"?>
<A>A</A>
file2.xml
<?xml version="1.0" encoding="UTF-8"?>
<B>B</B>
Result will be
<?xml version="1.0"?>
<base>
<A>A</A>
<B>B</B>
</base>
Update:
You could also try...
function read_xml_files() {
$target = new DOMDocument();
$target->loadXML('<queries />');
mergeFile($target, "NewFile.xml");
mergeFile($target, "NewFile1.xml");
$xml = simplexml_import_dom($target);
return $xml->asXML();
}
function mergeFile ( DOMDocument $target, $fileName ) {
$source = new DOMDocument();
$source->load($fileName);
foreach ( $source->getElementsByTagName("query") as $row ) {
$import = $target->importNode($row, true);
$target->documentElement->appendChild($import);
}
}
This merges the file so that the result is
<?xml version="1.0"?>
<queries>
<query>
<admin_user_type>user</admin_user_type>
<show_in_menu>True</show_in_menu>
<title>Dashboard</title>
<vertical_report>True</vertical_report>
</query>
<query>
<admin_user_type>admin</admin_user_type>
<show_in_menu>false</show_in_menu>
<title>Profile Element</title>
<input_name>Id</input_name>
<input_type>hidden</input_type>
</query>
</queries>

XML/PHP: XML doesnt get written properly by my script

I seem to have a small problem, whenever i insert information via a form into my XML file, it adds the information directly IN the previous's entry's child, instead of creating a new child, for the entry, i get something like THIS:
<people>
<person>
<name>Lighty</name>
<age>17</age>
<sex>M</sex>
<comment>iets</comment>
<name>Darky</name><age>22</age><sex>F</sex><comment>things</comment></person>
While i need to have something, that would look like THIS:
<people>
<person>
<name>Lighty</name>
<age>17</age>
<sex>M</sex>
<comment>iets</comment>
</person>
<person>
<name>Darky</name>
<age>22</age>
<sex>F</sex>
<comment>iets</comment>
</people>
i tried using the "$xml->formatOutput = true;" line, but it would just add the child formatOutput with 1 filled in, a complete fail.
Any idea what im doing wrong? here is m PHP Code:
<?php
echo ('Script started');
//making sure the script only runs when you use a post
if ($_SERVER["REQUEST_METHOD"] == "POST") {
echo ('-Post accepted');
//Load XML File into variable
$xml = simplexml_load_file("phptest3.xml");
echo ('-XML Loaded');
//Connect form to Variables
$name = $_POST['name'];
$age = $_POST['age'];
$sex = $_POST['sex'];
$comment = $_POST['comment'];
echo ('-Vars connected');
//Function to strip items that are not needed to prevend XSS/Injections
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
echo ('-Injections stripped');
//Create new children in XML file and Connect the from data to the corresponding XML entries
$xml->formatOutput = true;
$xml->people[0];
$xml->people->addChild('person');
$xml->person->addChild('name', $name);
$xml->person->addChild('age', $age);
$xml->person->addChild('sex', $sex);
$xml->person->addChild('comment', $comment);
echo ('-Data inserted');
//Save current data to XML file...
$xml->savexml('phptest3.xml');
echo ('-saved');
}
echo ('-Script ended.');
?>
You can do this with a combination of SimpleXMLElement and DOMDocument.
This is how I did it:
<pre>
<?php
// Orignal XML - Starting Empty
$xmlStr = "<?xml version='1.0' standalone='yes'?>
<people></people>";
// Load XML
$people = new SimpleXMLElement($xmlStr);
// Debug (Before Add)
echo "<b>Before</b> Add\r\n";
print_r($people);
echo "<hr>\r\n\r\n";
// Add First Person
$newPerson = $people->addChild('person');
$newPerson->addChild('name', 'Lighty');
$newPerson->addChild('age', 17);
$newPerson->addChild('sex', 'M');
$newPerson->addChild('comment', 'iets');
// Debug (After Add)
echo "<b>After</b> Add\r\n";
print_r($people);
echo "<hr>\r\n\r\n";
// Output Modified XML With Formatting
$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
$dom->loadXML($people->asXML());
$dom->formatOutput = true;
echo $dom->saveXml();
?>
Browser Outout:
Formatted XML Output:
<?xml version="1.0" standalone="yes"?>
<people>
<person>
<name>Lighty</name>
<age>17</age>
<sex>M</sex>
<comment>iets</comment>
</person>
</people>
Hope this helps.

XML PHP Delete specific Child if?

I have a xml document looking like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<library>
<invites>
<invite>
<username>0</username>
<userid>0</userid>
</invite>
<invite>
<username>Danielle</username>
<gameid>87808</gameid>
</invite>
<invite>
<username>Petra</username>
<userid>978</userid>
</invite>
</invites>
</library>
Now, I want to delete the <invite> with Danielle but I am not sure how? I am using this right now but this will only delete the first record?
$file = 'my.xml';
$fp = fopen($file, "rb") or die("cannot open file");
$str = fread($fp, filesize($file));
$xml = new DOMDocument("1.0", "ISO-8859-1");
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$xml->loadXML($str) or die("Error");
$root = $xml->documentElement;
$fnode = $root->firstChild;
$ori = $fnode->childNodes->item(0);
$fnode->removeChild($ori);
$xml->save($file);
I want to be able to delete depending on either gameid or userid. How do I go about this?
Thanks in advance :-)
You could use XPath to select all nodes that have a certain userid or gameid: http://www.w3schools.com/xpath/default.asp
Try this:
Using DOM & DOMXPath.
<?php
$dom = new DOMDocument( '1.0' );
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
// load the xml file
$dom->loadXML( '<?xml version="1.0" encoding="ISO-8859-1"?>
<library>
<invites>
<invite>
<username>0</username>
<userid>0</userid>
</invite>
<invite>
<username>Danielle</username>
<gameid>87808</gameid>
</invite>
<invite>
<username>Petra</username>
<userid>978</userid>
</invite>
</invites>
</library>', LIBXML_NOBLANKS );
$xpath = new DOMXPath($dom);
//find all 'invite' nodes with username=Danielle and delete'em.
$node = $xpath->query("//invite[username='Danielle']");
// if found, append the new "value" node
if( $node->length ) {
foreach ($node as $n) {
$n->parentNode->removeChild( $n );
}
}
header('content-type: text/xml');
echo $dom->saveXML();
?>
Hope this helps.

XML creation on the fly using PHP

I have a small requirement where I need to create a XML file on the fly. It was no problem for me to create a normal xml file which would be looking like this:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>
<name></name>
</item>
</root>
But my requirement is such that I need to create a XML file whose output is:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>
<name url = "C:\htdocs\proj1\source_file1"/>
<name url = "C:\htdocs\proj1\source_file2"/>
<name url = "C:\htdocs\proj1\source_file3"/>
</item>
</root>
I have tried in this fashion:
<?php
$domtree = new DOMDocument('1.0', 'UTF-8');
$domtree->formatOutput = true;
$xmlRoot = $domtree->createElement("root");
$xmlRoot = $domtree->appendChild($xmlRoot);
$item = $domtree->createElement("item");
$item = $xmlRoot->appendChild($item);
$name= $domtree->createElement("name");
$name = $item->appendChild($name);
$sav_xml = $domtree->saveXML();
$handle = fopen("new.xml", "w");
fwrite($handle, $sav_xml);
fclose($handle);
?>
But I wanted to append/add the url="path" to my elements. I have tried declaring variables with url and path but this throws me errors like:
Uncaught exception 'DOMException' with message 'Invalid Character Error'
Any ideas how to approach this problem!
Thanks
You just have to declare that attributes via php DOM:
...
$name= $domtree->createElement("name");
$urlAttribute = $domtree->createAttribute('url');
$urlAttribute->value = 'C:\htdocs\proj1\source_file1';
$name->appendChild($urlAttribute);
$item->appendChild($name);
...
Link to DOMDocument docs

XML Parsing Error

here i am creating xml file dynamically at run time but i m getting error
XML Parsing Error: junk after document element
Location: http://localhost/tam/imagedata.php?imageid=8
Line Number 9, Column 1:
^
$id=$_GET['imageid'];
$dom = new DomDocument('1.0');
$query="select * from tbl_image_gallery where imageId='$id'";
$select=mysql_query($query);
while($res=mysql_fetch_array($select))
{
$content = $dom->appendChild($dom->createElement('content'));
$image = $content->appendChild($dom->createElement('image'));
$small_image_path = $image->appendChild($dom->createElement('small_image_path'));
$small_image_path->appendChild($dom->createTextNode("load/images/small/".$res['image']));
$big_image_path = $image->appendChild($dom->createElement('big_image_path'));
$big_image_path->appendChild($dom->createTextNode("load/images/big/".$res['image']));
$description = $image->appendChild($dom->createElement('description'));
$description->appendChild($dom->createTextNode($res['description']));
$dom->formatOutput = true;
}
echo $test1 = $dom->saveXML();
and xml format is
<?xml version="1.0"?>
<content>
<image>
<small_image_path>load/images/small/1.jpg</small_image_path>
<big_image_path>load/images/big/1.jpg</big_image_path>
<description>hgjghj</description>
</image>
<image><small_image_path>load/images/small/2.jpg</small_image_path><big_image_path>load/images/big/2.jpg</big_image_path><description>fgsdfg</description></image><image><small_image_path>load/images/small/3.jpg</small_image_path><big_image_path>load/images/big/3.jpg</big_image_path><description>sdfgsdfg</description></image><image><small_image_path>load/images/small/4.jpg</small_image_path><big_image_path>load/images/big/4.jpg</big_image_path><description>gsbhsg</description></image><image><small_image_path>load/images/small/4.jpg</small_image_path><big_image_path>load/images/big/4.jpg</big_image_path><description>gsbhsg</description></image><image><small_image_path>load/images/small/avatar.jpg</small_image_path><big_image_path>load/images/big/avatar.jpg</big_image_path><description></description></image></content>
Can it be that you are posting html code into the description field?
Could be usefull to add a CDataSection instead of a TextNode
$cdata = $dom->createCDATASection($res['description']);
$image->appendChild($cdata);

Categories