1

I am trying to display the posts of some RSS Feeds and I came up with a question/problem I have, when I have two same feeds I am trying to show not all the posts but the unique. What I was using is this, that shows me all the posts twice (this is logical)

 <?php

$feeds = array(
'feed.xml', 'feed.xml'
);


// Get all feed entries
$entries = array();
foreach ($feeds as $feed) {

    $xml = simplexml_load_file($feed);
    $entries = array_merge($entries, $xml->xpath('/rss/channel//item'));

}


// Sort feed entries by pubDate (ascending)
usort($entries, 'mysort');


function mysort($x, $y) {
    return strtotime($y->pubDate) - strtotime($x->pubDate);
}


foreach ($entries as $entry) {
echo $entry->title; 
echo "<br>";
} 

?>

but when I changed that line to

$entries = array_unique(array_merge($entries, $xml->xpath('/rss/channel//item')));

I get only one post shown.

How can I correctly show the posts only once? Thank you.

EnexoOnoma
  • 8,454
  • 18
  • 94
  • 179

2 Answers2

0

From the documentation of array_unique

Note: Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same. The first element will be used.

In this case, the objects you're getting out of the XPath query translate to string form like "SimpleXML object" (not exactly like that, but the exact representation is not important). According to the above rules, then, every element looks exactly the same to array_unique.

Unfortunately, there's no way to make array_unique behave the way you want, so you will need to fake it yourself:

$feeds = array(
'myfeed.xml', 'myfeed.xml'
);


// Get all feed entries
$entries = array();
foreach ($feeds as $feed) {

    $xml = simplexml_load_file($feed);
    $tmp = $xml->xpath('/rss/channel//item');

    foreach ($tmp as $item) {
        if(!in_array($tmp, $entries)) {
            $entries[] = $tmp;
        }
    }

}

I'm not sure if this will work, as it depends on being able to compare objects, and also I don't know that identical nodes from separate XML documents would compare the same anyway. But try it, and let me know. I can whip something else up if this doesn't work.

Mike Caron
  • 14,351
  • 4
  • 49
  • 77
  • Hi, I tried it but I didnt get any results. I have updated my question with full code. – EnexoOnoma Jul 12 '11 at 11:51
  • If you replace the last foreach with this: $feedTitles = array(); foreach ($entries as $entry) { if( empty($feedTitles) || !in_array( $entry->title, $feedTitles ) ) { $feedTitles[] = (string)$entry->title; echo $entry->title; echo "
    "; } } you should get just the unique results
    – James Bell Jul 12 '11 at 12:41
0

Update:

function mysort($x, $y) {
    return strtotime($y->pubDate) - strtotime($x->pubDate);
}

$feeds = array( 'http://feeds.bbci.co.uk/news/world/rss.xml',
                'http://feeds.bbci.co.uk/news/world/rss.xml'
              );

// Get all feed entries
$entries = array();
foreach ($feeds as $feed) {
    $xml = simplexml_load_file($feed);
    $entries = array_merge($entries, $xml->xpath('/rss/channel//item'));
}

$uniqueEntries = array();
foreach ($entries as $entry) {
    $uniqueEntries[(string)$entry->title] = $entry;
}

// Sort feed entries by pubDate (ascending)
usort($entries, 'mysort');

foreach ($uniqueEntries as $entry) {
    echo $entry->title; 
    echo "<br>";
} 
James Bell
  • 604
  • 1
  • 7
  • 18
  • Hi, I have added the function below the mysort function and the array_filter below array_merge. I get this Warning: Missing argument 2 for feed_unique() – EnexoOnoma Jul 12 '11 at 12:23
  • And below all that warnings I still get the same double titles – EnexoOnoma Jul 12 '11 at 12:37
  • Ignore this sorry misread the documentation. See my comment on Mikes answer – James Bell Jul 12 '11 at 12:42
  • Great ! Working great. One more question though. If this "check" is made before the mysort function, will I gain something in speed or performance ? I mean to prevent sorting same things and then remove them, but to remove them first and sort them next – EnexoOnoma Jul 12 '11 at 12:51
  • Possibly, but the difference will be very small with such as small number of items. – James Bell Jul 12 '11 at 13:27
  • Instead of doing the in_array check every time, just build the array using the title as key, so in case of a duplicate it just gets silently overwritten. – Matteo Riva Jul 12 '11 at 13:32
  • @Matteo can you please post an answer with your example please? – EnexoOnoma Jul 12 '11 at 16:36
  • Nice idea @Matteo I have updated my answer to use the method you suggested. – James Bell Jul 12 '11 at 21:04