1

I want to remove tasks that are older than today, but I can't quite figure out how to remove elements from XML file yet.

$xml_file = simplexml_load_file('file.xml');    
foreach ($xml_file->task as $aTask) {
        if ($aTask->date < $today) {
            //$xml_file->removeChild($aTask); //doesnt work
        }
}

Here is my XML file below:

<?xml version="1.0"?>
<calender>
<task><date>00/00/0000</date><title>My Birthday</title><description>Today is my birthday!</description></task><task><date>04/01/2013</date><title>ghh</title><description>jfhjhj</description></task><task><date>04/01/2013</date><title>egfwe</title><description>wefwef</description></task><task><date>04/01/2013</date><title>cvbhm</title><description>dhmdh</description></task><task><date>04/02/2013</date><title>gg</title><description>gg</description></task><task><date>04/02/2013</date><title>test</title><description>test</description></task><task><date>04/03/2013</date><title>ggg</title><description>ggg</description></task><task><date>04/03/2013</date><title>ssdv</title><description>ssdvs</description></task><task><date>04/03/2013</date><title>test</title><description>testtest</description></task><task><date>04/04/2013</date><title>tttt</title><description>ttttttttt</description></task><task><date>04/05/2013</date><title>qewerbqwer</title><description>bwerbwerbwebr</description></task><task><date>04/07/2013</date><title>fgj</title><description>fghj f</description></task><task><date>04/08/2013</date><title>test</title><description>swdefswde</description></task><task><date>04/09/2013</date><title>hj,h</title><description>hj,gh</description></task><task><date>04/16/2013</date><title>dfbd</title><description>dfbdfb</description></task><task><date>04/17/2013</date><title>dfb</title><description>dfb</description></task>
</calender>

can someone please help me?

1
  • Can you show what $aTask->date and $today contain? Commented Apr 9, 2013 at 16:10

3 Answers 3

2

Using simplexml: --> live demo @ http://codepad.viper-7.com/Jl16Oh

$xml = simplexml_load_string($x); // XML is in $x

$today = date("m/d/Y");
$max = $xml->task->count()-1;

for ($i = $max; $i >=0; $i--) {

   if ($xml->task[$i]->date < $today) unset($xml->task[$i]);

}
Sign up to request clarification or add additional context in comments.

2 Comments

Explanation: you loop backwards so index remains the same after deleting nodes. This is answer is fine.
@michi, I have to say it is very clean. +1!
0

It's actually very tricky. You have to unset() the appropriate variable, but it needs to be a reference to the parent node (i.e., unset($aTask) will not work). Additionally, if you do foreach ($xml_file->task as $index => $aTask) to keep track of the child position, you'll get task in every iteration!

You need some ugly code like this:

$index = 0;
$remove = array();
foreach ($xml_file->task as $aTask) {
    if ($aTask->date < $today) {
        $remove[] = $index;
    }
    $index++;
}

foreach($remove as $index){
    unset($xml_file->task[0]);
}

P.S. As already noted, your date handling routines do not work.

Edit: I've actually tried my own code and it works, so downvoter should explain himself.

Comments

0

I think it is problematic to compare dates as if it was an implemented type of datas.

With your algorithm, you are comparing strings, which is not what you want. You can use preg_match to get day, month and year, then mktime to compare timestamps:

http://php.net/manual/en/function.preg-match.php

http://php.net/manual/en/function.mktime.php

EDIT: You can even do that without preg_match, that is time consuming. Here is an example casting your object into an array (you have to cast one way or another, you can also select to use DOM, see: Remove a child with a specific attribute, in SimpleXML for PHP)

<?
$xml_file = (array)simplexml_load_file("file.xml")or die('Error reading XML file');
print_r($xml_file);

$today=array(
    'day'   => intval(date('d')),
    'month' => intval(date('m')),
    'year'  => intval(date('Y')),
    );
//print_r($today);

foreach($xml_file['task'] as $key=>$aTask) {
        $date  = (string)$aTask->date;
        $month = intval($date[0].$date[1]);
        $day   = intval($date[3].$date[4]);
        $year  = intval($date[6].$date[7].$date[8].$date[9]);
        //echo $aTask->title.': '.$month.'/'.$day.'/'.$year."\n";
        if ( ($year < $today['year']) || ($year==$today['year'] && $month < $today['month']) || ($year==$today['year'] && $month == $today['month'] && $day < $today['day']) ) {
            //echo 'Deleting '.$aTask->title."\n";
            unset($xml_file['task'][$key]);
        }
}

// Inspired from: https://stackoverflow.com/questions/1397036/how-to-convert-array-to-simplexml 
$xml  = '<?xml version="1.0"?>'."\n".'<calendar>';
function addChild($item) { global $xml; $xml.=$item->asXML(); }
array_walk_recursive($xml_file['task'], 'addChild');
$xml .= '</calendar>';
//echo $xml;
file_put_contents('out.xml', $xml);
?>

4 Comments

I've tried your code but couldn't make it past $xml_file['task'], which triggers Warning: Invalid argument supplied for foreach().
Did you try the exact same code, including the cast to an array? Because it worked for me. Maybe you have an old version of PHP then?
Oh, sorry, I overlooked the (array) bit. Then, I think you should clarify how to get XML code back since it isn't immediately obvious.
@ÁlvaroG.Vicario: done, but obviously Michi solution will be by far more quick than mine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.