1

I use the following PHP to remove items from an XML I own if they are over 8 days old. It had worked fine once before but now gives me the error message

Call to a member function removeChild() on a non-object in /Users//DateTest-3.php on line 40

Line 40 is

$node->parentNode->removeChild($node); 

Any ideas why this is throwing the error?

<?php $rss = new DOMDocument(); $url = 'http://URL.com/Test.xml'; $rss->load($url); $feed = array(); foreach ($rss->getElementsByTagName('item') as $node) { $item = array ( 'title' => $node->getElementsByTagName('title')->item(0)->nodeValue, 'desc' => $node->getElementsByTagName('description')->item(0)->nodeValue, 'link' => $node->getElementsByTagName('link')->item(0)->nodeValue, 'date' => $node->getElementsByTagName('date')->item(0)->nodeValue, ); array_push($feed, $item); } $limit = 50; for ($i = 0; $i < count($feed); $i++) { date_default_timezone_set('America/Los_Angeles'); $newDate = strtotime("-8 day"); $date = strtotime($feed[$i]['date']); if ($date > $newDate) { echo "Don't delete"; } else { echo "Delete"; $node->parentNode->removeChild($node); } } $rss->save("Test.xml") ?> 
6
  • I'm puzzled by this: why would you explicitly remove older entry from a feed? Commented Aug 5, 2014 at 14:00
  • @JulienGenestoux The app that accesses this XML already only shows entries with a date of at most 7 days old, but still parses all entries. Easily removing all entries that won't be displayed will keep the file size of the XML down, making it faster to parse and use less data as time goes on and the entries grow. Commented Aug 5, 2014 at 15:32
  • Then why don't you just limit the size of the feed to say 10 entries or 20? Commented Aug 7, 2014 at 8:47
  • Because this is an XML that any person using the app can add to. How about instead of offering me different things that have nothing to do with my question, y'all focus on answering the question. If I wanted to know how to limit an XML, I would have asked that. @JulienGenestoux Commented Aug 7, 2014 at 11:03
  • Do you want a new $feeds array containing the items or do you want to delete the (older) nodes in the DomDocument $rss object? Do you want an item limit or just the date filter or both? Commented Aug 8, 2014 at 16:37

3 Answers 3

1
+200
  • In RSS 1.0 there is no 'date' on items. But 'dc:date' comes into play. http://web.resource.org/rss/1.0/spec#s5.5

  • In RSS 2.0 there is no 'date', but 'pubdate' on items. http://cyber.law.harvard.edu/rss/rss.html#hrelementsOfLtitemgt

  • Decide, if you want to look for 'date', 'dc:date' and 'pubDate'. The following code works with pubDate.

  • $limit = 50; was unused

  • Removing nodes from a nodeList under iteration will not work. It's an old hat! See comments here: http://php.net/manual/de/domnode.removechild.php The solution is to use a queue for marking the bad nodes and remove them afterwards.

  • I have taken the liberty to mangle the code a bit. I left the debug stuff intentionally active. Mainly for date comparison stuff and reduced list display. The code is commented.

  • Please adjust the feed URL and the "-x days" in the condition. I had to work with a public rss feed to test things.

--

