Skip to main content

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

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).

Summary:  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.

View more content in this series

Date:  10 Apr 2007
Level:  Intermediate
Activity:  2478 views

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

DescriptionNameSizeDownload method
Atom paging samplesx-tipatom2-source.zip2KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

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

Discuss

About the author

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).

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

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
author1-email=ibmquestions@nicholaschase.com
author1-email-cc=dwxed@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers