Tip: Paging Atom: Create a multi-section Atom collection or feed

Let users page through your multiple page Atom feed using "next" and "previous" links

As feeds move beyond merely announcing new content on somebody's blog and into organizing data, you can easily find situations where you don't want your feed to include all of the available data. This tip shows you how to create an Atom feed that lets users page through it using "next" and "previous" links or buttons. While the tip shows you how to implement this functionality using PHP, the concepts are the same for any programming language.

Share:

Nicholas Chase (ibmquestions@nicholaschase.com), Writer, Freelance

Nicholas Chase has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the Chief Technology Officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sams).



10 April 2007

The feed in question

As an example, look at the Syfy Portal newsfeed, which has the potential to contain over 3000 archived news stories (see Resources for a link). Virtually nobody wants their feed reader to download all of these messages, especially since many of them are several years old. To solve that problem, the Atom specification allows for the necessity to send only a portion of the available information.

In this case, the spec mandates the addition of several link elements that help lead the application along. Listing 1 shows an example.

Listing 1. The sample feed
<?xml version="1.0" encoding="us-ascii"?>
<feed xmlns="http://www.w3.org/2005/Atom">

<title>SyFy Portal Headlines</title>
<link href="http://www.syfyportal.com"/>
<updated>2007-01-23T10:34:22Z</updated><id>http://www.syfyportal.com/a
tomfeed.php</id><subtitle>Your Premier Source For Science Fiction and 
Fantasy News Since 1998</subtitle>
<link rel="alternate" type="text/html" hreflang="en" 
href="http://www.syfyportal.com/"/>
<link rel="self" type="application/atom+xml" 
                        href="http://www.syfyportal.com/atomFeed.php"/>
<link rel="first" href="http://www.syfyportal.com/atomFeed.php"/>
<link rel="next" href="http://www.syfyportal.com/atomFeed.php?page=2"/>
<link rel="last" 
              href="http://www.syfyportal.com/atomFeed.php?page=147"/>
<entry>
<id>http://www.syfyportal.com/news423172.html</id><title>'Heroes' 
Holds Its Own Against '24'</title>
<link rel="alternate" type="text/html" 
href="http://www.syfyportal.com/news423172.html"/>
<author><name>Michael 
Hinman</name></author><updated>2007-01-23T10:03:08Z</updated>
<content>Who will win in the battle between NBC's "Heroes" and Fox's "24"? In 
terms of overnight ratings, it's actually a virtual tie."Heroes" slid a bit in the 
ratings to earn an 8.5 rating/12 share according ...</content>
</entry>

<entry>
...

In this case, you're looking at the first page, so this page specifies four pieces of information. The first is the URL for the actual page. The second is the URL for the first page in the series, which of course is the same as the current URL.

The next two, however, are where some of the power is, specifying the "next" and "last" pages respectively. This feed contains 20 items, so the first 20 items are on this page, items 21 through 40 are on page 2, and so on. All pages but the first also have an additional "previous" link (see Listing 2).

Listing 2. Page 2
...
<link rel="self" type="application/atom+xml" 
             href="http://www.syfyportal.com/atomFeed.php?page=2"/>
<link rel="first" href="http://www.syfyportal.com/atomFeed.php"/>
<link rel="previous" 
             href="http://www.syfyportal.com/atomFeed.php?page=1"/>
<link rel="next" href="http://www.syfyportal.com/atomFeed.php?page=3"/>
<link rel="last" href="http://www.syfyportal.com/atomFeed.php?page=147"/>
<entry>
...

Creating this functionality in PHP doesn't require any special skills or modules, just a methodical approach.


Creating the links

Consider this example, the PHP that generates the Atom feed for the Syfy Portal site. Generating the basic feed is straightforward (see Listing 3).

Listing 3: The basic feed
<?php
    include("functions/engine.php");

    header("Content-Type: text/xml");

    $result = query("select * from content limit 20");
    if (!result) {
      echo "An error occured";
    } else {
        echo "<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n\n";
        echo "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n\n";
        echo "<title>SyFy Portal Headlines</title>\n";
        echo "<link href=\"http://www.syfyportal.com\"/>\n";
        echo "<updated>".date('Y-m-d\TH:i:s\Z')."</updated>";
        echo "<id>http://www.syfyportal.com/atomfeed.php</id>";
        echo "<subtitle>Your Premier Source For Science Fiction and 
Fantasy News Since 1998</subtitle>\n";

        echo "<link rel=\"alternate\" type=\"text/html\" 
          hreflang=\"en\" href=\"http://www.syfyportal.com/\"/>\n";
        echo "<link rel=\"self\" type=\"application/atom+xml\" 
              href=\"http://www.syfyportal.com/atomFeed.php\"/>\n";

        for ($i=0; $i < count($result); $i++){

            $author = query("select * from authors where ".
                               "id='".$result[$i]['authorid']."'");

            $item = $result[$i];
            echo "<entry>\n";

            echo "<id>http://www.syfyportal.com/news42".
                                             $item['id'].".html</id>";
            echo "<title>".
      stripslashes(htmlspecialchars($item['headline']))."</title>\n";
            echo "<link rel=\"alternate\" type=\"text/html\" ". 
"href=\"http://www.syfyportal.com/news42".$item['id'].".html\"/>\n";
            $hometext = strip_tags($item['body']);

            if (strlen($hometext)>101) {
                   $desctext = htmlspecialchars(substr($hometext, 0, 
                                strpos($hometext, ' ', 200)))." ...";
            } else {
                   $desctext = htmlspecialchars($hometext);
            }

            echo 
"<author><name>".$author['name']."</name></author>";
            echo "<updated>".date('Y-m-d\TH:i:s\Z', 
                                  $result[$i]['added'])."</updated>";
            echo "<content>".stripslashes($desctext)."</content>\n";
            echo "</entry>\n\n";
        }
        echo "</feed>";
    }
?>

Starting at the top, the site uses a number of internal routines, including one that wraps database transactions. Those are not the topic of this article, of course, but the important part is that the query() function returns an array of rows, each of which is itself represented as an array. The page loops through each of those items, creating an Atom feed.

To add paging capabilities, start by analyzing the available data (see Listing 4).

Listing 4. Adding paging
<?php
    include("functions/engine.php");

    header("Content-Type: text/xml");

    $result = query("select * from content");
    if (!result) {
      echo "An error occured";
    } else {

        $numberOfItems = count($result);

        $numberOfPages = intval($numberOfItems / 20);
        if (isset($_GET['page'])){
            $thisPage = $_GET['page'];
        } else {
             $thisPage = 1;
        }
        $offset = ($thisPage - 1) * 20;


        echo "<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n\n";
        echo "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n\n";
        echo "<title>SyFy Portal Headlines</title>\n";
        echo "<link href=\"http://www.syfyportal.com\"/>\n";
        echo "<updated>".date('Y-m-d\TH:i:s\Z')."</updated>";
        echo "<id>http://www.syfyportal.com/atomfeed.php</id>";
        echo "<subtitle>Your Premier Source For Science Fiction and Fantasy News 
Since 1998</subtitle>\n";
	
        echo "<link rel=\"alternate\" type=\"text/html\"". 
" hreflang=\"en\" href=\"http://www.syfyportal.com/\"/>\n";

        echo "<link rel=\"self\" type=\"application/atom+xml\"". 
" href=\"http://www.syfyportal.com/atomFeed.php\"/>\n";

        echo "<link rel=\"first\"". 
" href=\"http://www.syfyportal.com/atomFeed.php\" />\n";

        if ($thisPage > 1){
           echo "<link rel=\"previous\" ". 
"href=\"http://www.syfyportal.com/atomFeed.php?page=".($thisPage-1).
"\" />\n";
        }

        if ($thisPage < $numberOfPages){
           echo "<link rel=\"next\" ". 
"href=\"http://www.syfyportal.com/atomFeed.php?page=".($thisPage+1).
"\" />\n";
        }

        echo "<link rel=\"last\" ". 
"href=\"http://www.syfyportal.com/atomFeed.php?page=".$numberOfPages.
"\" />\n";

        for ($i=$offset; ($i < ($offset + 20) and $i < count($result)); 
                         $i++){

            $author = query("select * from authors where 
id='".$result[$i]['authorid']."'");

            $item = $result[$i];
            echo "<entry>\n";

...

Previously, you let the SQL statement limit the number of records as a way to select a maximum of 20. In this case, you want to select all of the data that's available. From there, you can determine the maximum number of pages.

Next, determine what page you currently need to display and use that information to determine the offset, or number of records to skip.

Now it's time to add the actual links. The "first" and "last" link elements appear on all pages, but the "previous" and "next" links appear on all but the first and last pages, respectively.

Finally, adjust the loop so that it displays only the appropriate records, skipping those on previous pages and still displaying only 20. (In this case, 20 is an entirely arbitrary number.)

The result is an Atom feed that enables feedreaders or other applications to request only the records they want to see.


Summary

The Atom Publishing Protocol takes into account the fact that you don't always want to send all of your data to a requester, and provides a way to make this capability feasible. Use the first, next, previous, and last link elements to guide your users through your data in manageable chunks.


Download

DescriptionNameSize
Atom paging samplesx-tipatom2-source.zip2KB

Resources

Learn

Get products and technologies

  • The Blogapps server: Download the server in this collection of useful RSS and Atom utilities and examples.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=205661
ArticleTitle=Tip: Paging Atom: Create a multi-section Atom collection or feed
publish-date=04102007