Trivial RSS Writer



Recently, I’ve been going through the standard fatherhood ritual of trying to setup of a webpage to share out photos of my kid. This naturally involves creating an RSS feed so that family can subscribe to the new image list.


I wanted to be able to write simple C# code like this to produce the feed:


static void WriteWholeFile()
{
XmlWriter xml =
new XmlTextWriter(new StreamWriter(“myfeed.xml”));
RssWriter rss =
new RssWriter(xml);

rss.WriteHeader(“My Mini blog”, “http://xyz.com”, “My site of baby pictures”, null);
rss.WriteItem(
“First item”,
“Hi! Here’s the <b>first</b> item”,
new System.Uri(“http://xyz.com/1.html”),
new DateTime(1999, 12, 1));

rss.WriteItem(
“Second item”,
“Here’s the <b>2nd</b> item.”,
new System.Uri(“http://xyz.com/2.html”),
new DateTime(1988, 10, 4));
rss.Close();
xml.Close();
}


Here’s some trivia about some of the decisions I made here:



  • I’m no RSS/XML/Web expert, so I have no doubt there are many better implementations out there.
  • Copying one of these other writers would violate the unspoken rules of this standard fatherhood ritual. (as would using Flickr)
  • My main goal was simplicity, as illustrated by the usage snippet above.
  • It’s producing valid RSS 2.0 feeds. You can validate the feeds by URL at http://feedvalidator.org, or by pasting in the text at http://validator.w3.org/feed. And they also work in SharpReader (which is what my target audience is using).
  • DateTimeFormatInfo is a live-saver to get the the DateTime into the date format needed for an RSS feed.
  • Since RSS is just XML, I choose to build RSSWriter on an XmlWriter. This lets the caller have great flexibility about where the XML goes (a local file, a string, a node in an XML Dom)
  • The RSSWriter does not own the underlying XmlWriter, and so RSSWriter.Close() does not close the underlying streams.
  • I avoided XML Serialization (the method Dare used in RSSBandit) because I wanted a simple, forward writing, stateless, writer. This is similar to using XmlWriter over the XML Dom.

Here’s the code:  [Updated: made some minor tweaks, including rename RSS–>Rss per fxcop guidelines]


using System;
using System.Xml;
using System.IO;

// Class to write out RSS
// Expected Usage:
// rss = new RSSWriter(…);
// rss.WriteHeader(…);
// rss.WriteItem(..);
// rss.WriteItem(..);
// rss.WriteItem(..);
// rss.Close();

// Validate feeds by URL: http://feedvalidator.org, or http://validator.w3.org/feed
// Code for RSS writer from http://blogs.msdn.com/jmstall
class RssWriter
{
XmlWriter m_writer;
public RssWriter(XmlWriter tw)
{
m_writer = tw;
}

// Write header for RSS Feed
// Parameters:
// title – Pretty title of the RSS feed. Eg “My Pictures”
// link – optional URL to link RSS feed back to a web page.
// description – more verbose human-readable description of this feed.
// generator – optional string for ‘generator’ tag.
public void WriteHeader(string title, string link, string description, string generator)
{
m_writer.WriteStartElement(
“rss”);
m_writer.WriteAttributeString(
“version”, “2.0”);
m_writer.WriteStartElement(
“channel”);
m_writer.WriteElementString(
“title”, title);

if (link != null)
{
m_writer.WriteElementString(
“link”, link); // link to generated report.
}
m_writer.WriteElementString(
“description”, description);

if (generator != null)
{
m_writer.WriteElementString(
“generator”, generator);
}

m_writer.WriteElementString(“lastBuildDate”, ConvertDate(new DateTime()));

}

// Write out an item.
// title – title of the blog entry
// content – main body of the blog entry
// link – link the blog entry back to a webpage.
// time – date for the blog entry.
public void WriteItem(string title, string content, System.Uri link, DateTime time)
{
m_writer.WriteStartElement(
“item”);
WriteItemBody(m_writer, title, content, link, time);
m_writer.WriteEndElement();
// item
}

// Write just the body (InnerXml) of a new item
public static void WriteItemBody(XmlWriter w, string title, string content, System.Uri link, DateTime time)
{
w.WriteElementString(
“title”, title);
if (link != null) { w.WriteElementString(“link”, link.ToString()); }
w.WriteElementString(
“description”, content); // this will escape
w.WriteElementString(“pubDate”, ConvertDate(time));
}

// Close out the RSS stream.
// this does not close the underlying XML writer.
public void Close()
{
m_writer.WriteEndElement();
// channel
m_writer.WriteEndElement(); // rss
}

// Convert a DateTime into the format needed for RSS (from RFC 822).
// This looks like: “Wed, 04 Jan 2006 16:03:00 GMT”
static string ConvertDate(DateTime t)
{

// See this for help on format string
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconcustomdatetimeformatstrings.asp
DateTime t2 = t.ToUniversalTime();
return t2.ToString(@”ddd, dd MMM yyyy HH:mm:ss G\MT”);
}

}

 

Comments (3)

  1. Kevin Dente says:

    Nice. But according to the framework naming guidelines, shouldn’t that class be named RssWriter?

  2. I needed a similar thing and I cooked up an ugly xml dumper at http://blogs.msdn.com/abhinaba/archive/2005/12/21/506277.aspx

    Too bad your blog was not up by that time 🙁

  3. jmstall says:

    Kevin – you caught me red-handed. I mdae an update.