Creating an RSS Feed






Creating an RSS Feed

Based on the examples and information above, you should be able to create RSS documents using the tools explored earlier in this book. DOM, JDOM, dom4j, and StAX can all be used to create XML documents and thus can be used to create RSS documents. You don't even need to use an XML library. For example, the Java blogging application blojsom (available from http://www.blojsom.com) generates its RSS feeds using the Velocity scripting language. If you find yourself creating multiple different RSS feeds, you may find it helpful to use an RSS library that contains an RSS data model so that you deal with classes named Channel and Item instead of Document and Element. Because feeds are represented in this data model, an RSS library can be used to output or input feeds targeting a variety of RSS formats with a consistent data model. One open source RSS library is ROME: RSS and Atom Utilities.

Introducing ROME

ROME is an RSS library supporting the full range of RSS and Atom formats:

  • RSS 0.9

  • RSS 0.91 Netscape

  • RSS 0.91 Userland

  • RSS 0.92

  • RSS 0.93

  • RSS 0.94

  • RSS 1.0

  • RSS 2.0

  • Atom 0.3

  • Atom 1.0

ROME supports parsing and generating feeds as well as converting between one format and another. ROME is downloadable from its project web site, https://rome.dev.java.net/. As of the time of writing, the current version of ROME is 0.8 beta. ROME uses the JDOM library we examined in Chapter 9, and you will need to include the JDOM JAR file, along with the ROME JAR file, in your classpath.

ROME data models

ROME includes three different data models: an RSS data model in the package com.sun.syndication.feed.rss, an Atom data model in the package com.sun.syndication.feed.atom, and a format-independent data model in the package com.sun.syndication.feed.synd. Figure contains a UML diagram of the interfaces in the format-independent model.

ROME format-independent data model


For each of these interfaces, ROME includes an implementation class: SyndFeedImpl for the SyndFeed interface, SyndEntryImpl for the SyndEntry interface, and so on. As you can see, this format-independent model is based on a superset of features from RSS and Atom. Likewise, the RSS data model, diagrammed in Figure, contains the superset of the features from all the various RSS versions; the Atom data model, diagrammed in Figure, supports all the features in both released versions of the Atom specification: 0.3 and 1.0.

ROME RSS data model


ROME Atom data model


ROME refers to feeds in one of the format-specific models as wire feeds and both the Channel and Feed objects extend the abstract class com.sun.syndication.feed.WireFeed. To convert from an instance of the format-independent SyndFeed interface to a specific wire feed format, use the SyndFeed interface methods named createWireFeed( ). A SyndFeed object can have a default feed type, set with the setFeedType( ) method, in which case the no-argument version of createWireFeed( ) can be used. There is also an overloaded createWireFeed( ) method that accepts a String parameter to determine the format of the created wire feed. To get a list of the supported values for this parameter, call the getSupportedFeedTypes( ) method. These type strings are supported by default in ROME:

  • rss_0.9

  • rss_0.91N

  • rss_0.91U

  • rss_0.92

  • rss_0.93

  • rss_0.94

  • rss_1.0

  • rss_2.0

  • atom_0.3

  • atom_1.0

To do the reversecreate a SyndFeed object from a wire feedyou can construct a new SyndFeedImpl object by passing a Channel (from the RSS model) or a Feed (from the Atom model) to the SyndFeedImpl constructor.

Outputting a ROME feed

The com.sun.syndication.io package contains the classes SyndFeedOutput and WireFeedOutput to handle outputting ROME feeds. Both SyndFeedOutput and WireFeedOutput have methods to output feeds to:

  • A java.lang.String object

  • A java.io.File object

  • A java.io.Writer object

  • An org.w3c.dom.Document object

  • An org.jdom.Document object

SyndFeedOutput can be used only if the SyndFeed object's setFeedType( ) method has been called to set the default wire feed format. Otherwise, you'll need to convert your SyndFeed object to a WireFeed object and then use WireFeedOutput.

Creating a Feed with ROME

Figure contains a class that generates a generic example feed as a SyndFeed object and then outputs it in the format specified on the command line.

Outputting an example feed with ROME

package javaxml3;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Collections;
import java.util.List;

import com.sun.syndication.feed.WireFeed;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.feed.synd.SyndPerson;
import com.sun.syndication.feed.synd.SyndPersonImpl;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.WireFeedOutput;

