4

I just can remove an item from a simpleXML element with:

unset($this->simpleXML->channel->item[0]);

but I can't with the a for:

    $items = $this->simpleXML->xpath('/rss/channel/item');
    for($i = count($items); $i > $itemsNumber; $i--) {
        unset($items[$i - 1]);
    }

some items are removed from $items (Netbeans Debug can confirm that) but when I get the path again (/rss/channel/item) nothing was deleted.

What's wrong?

Xavier Barbosa
  • 3,919
  • 1
  • 20
  • 18
thom
  • 41
  • 1
  • 2

3 Answers3

7

SimpleXML does not handle node deletion, you need to use DOMNode for this. Happily, when you import your nodes into DOMNode, the instances point to the same tree.

So, you can do that :

<?php

$items = $this->simpleXML->xpath('/rss/channel/item');
foreach ($items as $item) {
    $node = dom_import_simplexml($item);
    $node->parentNode->removeChild($node);
}
Josh Davis
  • 28,400
  • 5
  • 52
  • 67
Xavier Barbosa
  • 3,919
  • 1
  • 20
  • 18
  • SimpleXML does handle deletion as mentionned first in the question, but not if you don't have a hold of the node's parent and it's not very practical, which is why I'd recommend using DOM for that kind of manipulation. – Josh Davis Jan 19 '11 at 08:51
3

You're currently only, as you know, unsetting the item from the array.

To get the magical unsetting to work on the SimpleXMLElement, you have to either do as Xavier Barbosa suggested or give PHP a little nudge into firing off the correct unsetting behaviour.

The only change in the code snippet below is the additions of [0]. Heavy emphasis on the word magical.

$items = $this->simpleXML->xpath('/rss/channel/item');
for($i = count($items); $i > $itemsNumber; $i--) {
    unset($items[$i - 1][0]);
}

With that said, I would recommend (as Xavier and Josh have) moving into DOM-land for manipulating the document.

Community
  • 1
  • 1
salathe
  • 51,324
  • 12
  • 104
  • 132
0

Well I was racking my brain trying to figure out how to delete the last child from an xml document. Then I insert a new element at the top. This way there is always a set amount of items in my rss feed. I could not get the xpath stuff to work. That could be because of the free server I am using but anyways. This is what I did. My xml document is an rss feed so I have 6 elements before the items start. ie. title,description under the channel. $file = 'newrss.xml';//get file

$fp = fopen($file, "rb") or die("cannot open file");//open the file
$str = fread($fp, filesize($file));//read the file

$xml = new DOMDocument();//new xml DOMDocument
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$xml->loadXML($str) or die("Error");//Load Document
// get document element
$root   = $xml->documentElement;
$fnode  = $root->firstChild;
$ori    = $fnode->childNodes->item(6);//The 6th item starts the item nodes
//Get the number of items in my xml.
$nodeLength = $fnode->getElementsByTagName('item')->length;//count nodes
$itemNum=$nodeLength+5;//I added 5 so it starts from the first item
$lNode  = $fnode->childNodes->item($itemNum);//Get the last child node
$fnode->removeChild($lNode);//finally remove that node.

I know this is not pretty but it works good. It took me forever to figure this out so I hope it will help someone else since I see this question a lot. If you are not interested in adding your new item to the top of the rss list then you could skip the $ori variable. Furthermore if you do leave out the $ori variable you will have to adjust the $itemNum so you remove the correct item.

  • I forgot to mention about that at the end of this code you will have to save the xml document again for changes to happen. $xml->save('newrss.xml')or die("Error") ; – jaybyrd Aug 07 '15 at 12:31