remove node inside node in XML using PHP - php

I want to remove a specific node from my XML file and seems I missed something in code !
can you help me figure it out , for example I want to delete tag and all of its inner tags .
XML structure :
<students>
<student>
<username>sally</username>
<subjects>
<subjects>sub1</subjects>
<subjects>sub2</subjects>
<subjects>sub3</subjects>
</subjects>
</student>
<student>
<username>jojo</username>
<subjects>
<subjects>sub1</subjects>
<subjects>sub2</subjects>
<subjects>sub3</subjects>
<subjects>sub4</subjects>
<subjects>sub5</subjects>
</subjects>
</student>
</students>
function :
public static function delete_subjects($UserName, $fileName) {
//delete from xml
$xml = new DOMDocument();
$xml->load($fileName);
$users = $xml->getElementsByTagName('student');
foreach ($users as $user) {
$username = $user->getElementsByTagName('username')->item(0)->nodeValue;
if ($username == $UserName) {
$p=$user->getElementsByTagName('subjects')->item(0);
$xml->documentElement->removeNode($p);
break;
}
}
$xml->save($fileName);
}
call :
delete_subjects('jojo', $fileName);

Instead of $xml->documentElement->removeNode($p); try using $user->removeChild($p);
Edit: or even $p->parentNode->removeChild($p);

Related

PHP appendChild to XML root

I know this should be simple, but I'm new to PHP and just do not understand the documentation I've come across. I need a simple explanation.
I have an XML document that I would like to add nodes to. I can add nodes to the document, they only appear outside of the root node and cause errors to happen on subsequent attempts.
Here is my XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
</root>
and here is my PHP:
$playerID = "id_" . $_POST['player'];
//load xml file to edit
$xml = new DOMDocument();
$xml->load('../../saves/playerPositions.xml') or die("Error: Cannot load file.");
//check if the player is already in the database
if(isset($xlm->$playerID)){
echo "Player ID was found.";
}
else{
echo "Player ID was not found.";
//so we want to create a new node with this player information
$playerElement = $xml->createElement($playerID, "");
$playerName = $xml->createElement("name", "John Doe");
//add the name to the playerElement
$playerElement->appendChild($playerName);
//add the playerElement to the document
//THIS IS WHERE THE ERROR OCCURS
$xml->root->appendChild($playerElement);
//save and close the document
$xml->formatOutput = true;
$xml->save("../../saves/playerPositions.xml");
}
echo "done";
If I just use $xml->appendChild() then I can modify the document, but the new text appears outside of <root></root>.
The exact error is:
Notice: Undefined property: DOMDocument::$root
$xml->root isn't the correct way to access root element in this context, since $xml is an instance of DOMDocument (It will work if $xml were SimpleXMLElement instead). You can get root element of a DOMDocument object from documentElement property :
$xml->documentElement->appendChild($playerElement);
eval.in demo 1
Or, more generally, you can get element by name using getElementsByTagName() :
$xml->getElementsByTagName("root")->item(0)->appendChild($playerElement);
eval.in demo 2
Further reading : PHP DOM: How to get child elements by tag name in an elegant manner?
That said, this part of your code is also not correct for the same reason (plus a typo?):
if(isset($xlm->$playerID)){
echo "Player ID was found.";
}
Replace with getElementsByTagName() :
if($xml->getElementsByTagName($playerID)->length > 0){
echo "Player ID was found.";
}
You are trying to handle the dom like a Standar Object, but is not.
To look for elements, you need to use the function getElementsByTagName, and handle the dom like a collection of nodes, like this:
$xml = new DOMDocument();
$xml->loadXML('<?xml version="1.0" encoding="UTF-8"?>
<root>
</root>') or die("Error: Cannot load file.");
$len = $xml->getElementsByTagName('player')->length;
if ( $len > 0 ) {
} else {
$player = $xml->createElement('player', '');
$playerName = $xml->createElement('playerName', "Jhon Doe");
$player->appendChild( $playerName );
$root = $xml->getElementsByTagName('root');
if ( $root->length > 0 ) {
$root[0]->appendChild( $player );
}
$xml->formatOutput = true;
echo $xml->saveXML();
}
This code produces:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<player><playerName>Jhon Doe</playerName></player></root>

How to change value of cdata inside a .xml file and then again save it using php

i want to just change ABCD written inside cdata of data.xml file with a new value held by $change by php. i am able to get all cdata value using the following code but don't know how to change and save it.
<?php
$doc = new DOMDocument();
$doc->load('data.xml');
$destinations = $doc->getElementsByTagName("text");
foreach ($destinations as $destination) {
foreach($destination->childNodes as $child) {
if ($child->nodeType == XML_CDATA_SECTION_NODE) {
echo $child->textContent . "<br/>";
}
}
}
?>
my data.xml file.
<?xml version="1.0" encoding="utf-8"?>
<data displayWidth="" displayHeight="" frameRate="" fontLibs="assets/fonts/Sansation_Regular.swf">
<preloader type="snowflake" size="40" color="0xffffff" shapeType="circle" shapeSize="16" numShapes="8"/>
<flipCard openingDuration="2" openCardZ="400" tweenMethod="easeOut" tweenType="Back">
<video videoPath="video.MP4" frontImage="assets/christmas/front.jpg" videoPoster="assets/christmas/videoPoster.jpg" videoFrame="assets/christmas/videoFrame.png" bufferTime="10" loopVideo="true"/>
<flips backImage="assets/christmas/back.jpg" backColor="0x808080">
<flip isText="true" xPos="600" yPos="470" openDelay="8" openDuration="2" tweenMethod="easeOut" tweenType="Elastic" action="link" url="http://activeden.net/">
<text id="name" font="Sansation_Regular" embedFonts="true" size="40" color="0x802020"><![CDATA[ABCD]]></text>
</flip>
<flip isText="true" xPos="300" yPos="30" openDelay="2" openDuration="2" tweenMethod="easeOut" tweenType="Elastic">
<text font="Sansation_Regular" embedFonts="true" size="80" color="0x202020"><![CDATA[HAPPY]]></text>
</flip>
</flips>
</flipCard>
</data>
You change the text inside a CDATA section by setting the nodeValue of that CDATA node (DOMCdataSection in PHP):
$child->nodeValue = $change;
Output (excerpt & simplified):
...
<flip isText="true" xPos="600" yPos="470" openDelay="8" openDuration="2" tweenMethod="easeOut" tweenType="Elastic" action="link" url="http://activeden.net/">
<text id="name" ... color="0x802020"><![CDATA[changed ABCD]]></text>
</flip>
<flip isText="true" xPos="300" yPos="30" openDelay="2" openDuration="2" tweenMethod="easeOut" tweenType="Elastic">
<text font="Sansation_Regular" ... ><![CDATA[changed HAPPY]]></text>
</flip>
...
For your second question you have on how to save the document: The method to save the XML document is DOMDocument::save:
$filename = '/path/to/file.xml';
$doc->save($filename);
Answer from #Hakre is correct. just want to update final working code because following code will only update my ABCD value not all.
<?php
$doc = new DOMDocument();
$xml='data.xml';
$doc->load($xml);
$destinations = $doc->getElementsByTagName("text");
foreach ($destinations as $destination) {
foreach($destination->childNodes as $child) {
if ($child->nodeType == XML_CDATA_SECTION_NODE) {
echo $child->textContent . "<br/>";
$child->nodeValue = "new value";
}
}break;
}
$doc->save($xml);
?>

Generate xml file with stylesheet using SimpleXML

I have a question about how to add a stylesheet to a SimpleXML generated XML file.
This is my code, but I don't know how to add a stylesheet for this.
$xml = new SimpleXMLElement('<Cart/>');
$Order = $xml->addChild('Person');
$Order->addChild('Name', $_GET['name']);
$Order->addChild('Last-name', $_GET['lname']);
$Order->addChild('E-mail', $_GET['email']);
$Order->addChild('Phone', $_GET['phone']);
$Order->addChild('Date', date('Y-m-d'));
$Order->addChild('Adress', isset($_GET['adress'])&&$_GET['adress'] != NULL?$_GET['adress']:'Not set');
$Products = $xml->addChild('Products');
foreach ($cart as $product_id) {
foreach($productlist as $list){
if($list['id'] == $product_id){
$Cart = $Products->addChild('Product');
$Cart->addChild('ID', $list['id']);
$Cart->addChild('Brand', $list['brand']);
$Cart->addChild('Model', $list['model']);
$Cart->addChild('Price', $list['price']);
}
}
}
Header('Content-type: text/xml');
date_default_timezone_set("Europe/Helsinki");
$xml->asXML('orders/' .date('Y-m-d(H-i-s)'). '.xml');
And this is the line that I want to add to the top of my generated XML file.
<?xml-stylesheet type="text/xsl" href="order.xsl" ?>
You can try just adding it before the root node
$xml = new SimpleXMLElement('<?xml version="1.0"?><?xml-stylesheet type="text/xsl" href="order.xsl"?><Cart/>');
you need to write
$xml->addProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="order.xsl"');
how to add function you can view here
SimpleXML insert Processing Instruction (Stylesheet)

PHP + XML - how to rename and delete XML elements using SimpleXML or DOMDocument?

I've had some success due to the help of StackOverflow community to modify a complex XML source for use with jsTree. However now that I have data that is usable, it is only so if i manually edit the XML to do the following :
Rename all <user> tags to <item>
Remove some elements before the first <user> tag
insert an 'encoding=UTF-8' into the XML opener
and lastly modify the <response> (opening XML tag) to <root>
XML File Example : SampleXML
I have read and read through so many pages on here and google but cannot find a method to achieve the above items.
Point (2) I have found out that by loading it via SimpleXML and using UNSET i can delete the portions I do not require, however I am still having troubles with the rest.
I thought I could perhaps modify the source with SimpleXML (that I am more familiar with) and then continue to modify the code via the help I had been provided before.
<?php
$s = file_get_contents('http://www.fluffyduck.com.au/sampleXML.xml');
$doc1 = simplexml_load_string($s);
unset($doc1->row);
unset($doc1->display);
#$moo = $doc1->user;
echo '<textarea>';
echo $doc1->asXML();
echo '</textarea>';
$doc = new DOMDocument();
$doc->loadXML($doc1);
$users = $doc->getElementsByTagName("user");
foreach ($users as $user)
{
if ($user->hasAttributes())
{
// create content node
$content = $user->appendChild($doc->createElement("content"));
// transform attributes into content elements
for ($i = 0; $i < $user->attributes->length; $i++)
{
$attr = $user->attributes->item($i);
if (strtolower($attr->name) != "id")
{
if ($user->removeAttribute($attr->name))
{
if($attr->name == "username") {
$content->appendChild($doc->createElement('name', $attr->value));
} else {
$content->appendChild($doc->createElement($attr->name, $attr->value));
}
$i--;
}
}
}
}
}
$doc->saveXML();
header("Content-Type: text/xml");
echo $doc->saveXML();
?>
Using recursion, you can create a brand new document based on the input, solving all your points at once:
Code
<?php
$input = file_get_contents('http://www.fluffyduck.com.au/sampleXML.xml');
$inputDoc = new DOMDocument();
$inputDoc->loadXML($input);
$outputDoc = new DOMDocument("1.0", "utf-8");
$outputDoc->appendChild($outputDoc->createElement("root"));
function ConvertUserToItem($outputDoc, $inputNode, $outputNode)
{
if ($inputNode->hasChildNodes())
{
foreach ($inputNode->childNodes as $inputChild)
{
if (strtolower($inputChild->nodeName) == "user")
{
$outputChild = $outputDoc->createElement("item");
$outputNode->appendChild($outputChild);
// read input attributes and convert them to nodes
if ($inputChild->hasAttributes())
{
$outputContent = $outputDoc->createElement("content");
foreach ($inputChild->attributes as $attribute)
{
if (strtolower($attribute->name) != "id")
{
$outputContent->appendChild($outputDoc->createElement($attribute->name, $attribute->value));
}
else
{
$outputChild->setAttribute($attribute->name, $attribute->value);
}
}
$outputChild->appendChild($outputContent);
}
// recursive call
ConvertUserToItem($outputDoc, $inputChild, $outputChild);
}
}
}
}
ConvertUserToItem($outputDoc, $inputDoc->documentElement, $outputDoc->documentElement);
header("Content-Type: text/xml; charset=" . $outputDoc->encoding);
echo $outputDoc->saveXML();
?>
Output
<?xml version="1.0" encoding="utf-8"?>
<root>
<item id="41">
<content>
<username>bsmain</username>
<firstname>Boss</firstname>
<lastname>MyTest</lastname>
<fullname>Test Name</fullname>
<email>lalal#test.com</email>
<logins>1964</logins>
<lastseen>11/09/2012</lastseen>
</content>
<item id="61">
<content>
<username>underling</username>
<firstname>Under</firstname>
<lastname>MyTest</lastname>
<fullname>Test Name</fullname>
<email>lalal#test.com</email>
<logins>4</logins>
<lastseen>08/09/2009</lastseen>
</content>
</item>
...

PHP XML add edit delete

I have the following XML structure, and I would like to have code that:
INSERTS
DELETES
Delete an entire element based on its TITLE value.
Replace the publisher's value with another value
<Game type="XXX">
<TITLE>XXX</TITLE>
<PUBLISHER>XXX</PUBLISHER>
</Game>
This is my XML structure:
<?xml version="1.0" encoding ="utf-8"?>
<GameStore>
<Game type="adventure">
<TITLE>Assassin's Creed: Brotherhood</TITLE>
<PUBLISHER>Ubisoft</PUBLISHER>
</Game>
<Game type="adventure">
<TITLE>Batman: Arkham Asylum</TITLE>
<PUBLISHER>Eidos</PUBLISHER>
</Game>
</GameStore>
Using SimpleXML:
<?php
// load the XML file
$games = simplexml_load_file('games.xml');
$i = 0;
foreach ($games as $game) {
if ($game->TITLE == 'Batman: Arkham Asylum') {
// remove the Game element
unset($games->Game[$i]);
}
$i++;
}
// save the amended file
$games->asXML('games2.xml');
?>
You will want to use the PHP DOM classes. I think it goes something like this.
To load an XML file.
$xml = new DOMDocument();
$xml->load('path/to/file.xml');
To insert.
$node = $xml->createElement('Game');
$newnode = $xml->appendChild($node);
To delete based on title.
foreach ($xml->Game as $node) {
if ($node->TITLE->nodeValue == 'some_title') {
$xml->removeChild($node);
}
}
etc
more info at http://www.php.net/manual/en/book.dom.php
You will need to learn http://www.php.net/manual/fr/book.dom.php for manipulating xml.
There is some hints :
// Inserts
$new_node = $dom->createElement('foo', 'bar');
$gamestore_node = $xpath->query('/*')->item(0)->appendChild($new_node);
echo $dom->saveXML();
// Delete based on title
$deletable_node = $xpath->query("//Game[TITLE/text() = 'Batman: Arkham Asylum']")->item(0);
$deletable_node->parentNode->removeChild($deletable_node);
echo $dom->saveXML();
// EDIT Replace Publisher's value with another value
$editable_node = $xpath->query("//PUBLISHER[text() = 'Ubisoft']")->item(0);
$editable_node->nodeValue = 'baz';
echo $dom->saveXML();

Categories