I wanted to read RSS into a DataSet but found that when loading the XML from, for example, a community server feed I would often get a 'column already exists'. This was because the feed used namespaces which causes elements to be declared like this: <slash:comment>
There are two solutions to this. First, write an XSLT to parse out the stuff I don't want. Second, run over the raw XML myself and filter it. I wanted to go with the second, because writing XSLT for every customised RSS, ATOM, etc feed that my front end developers might want to use didn't appeal - I just wanted to be able to load the RSS into a DataSet. However, then I found some code which seemed to work: http://www.aspcode.net/Updated-RSS-reader-class-dealing-with-already-belongs-error.aspx
The one problem I had was that the code did not seem to know when an element like <enclosure/> did not have a closing tag following it. I have fixed this code and present it below. I have used it to load the header information and each item entry in the RSS feed into a couple of repeaters, for quick databinding, so that I can provide a simple data layout for my front end designer to work with. He can then style this anyway he likes and I can even wrap the items table in a DataView to sort and filter it by any combination of fields in the feed. Of course, because this uses a DataSet, I could even merge other feeds into it.
Many thanks to, er, admin(?), for writing the original - you really have helped me a lot!...
protected void Page_Load(object sender, EventArgs e)
{
DataSet set = new DataSet();
XmlTextReader xmlRdr = new XmlTextReader("http://stuff.tv/blogs/cool/rss.aspx");
XmlDocument doc = new XmlDocument();
doc.Load(xmlRdr);
set = GetRSSDataSet("http://stuff.tv/blogs/cool/rss.aspx");
headerRepeater.DataSource = set.Tables[1];
itemsRepeater.DataSource = set.Tables[2];
DataBind();
}
public DataSet GetRSSDataSet(string m_strAdress)
{
DataSet m_ds = new DataSet();
System.Xml.XmlTextReader oXml = new System.Xml.XmlTextReader(m_strAdress);
oXml.WhitespaceHandling = System.Xml.WhitespaceHandling.None;
System.Text.StringBuilder oBuilder = new StringBuilder();
bool fContinue = oXml.Read();
while (fContinue)
{
string sName = oXml.Name.Replace(":", "_");
bool isClosed = oXml.IsEmptyElement;
if (oXml.NodeType == System.Xml.XmlNodeType.Element)
{
//Add the element...
oBuilder.Append("<" + sName);
if (oXml.HasAttributes)
{
while (oXml.MoveToNextAttribute())
{
sName = oXml.Name.Replace(":", "_");
oBuilder.AppendFormat(" " + sName + "=\"" + oXml.Value + "\"");
}
}
if (isClosed)
oBuilder.Append("/");
oBuilder.Append(">");
}
else if (oXml.NodeType == System.Xml.XmlNodeType.Text)
{
oBuilder.Append(System.Web.HttpUtility.HtmlEncode(oXml.Value));
}
else if (oXml.NodeType == System.Xml.XmlNodeType.EndElement)
{
oBuilder.Append("</" + sName + ">");
}
fContinue = oXml.Read();
}
oXml.Close();
string sXmlResult = oBuilder.ToString();
m_ds = new DataSet();
System.IO.StringReader oStringReader = new System.IO.StringReader(sXmlResult);
try
{
m_ds.ReadXml(oStringReader, System.Data.XmlReadMode.Auto);
}
catch (Exception ex)
{
m_ds = null;
}
if (oStringReader != null)
oStringReader.Close();
if (oXml != null)
oXml.Close();
return m_ds.Tables.Count == 0 ? null : m_ds;
}
[EDIT: 2008-06-20] I have a .NET3.5 new and improved version of this, which allows multiple feeds and optional sorting - I'll post this later.
[EDIT: 2009-02-19] Sorry for not having posted the replacement of this code. I will, when I find it. A lot has happened since the original posting.