Blogger :
Dan Wahlin XML
All posts :
All posts by Dan Wahlin XML
Category :
.NET XML, System.XML
Blogged date : 2006 Sep 28
We needed an RSS blog roller for http://www.interfacett.com so we could show various employee blogs. While there are several out there for .NET we wanted something that we could build on and customize so I put together a quick class named RssBlogRoller that would read an array of blog URLs, grab a specific number of items and then sort them based upon the <pubDate> element. It was a fun little exercise that will be useful in classes as well since it demonstrates generics, XmlReaders (and sub readers) and the ASP.NET ObjectDataSource.
The code for the RssBlogRoller is shown below. I've refactored it several times now and while it's not perfect, it gets the job done. RssBlogRoller has a method named GetRssItems that returns an array of RssItem objects (also shown below).
using System;
using System.Web.Configuration;
using System.Xml;
using System.IO;
using System.Collections.Generic;
using System.Web;
namespace InterfaceTT {
public class RSSBlogRoller {
public static RSSItem[] GetRssItems(string rssURLs,
int numberToShow)
{
//Try to grab URLs from web.config
if (rssURLs == null) rssURLs =
WebConfigurationManager.AppSettings["BlogUrls"];
if (String.IsNullOrEmpty(rssURLs))
{
HttpContext.Current.Trace.Warn("GetRssItems",
"rssURLs is empty. No blogs to parse were found.");
return null;
}
//Get each person's blog URL
string[] rssUrlsArray = rssURLs.Split(new char[] { ';' });
//Check if we have any URLs to retrieve
if (rssUrlsArray == null || rssUrlsArray.Length == 0)
{
HttpContext.Current.Trace.Warn("GetRssItems",
"rssURLs is empty. No blogs to parse were found.");
return null;
}
//Create dictionary to store each person's blog entries
//Key is blog URL, value is all the person's entries
Dictionary<string, List<RSSItem>> namesFeeds =
new Dictionary<string, List<RSSItem>>();
foreach (string url in rssUrlsArray)
{
if (url.Length > 0)
{
List<RSSItem> blogItems = new List<RSSItem>();
RSSItem currItem = null;
XmlReader reader = null;
try
{
reader = XmlReader.Create(url);
while (reader.Read())
{
//Exit read operation if we've
//found all we need
if (blogItems.Count > numberToShow) break;
if (reader.NodeType == XmlNodeType.Element
&& reader.Name.ToLower() == "item")
{
//Create a sub XmlReader
currItem = ReadRSSItem(reader.ReadSubtree());
}
//After each item end tag create HTML output
if (reader.NodeType == XmlNodeType.EndElement
&& reader.Name.ToLower() == "item")
{
if (currItem != null)
blogItems.Add(currItem);
}
}
}
catch (Exception exp)
{
HttpContext.Current.Trace.Warn("GetRssItems",
"Error in reading RSS feed: " + exp.Message);
}
finally
{
if (reader != null) reader.Close();
}
if (blogItems.Count > 0)
{
namesFeeds.Add(url, blogItems);
}
}
} //End For
RSSItem[] newItems = GetRSSItems(namesFeeds, numberToShow);
//Will sort by pubDate...implements IComparable<T>
Array.Sort(newItems);
return newItems;
}
private static RSSItem ReadRSSItem(XmlReader subReader)
{
string title = null;
string link = null;
string desc = null;
DateTime? pubDate = null; //Nullable<DateTime>
string authorName = null;
subReader.MoveToContent();
while (subReader.Read())
{
switch (subReader.Name.ToLower())
{
case "title":
title = subReader.ReadString();
break;
case "link":
link = subReader.ReadString();
break;
case "description":
desc = subReader.ReadString();
break;
case "pubdate":
string pubDateVal = subReader.ReadString();
DateTime d;
if (DateTime.TryParse(pubDateVal, out d))
{
pubDate = Convert.ToDateTime(pubDateVal);
}
break;
case "author":
authorName = subReader.ReadString();
break;
}
}
if (!String.IsNullOrEmpty(title)
&& !String.IsNullOrEmpty(link)
&& !String.IsNullOrEmpty(desc))
{
RSSItem item = new RSSItem(title, link,
desc, pubDate, authorName);
return item;
}
return null;
}
private static RSSItem[] GetRSSItems(Dictionary<string,
List<RSSItem>> namesFeeds, int numberToShow)
{
if (numberToShow < 1) numberToShow = 1;
List<RSSItem> blogItems = new List<RSSItem>();
int i = 0;
if (namesFeeds != null && namesFeeds.Count > 0)
{
foreach (string key in namesFeeds.Keys)
{
List<RSSItem> items = namesFeeds[key];
if (items != null)
{
int count = items.Count;
if