Generating XML RSS 2 feeds with JDOM 2 with a servlet

To better demonstrate how to generate XML RSS 2 feeds, we will use a servlet with JDOM 2 library. In this short blog, we will generate only the required elements plus a few options for feed reader interoperability. Please refer to the RSS 2 documentation for more of the optional elements and to learn more about the RSS 2 specifications. JDOM 2 is available for download here http://www.jdom.org/.

Below is a sample RSS 2 feed generated by the servlet that follows further down (contents edited for clarity).

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <!-- title, link, description are required -->
    <title>Primo's code blogs feeds</title>
    <description>Feeds from  Kahimyang Projects Primo's code blogs</description>
    <link>http://kahimyang.info/kauswagan/RssFeeds.xml?type=howto</link>
    <language>en</language>

    <!-- Only for feed reader interoperability -->
    <atom:link rel="self" href="http://kahimyang.info/kauswagan/RssFeeds.xml?type=howto" 
            type="application/rss+xml" />

    <!-- Contents of the feed -->
    <item>
      <title>
         Title of the story item.
      </title>
      <link>
         URL that points to the full content.
      </link>
      <description>
        <![CDATA[
        Description of the item.  In the case of a blog or 
            news item, this can be the synopsis.  
        ]]>
      </description>
      <guid>
         unique_id_of_the_feed_item
      </guid>
      
      <!-- Required format.  Publication date -->
      <pubDate>Fri, 16 Sep 2011 14:31:01 EDT</pubDate>

    </item>

    <!-- more items -->

  </channel>
</rss>

The sample feed above was generated based on the recommendation of the Feed Validator Service from w3.org.

Elements <link /> and <atom:link /> in lines 7 and 11 should point to the URL of the feed. Sub-element <link /> of <item /> points to the URL of the item itself.  Date and time values should conform to RFC #822.  Wrapping the description with CDATA is required if the content has HTML formatting.

Here is the servlet that generated the above sample feed.  Please refer to the inline comments for more information. In this servlet, items are drawn from a database. Please note that some lines were removed for clarity.


package pname;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jdom2.CDATA;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;

@WebServlet(name = "RssFeeds", urlPatterns = {"/RssFeeds.xml"})
public class RssFeeds extends HttpServlet {

    @Override
    protected void doGet (HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
                
        response.setContentType("application/xml;charset=UTF-8");
        PrintWriter servlet = response.getWriter();
        
        try {
            // Create the root rss element            
            Element rssRoot = new Element("rss");


            // Required attribute
            rssRoot.setAttribute("version", "2.0");
            
            // Create the XML document
            Document feed = new Document();
            feed.setRootElement(rssRoot);
                        
            Element channel = new Element("channel");
            
            rssRoot.addContent(channel);


            channel.addContent(new Element("title").
                     addContent("Title of the Feed"));
            channel.addContent(new Element("description").
                 addContent("Description of the entire feed"));
            
            final String url=
                    "http://kahimyang.info/kauswagan/RssFeeds.xml?type=howto";
            
            channel.addContent(new Element ("link").addContent (url));                 
            channel.addContent(new Element("language").addContent("en"));


            // Create the atom namespace
            Namespace atom = 
                   Namespace.getNamespace("atom","http://www.w3.org/2005/Atom");
            rssRoot.addNamespaceDeclaration(atom);            
                       
            Element link = new Element ("link",atom);  // atom:link
            link.setAttribute("rel","self").setAttribute("href",url).
                 setAttribute("type","application/rss+xml");

            channel.addContent(link);
                        
            addRssItems (channel); // the actual feeds
                       
            // Write the document to the servlet response
            XMLOutputter output = new XMLOutputter();
            output.setFormat(Format.getPrettyFormat().setEncoding("UTF-8"));
            output.output(feed, servlet);

        }  
        finally {
            servlet.flush();
            servlet.close();
        }
    }


    void addRssItems (Element channel) {

        // Build the query 
        StringBuilder q = new StringBuilder("select ...");

        try (
                // Change the way you connect to database.
                Connection conn = DatasourceConnection.getConnection();
                Statement stmt = conn.createStatement();
                ResultSet result = stmt.executeQuery(q.toString())) {


            while (result.next()) {

                Element item = new Element("item");
                item.addContent(new Element("title").
                        addContent(result.getString(1)));

                // link to the item itself
                item.addContent(new Element("link").
                          addContent(result.getString(2)));

                // This can be a sysnopsis
                // Strip off risky attributes from html tags
                String teaser=Jsoup.clean(result.getString(3),Whitelist.basic());
                item.addContent(new Element("description").
                         addContent(new CDATA(teaser)));

                // Unique ID, usually this is the same as link 
                item.addContent(new Element("guid").addContent("the_unique_id"));
                    
                // Required format
                SimpleDateFormat f = 
                       new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
                item.addContent(new Element("pubDate").
                       addContent(f.format(result.getTimestamp(4))));

                channel.addContent(item);

            }
            

        } catch (Exception e) {
            // return an empty channel
        }
    }


    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Character encoding specified in lines 30 and 77 should match.  Application type application/xml should also be used for some browsers to render the feed correctly.

Additional library used in this servlet (line 112 above) is Jsoup. It can be downloaded here http://jsoup.org/.

That's it Good Luck.

If you like the article, please share.
(Site URL pattern has changed as a result social actions counter was reset.)



Comment icon Comments (Newest first)