phpsimplexmlopml

Sort OPML with simplexml


I've read through a bunch of posts here but I still can't figure out how to sort the data I am reading from an OPML file using simplexml functions. I realize this is kind of a duplicate, but I'm apparently too slow to get this right using abstracted examples.

I have a pretty standard OPML file with contents like:

<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
<!-- OPML generated by Fever -->
<head><title>Fever // Coffee</title></head>
<body>    
    <outline type="rss" text="I Love Coffee" title="I Love Coffee" xmlUrl="http://en.ilovecoffee.jp/posts/rss" htmlUrl="http://www.ilovecoffee.jp"/>
    <outline type="rss" text="Dear Coffee I Love You" title="Dear Coffee I Love You" xmlUrl="http://feeds.feedburner.com/DearCoffeeILoveYou" htmlUrl="http://www.dearcoffeeiloveyou.com"/>
</body>
</opml>

I am generating a Markdown list using the simplest possible code:

foreach ($opml->body->outline as $feed) {
    echo '* [' . $feed['title'] . '](' . $feed[htmlUrl] . ')' . "\n";
}

I simply want to sort the list by the "title" attribute, but I can't get my head around how to do so.

It's my understanding I need to convert the xml object into an array, which I can do with:

$json = json_encode($opml);
$xml_array = json_decode($json,TRUE);

But I can't seem to get things right to sort that array by the "title"


Solution

  • Rather than trying to blindly convert the whole XML document into an array (which will rarely be a particularly useful array), you should build an array with the items you want:

    $feed_list = array();
    foreach ($opml->body->outline as $feed) {
         $feed_list[] = $feed;
    }
    

    You can then use usort() to sort the items by whatever condition you want, e.g. using strcasecmp() to give a case-insensitive alphanumeric order:

    usort($feed_list, function($a, $b) {
         // $a and $b are SimpleXMLElement objects which are being sorted
         return strcasecmp( (string)$a['title'], (string)$b['title'] );
    });
    

    You now have a sorted array to pass to your existing display logic:

    foreach ( $feed_list as $feed ) {
        echo '* [' . $feed['title'] . '](' . $feed['htmlUrl'] . ')' . "\n";
    }