<?php date_default_timezone_set('America/Los_Angeles'); $feed = array(); // target array for filtered items $nodesToRemoveQueue = array(); // stores all nodes to remove $rss = new DOMDocument(); $url = 'http://rss.nytimes.com/services/xml/rss/nyt/Space.xml'; $rss->load($url); $nodeList = $rss->getElementsByTagName('item'); foreach ($nodeList as $node) { $pubDate = $node->getElementsByTagName('pubDate')->item(0)->nodeValue; // if date in the xml feed is older then desired number of days, remove node // and proceed with iteration. (do not transfer the data into the $feeds array.) if(isDateOlderThenDays($pubDate, '-5 days')) { echo 'Removed ' . $pubDate . '<br>'; // $node->parentNode->removeChild($node); this won't work!! $nodesToRemoveQueue[] = $node; // put node in queue, remove later continue; } echo 'Kept ' . $pubDate . '<br>'; // build item for $feed array, then add item to $feed array $item = array ( 'title' => $node->getElementsByTagName('title')->item(0)->nodeValue, 'desc' => $node->getElementsByTagName('description')->item(0)->nodeValue, 'link' => $node->getElementsByTagName('link')->item(0)->nodeValue, 'date' => $pubDate, ); $feed[] = $item; } // helper to compare dates - function isDateOlderThenDays($date, $days) { // when pubdate($date) is lower(older) then $days, return true, else false. return (strtotime($date) < strtotime($days)) ? true : false; } // feed array contains all the not "outdated" items var_dump($feed); // finally: remove the "outdated" nodes foreach($nodesToRemoveQueue as $node){ $node->parentNode->removeChild($node); } // nodelist reduction check. this should only displays the dates kept $nodeList = $rss->getElementsByTagName('item'); foreach ($nodeList as $node) { echo $node->getElementsByTagName('pubDate')->item(0)->nodeValue . '<br>'; } // write reduced RSS XML to file $rss->save(__DIR__.'/Test.xml'); 

Another way of saving the XML is:

$xmlString = $rss->saveXML(); file_put_contents(__DIR__.'/Test.xml', $xmlString); 
Sign up to request clarification or add additional context in comments.

3 Comments

I cannot see where it saved anything online, and also, I get Removed <br>Removed <br>Removed <br>Removed <br>Removed <br>Removed <br>Removed <br>Removed <br>Removed <br>Removed <br>Removed <br>Removed <br>array(0) in the notes. Currently there are 12 entries and only 9 should be removed, while other 3 are left.
The file will be saved in the current dir (DIR) as Test.xml. But array(0)indicates, that no "young" items are found. Did you adjust the "-x days" value? A possible error source is the date format in your own xml items. Would it be possible to provide the data of this xml feed? Then i can adjust the script to work with it...
When only Removed <br>" is printed, then $pubdate is not set. How is the date tag called in your XML? Adjust $node->getElementsByTagName('pubDate') replace pubDate with date or dc:date.. i don't know your XML..
0

Is it on purpose that you only work on the last node after the

foreach ($rss->getElementsByTagName('item') as $node) 

Because $node is kept with the last $rss->getElementsByTagName('item') assignment. Or is code missing?

5 Comments

Ok, I really don't understand your question at all. No code is missing
Do you purposely only check the LAST $node of all nodes in $rss->getElementsByTagName('item') ?
I think I made it fairly clear what I am doing. I want to remove all items within RSS that have a pubDate older than 8 days. My code reflects that. BTW, answers are meant for answers. You should have put your first statement as a comment and not an answer.
I asked because your code is wrong if that's what you want to accomplish. I wasn't allowed to comment. At which point do you go through all items to delete the old ones? You only access $node from the last run of the first foreach. Maybe you delete it and try to access it in the next loop iteration. That might trigger your error.
So you know that my code won't accomplish what I want it to, implying you know how to do what I want to accomplish. Care to fill me in?
0

In your second foreach, reassign $node on every iteration. E.g. $node = $feed[$i].

8 Comments

Still get error Call to a member function removeChild() on a non-object
Probably because $feed[$i] is still an array. Do you understand that in the second foreach you access the same $node variable on every iteration? If you use $feed[$i] , make $feed an array of nodes.
My issue is that this code worked perfectly a couple of weeks ago and now it isn't. Just show me a full PHP code where this would work for what I want to accomplish.
It works if the delete is only called once. If the if statement is only true once. Then you only delete the last node. In the second loop. The for ($i.... You need to access all $nodes. In the FIRST foreach, delete the $node using parent->removeChild(). That should work as you do not change the foreach variable. If it IS a problem: assign by reference.
I mentioned this already. Putting the removeChild in the first foreach also gives me the exact same error.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.