public class ExampleRomeOutput {

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err
                    .println("Usage: java javaxml3.ExampleRomeOutput [feedtype]");
            return;
        }

        SyndPerson author = new SyndPersonImpl(  );
        author.setEmail("[email protected]");
        author.setName("Example Person");

        SyndFeed feed = new SyndFeedImpl(  );
        feed.setTitle("Example Feed Output from ROME");
        feed.setDescription("The Example Organization web site");
        feed.setAuthors(Collections.singletonList(author));
        feed.setLink("http://www.example.org/");
        feed.setPublishedDate(new Date(  ));

        SyndEntry entry = new SyndEntryImpl(  );
        entry.setTitle("First Entry Title");
        entry.setLink("http://www.example.org/item1");
        SyndContent description = new SyndContentImpl(  );
        description.setValue("News about the Example project");
        description.setType("text");
        entry.setDescription(description);
        entry.setAuthors(Collections.singletonList(author));
        feed.getEntries(  ).add(entry);

        entry = new SyndEntryImpl(  );
        entry.setTitle("Second Entry Title");
        entry.setLink("http://www.example.org/item2");
        description = new SyndContentImpl(  );
        description.setValue("<i>More</i> news about the Example project");
        description.setType("html");
        entry.setDescription(description);
        entry.setAuthors(Collections.singletonList(author));
        feed.getEntries(  ).add(entry);

        List supportedTypes = feed.getSupportedFeedTypes(  );
        String feedType = args[0];
        if (!supportedTypes.contains(feedType)) {
            System.err.println("Feed Type is not supported.");
            System.err.println("Supported feed types are: "
                    + supportedTypes.toString(  ));
            return;
        }

        WireFeed rssFeed = feed.createWireFeed(feedType);

        WireFeedOutput output = new WireFeedOutput(  );
        try {
            output.output(rssFeed, new OutputStreamWriter(System.out));
        } catch (IOException e) {
            System.err.println("Unable to output feed: " + e.getMessage(  ));
            e.printStackTrace(  );
        } catch (FeedException e) {
            System.err.println("Unable to generate feed: " + e.getMessage(  ));
            e.printStackTrace(  );
        }
    }

}

ROME 0.8 has a nasty bug where if the type of an item/entry description isn't set with the setType( ) method, a NullPointerException is thrown when outputting RSS 2.0. The problem is that RSS 2.0 doesn't support typed descriptions, so if you're targeting a feed to RSS 2.0, you may not think to call the setType( ) method. Both to avoid this bug and to enable you to support feed formats that do support typed description, you should always call setType( ).


This class can be used to generate an RSS 2.0 feed by running:

java javaxml3.ExampleRomeOutput rss_2.0

This will produce:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Example Feed Output from ROME</title>
    <link>http://www.example.org/</link>
    <description>The Example Organization web site</description>
    <pubDate>Thu, 03 Aug 2006 02:49:20 GMT</pubDate>
    <managingEditor>Example Person</managingEditor>
    <dc:date>2006-08-03T02:49:20Z</dc:date>
    <item>
      <title>First Entry Title</title>
      <link>http://www.example.org/item1</link>
      <description>News about the Example project</description>
      <author>[email protected]</author>
      <guid>http://www.example.org/item1</guid>
    </item>
    <item>
      <title>Second Entry Title</title>
      <link>http://www.example.org/item2</link>
      <description>&lt;i&gt;More&lt;/i&gt; news about the Example 
project</description>
      <author>[email protected]</author>
      <guid>http://www.example.org/item2</guid>
    </item>
  </channel>
</rss>

This same feed can be output as RSS 1.0 by running:

java javaxml3.ExampleRomeOutput rss_1.0

producing:

<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel rdf:about="http://www.example.org/">
    <title>Example Feed Output from ROME</title>
    <link>http://www.example.org/</link>
    <description>The Example Organization web site</description>
    <items>
      <rdf:Seq>
        <rdf:li resource="http://www.example.org/item1" />
        <rdf:li resource="http://www.example.org/item2" />
      </rdf:Seq>
    </items>
    <dc:date>2006-08-03T02:51:45Z</dc:date>
  </channel>
  <item rdf:about="http://www.example.org/item1">
    <title>First Entry Title</title>
    <link>http://www.example.org/item1</link>
    <description>News about the Example project</description>
  </item>
  <item rdf:about="http://www.example.org/item2">
    <title>Second Entry Title</title>
    <link>http://www.example.org/item2</link>
    <description>&lt;i&gt;More&lt;/i&gt; news about the Example
project</description>
  </item>
</rdf:RDF>

And finally, output as Atom 1.0 by running:

java javaxml3.ExampleRomeOutput atom_1.0

which produces:

<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" 
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" 
xmlns:dc="http://purl.org/dc/elements/1.1/">
  <title>Example Feed Output from ROME</title>
  <link rel="alternate" href="http://www.example.org/" />
  <author>
    <name>Example Person</name>
    <email>[email protected]</email>
  </author>
  <subtitle>The Example Organization web site</subtitle>
  <updated>2006-08-03T02:50:02Z</updated>
  <dc:date>2006-08-03T02:50:02Z</dc:date>
  <entry>
    <title>First Entry Title</title>
    <link rel="alternate" href="http://www.example.org/item1" />
    <author>
      <name>Example Person</name>
      <email>[email protected]</email>
    </author>
    <summary type="text">News about the Example project</summary>
  </entry>
  <entry>
    <title>Second Entry Title</title>
    <link rel="alternate" href="http://www.example.org/item2" />
    <author>
      <name>Example Person</name>
      <email>[email protected]</email>
    </author>
    <summary type="html">&lt;i&gt;More&lt;/i&gt; news about the Example 
project</summary>
  </entry>
</feed>

As you can see from these sample outputs, ROME tends to create namespace declarations when they aren't required. You can safely ignore these. We'll see why this happens in the section "Creating a ROME Module" later in this chapter.




 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows