Based on the examples and information above, you should be able to create RSS documents using the tools explored earlier in this tutorial. 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 app blojsom (available from ) 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:

ROME supports parsing and generating feeds as well as converting between one format and another. ROME is downloadable from its project web site, . As of the time of writing, the current version of ROME is 0.8 beta. ROME uses the JDOM library we examined in , 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. contains a UML diagram of the interfaces in the format-independent model.

ROME format-independent data model

Java ScreenShot

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 , contains the superset of the features from all the various RSS versions; the Atom data model, diagrammed in , supports all the features in both released versions of the Atom specification: 0.3 and 1.0.

ROME RSS data model

Java ScreenShot

ROME Atom data model

Java ScreenShot

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:

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:

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

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.

Example 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("editor@example.org");
 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( );
 }
 }
}
Java Warning 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>editor@example.org</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>editor@example.org</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://web.archive.org/web/www.example.org/" />
 <author>
 <name>Example Person</name>
 <email>editor@example.org</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://web.archive.org/web/www.example.org/item1" />
 <author>
 <name>Example Person</name>
 <email>editor@example.org</email>
 </author>
 <summary type="text">News about the Example project</summary>
 </entry>
 <entry>
 <title>Second Entry Title</title>
 <link rel="alternate" href="http://web.archive.org/web/www.example.org/item2" />
 <author>
 <name>Example Person</name>
 <email>editor@example.org</email>
 </author>
 <summary type="html">&lt;i&gt;More&lt;/i&gt; news about the Example project</summary>
 </entry>
</feed>
Java Tip

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 " later in this chapter.