Delete XML node with SimpleXML, PHP - php

I'm trying to delete XML node with PHP (SimpleXML).
This is my XML:
<?xml version="1.0"?>
<items>
<a>
<name>A1</name>
<b>
<title>Item1</title>
<url>item1</url>
</b>
<b>
<title>Item2</title>
<url>item2</url>
</b>
<b>
<title>Item3</title>
<url>item3</url>
</b>
</a>
<a>
<name>A2</name>
<b>
<title>Item1</title>
<url>item1</url>
</b>
</a>
</items>
and this is my PHP code:
<?php
$xml = simplexml_load_file($_GET["xml"]);
$sxe = new SimpleXMLElement($xml->asXML());
$ID = $_GET["ID"];
$i = -1;
$num = $_GET["num"];
foreach ($sxe->children() as $var) {
if ($var == $ID) {
foreach ($var->children() as $data) {
if ($data == "link") {
$i++;
if ($i == $num) {
if ( ! empty($sxe)) {
unset($sxe[0]);
}
}
}
}
}
}
$sxe->asXML($_GET["xml"]);
?>
This code looks for with data of $ID (for example, $ID="A1"). The node it looks to delete is a node (with its and ), which is the #$num node.
Example: if $ID="A1" and $num=1,
it needs to delete the node with the title "Item2" and url "item2".
What am I doing wrong?
Thanks!

Use xpath to find a node. With your example it will be
//a[name="A1"]/b[2]
and use DomDocument method removeChild to change xml
$sxe = simplexml_load_string($xml);
$node = $sxe->xpath('//a[name="'. $ID .'"]/b['. $num .']');
$dom=dom_import_simplexml($node[0]);
$dom->parentNode->removeChild($dom);
echo $sxe->asXML();

Related

How to update an xml file on filesystem conditionally - PHP

I have the xml file called fonts.xml located on my filesystem.
Goal:
I want to update the attribute <status> where name is "Aclonica" but I don't know how to do it conditionally.
XML:
<fonts>
<font>
<name>Aclonica</name>
<category>Aclonica</category>
<variants>100,bold</variants>
<status>active</status>
</font>
<font>
<name>Azeebe</name>
<category>Sans-serif</category>
<variants>100,bold,italic</variants>
<status>active</status>
</font>
</fonts>
You need to use DOMDocument class. This way you select data using normal if condition:
solution:
$a = $_POST['font']; // here value 'Aclonica' is assigned to $a
$dom = new DOMDocument();
$dom->load('c:/xampp/htdocs/cms/public/fonts/font.xml');
foreach ($dom->documentElement->childNodes as $node) {
// print_r($node); // >> uncomment for debug purposes
if($node->nodeType == 1) {
$name = $node->getElementsByTagName('name')->Item(0);
if($name->nodeValue == $a) { // >> IMPORTANT: here is the condition you need
$OldJobId = $node->getElementsByTagName('status')->Item(0);
if($OldJobId->nodeValue == 'active') {
$newelement = $dom->createElement('status','inactive');
$OldJobId->parentNode->replaceChild($newelement, $OldJobId);
}else{
$newelement = $dom->createElement('status','active');
$OldJobId->parentNode->replaceChild($newelement, $OldJobId);
}
}
}
}
$dom->save("c:/xampp/htdocs/cms/public/fonts/font.xml");

simplexml doesn't read CDATA

I want to grab data from a xml file from a remote location which contains CDATA information in all nodes as listed below.
I use the following PHP function to grab such information but it doesn't work and seems not to be able to catch CDATA tags from xml file.
the question is whether my piece of code is correct or not ? and if it's wrong can you suggest any php code to get requested information?
<Items>
<Item ID="1">
<Name>Mountain</Name>
<Properties>
<Property Code="feature"><![CDATA[<ul><li>sample text</li></ul>]]></Property>
<Property Code="SystemRequirements"><![CDATA[Windows XP/Windows Vista]]></Property>
<Property Code="Description" Type="plain"><![CDATA[sample text2]]></Property>
</Properties>
</Item>
<Items>
and this is my php code :
<?
function xmlParse($file, $wrapperName, $callback, $limit = NULL) {
$xml = new XMLReader();
if (!$xml->open($file)) {
die("Failed to open input file.");
}
$n = 0;
$x = 0;
while ($xml->read()) {
if ($xml->nodeType == XMLReader::ELEMENT && $xml->name == $wrapperName) {
while ($xml->read() && $xml->name != $wrapperName) {
if ($xml->nodeType == XMLReader::ELEMENT) {
//$subarray[]=$xml->expand();
$doc = new DOMDocument('1.0', 'UTF-8');
$simplexml = simplexml_import_dom($doc->importNode($xml->expand(), true));
$subarray[]=$simplexml;
}
}
if ($limit == NULL || $x < $limit) {
if ($callback($subarray)) {
$x++;
}
unset($subarray);
}
$n++;
}
}
$xml->close();
}
echo '<pre>';
function func1($s) {
print_r($s);
}
xmlParse('myfile.xml', 'Item', 'func1', 100);
When I print this object by print_r($s); I can't see CDATA in result !.
do you have any idea in order to retrieve CDATA context ?
Treat it like a string
$file = "1.xml";
$xml = simplexml_load_file($file);
foreach($xml->Item->Properties->children() as $properties) {
printf("%s", $properties);
}
Output
<ul><li>sample text</li></ul>
Windows XP/Windows Vista
sample text2
There is allways way to use DOMDocument to open xml files, for example:
$xmlFile = new DOMDocument();
$xmlFile->load(myfile.xml);
echo $xmlFile->getElementsByTagName('Property')->item(0)->nodeValue;

How to replace a special xml tag by using php

I have a xml file such as this:
<?xml version="1.0"?>
<datas>
<books>
<book>
<id>1</id>
<title>PHP Undercover</title>
<author>Wiwit Siswoutomo</author>
</book>`enter code here`
<book>
<id>2</id>
<title>PHP Enterprise</title>
<author>Wiwit Siswoutomo</author>
</book>
</books>
</datas>
and now i wana to replace a special tag in this way:
search in xml file and if it has a PHP Enterprise ,find it and replace it by 'new title'.
What should i do?
TNX
You can parse the document with SimpleXML:
$datas = new SimpleXMLElement("my.xml");
foreach ($datas->books->book as $book) {
if (preg_match('/PHP Enterprise/', $book->title) {
$book->title = "new title";
}
}
$datas->asXML("my.xml");
This script will help you!! Try this :)
<?php
function replace_Special_Str($mystring)
{
//Load file
$filename="./myfile.xml";
if (!file_exists($filename)) { echo "There is not a myfile.xml file in the directory."; exit;}
$xml = simplexml_load_file($filename);
//search and replace particular node by book title
$node = $xml->xpath('/datas/books[title="' . $mystring. '"]');
if(sizeof($node) > 0)
{
$node[0]->title = 'My Title';
}
$xml->asXML('./aucstatus.xml');
}
?>
OR Try This,
<users>
<name>John</name>
<address>My Address</address>
<zipcode>12345</zipcode>
<city>My City</city>
<phone>555 1234-4321</phone>
</users>
PHP FILE
fopen('users.xml');
while ($users->read()) {
switch ($users->nodeType) {
case (XMLReader::ELEMENT):
if ($users->localName == "users") {
$node = $reader->expand();
$dom = new DomDocument();
$n = $dom->importNode($node,true);
$dom->appendChild($n);
$simple_xml = simplexml_import_dom($n);
$id = $simple_xml['id'];
$name = $simple_xml->name;
$address = $simple_xml->address;
// Custom code insert, update, whatever...
}
}
}

Need to show child data on parent id

i'm struggling with Xpath, i have an xml list and i need to get the child data based on the parent id ...
My xml file :
<projecten>
<project id="1">
<titel>Shop 1</titel>
<siteurl>http://test.be</siteurl>
<screenshot>test.jpg</screenshot>
<omschrijving>comment 1</omschrijving>
</project>
<project id="2">
<titel>Shop 2</titel>
<siteurl>http://test2.be</siteurl>
<screenshot>test2.jpg</screenshot>
<omschrijving>comment</omschrijving>
</project>
</projecten>
the code i use to get for example the project 1 data (does not work):
$xmlDoc = new DOMDocument();
$xmlDoc->load(data.xml);
$xpath = new DOMXPath($xmlDoc);
$projectId = '1';
$query = '//projecten/project[#id='.$projectId.']';
$details = $xpath->query($query);
foreach( $details as $detail )
{
echo $detail->titel;
echo $detail->siteurl;
echo $detail->screenshot;
echo $detail->omschrijving;
}
But this does not show anything, if someone can point me out ... thanks
In addition to the solution already given you can also use:
foreach ($xpath->query(sprintf('/projecten/project[#id="%d"]', $id)) as $projectNode) {
echo
$projectNode->getElementsByTagName('titel')->item(0)->nodeValue,
$projectNode->getElementsByTagName('siteurl')->item(0)->nodeValue,
$projectNode->getElementsByTagName('screenshot')->item(0)->nodeValue,
$projectNode->getElementsByTagName('omschrijving')->item(0)->nodeValue;
}
or fetch the DOMText node values directly with Xpath
foreach ($xpath->query(sprintf('/projecten/project[#id="%d"]', $id)) as $projectNode) {
echo
$xpath->evaluate('string(titel)', $projectNode),
$xpath->evaluate('string(siteurl)', $projectNode),
$xpath->evaluate('string(screenshot)', $projectNode),
$xpath->evaluate('string(omschrijving)', $projectNode);
}
or import the node to SimpleXml
foreach ($xpath->query(sprintf('/projecten/project[#id="%d"]', $id)) as $projectNode) {
$detail = simplexml_import_dom($projectNode);
echo
$detail->titel,
$detail->siteurl,
$detail->screenshot,
$detail->omschrijving;
}
or even concatenate all the values directly in the XPath:
$xpath = new DOMXPath($dom);
echo $xpath->evaluate(
sprintf(
'concat(
/projecten/project[#id = %1$d]/titel,
/projecten/project[#id = %1$d]/siteurl,
/projecten/project[#id = %1$d]/screenshot,
/projecten/project[#id = %1$d]/omschrijving
', $id
)
);
Accessing the child nodes as you do:
echo $detail->title;
Is not valid, if you use DOM* functions. This would probably work if you were using SimpleXML.
For DOM* try this:
$dom = new DOMDocument;
$dom->loadXml('<projecten>
<project id="1">
<titel>Shop 1</titel>
<siteurl>http://test.be</siteurl>
<screenshot>test.jpg</screenshot>
<omschrijving>comment 1</omschrijving>
</project>
<project id="2">
<titel>Shop 2</titel>
<siteurl>http://test2.be</siteurl>
<screenshot>test2.jpg</screenshot>
<omschrijving>comment</omschrijving>
</project>
</projecten>
');
$id = 2;
$xpath = new DOMXPath($dom);
foreach ($xpath->query(sprintf('/projecten/project[#id="%s"]', $id)) as $projectNode) {
// repeat this for every needed node
$titleNode = $xpath->query('titel', $projectNode)->item(0);
if ($titleNode instanceof DOMElement) {
echo $titleNode->nodeValue;
}
// or us a loop for all child nodes
foreach ($projectNode->childNodes as $childNode) {
echo $childNode->nodeValue;
}
}

php simple xml how to read multiple nodes with different child node levels

I have an xml file that has different named nodes and multi level child nodes (that are different between each node.) How should I access the data? Will it require many nested for loops?
Here is a sample of the xml code:
<start_info>
<info tabindex="1">
<infonumber>1</infonumber>
<trees>green</trees>
</info>
</start_info>
<people>
<pe>
<people_ages>
<range number="1">
<age value="1">1</age>
<age value="2">2</age>
</range>
</people_ages>
</pe>
</people>
Here is my code so far:
$xml = simplexml_load_file("file.xml");
echo $xml->getName() . "start_info";
foreach($xml->children() as $child)
{
echo $child->getName() . ": " . $child . "<br />";
}
Here is some example code that I hope can point you in the right direction. Essentially, it is walking the DOMDocument echoing the element name and values. Note that the whitespace between the elements is significant, so for the purposes of the demo, the XML is compacted. You may find a similar issue loading from a file, so if you are not getting the expected output you might need to strip whitespace nodes.
You could replace the //root/* with a different XPath for example //people if you only wanted the <people> elements.
<?php
$xml = <<<XML
<root><start_info><info tabindex="1"><infonumber>1</infonumber><trees>green</trees></info></start_info>
<people><pe><people_ages><range number="1"><age value="1">1</age><age value="2">2</age></range></people_ages></pe></people>
</root>
XML;
$dom = new DOMDocument();
$dom->recover = true;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$nodelist = $xpath->query('//root/*');
foreach ($nodelist as $node) {
echo "\n$node->tagName";
getData($node);
}
function getData($node) {
foreach ($node->childNodes as $child) {
if ($child->nodeType == XML_ELEMENT_NODE) {
echo ($child->tagName === '' ? '' : "\n").$child->tagName;
}
if ($child->nodeType == XML_TEXT_NODE) {
echo '->'.$child->nodeValue;
}
if ($child->hasChildNodes()) {
getData($child); // recursive call
}
}
}
?>
check this
$xml_file = 'file.xml';
$xmlobj = simplexml_load_file($xml_file);
echo $xmlobj->getName() . 'start_info<br />';
foreach($xmlobj->children() as $childs) {
echo $childs->getName(). ': '. '<br />';
if($childs->count()>1) {
foreach($childs as $child) {
echo $child->getName(). ': '. $child. '<br />';
}
}
}

Categories