A few days ago, I came up with an interesting concept to enable quick and easy parsing and generation of
syndication content feeds. Rather than using the standard approach
of using an XML document and using XPath to parse a feed into some other structure, I set about experimenting with Reflection to translate a
feed into a corresponding .NET class structure.
After a while, I started writing my own serialization framework, but this is strictly targeted at quick and dirty implementations
of feed reading and writing.
To summarize in brief terms, all you need to do is create a corresponding class for whatever feed type you want to consume - for simplicity's sake, we will consider
the XSPF playlist format, but you could apply the same principles to RSS and ATOM.
Using a set of base classes I have implemented, I can read and write valid XSPF using just
three classes, these classes define the primary objects of an XSPF file.
The playlist:
public class Playlist : ChannelBase, IChannel
{
public string title { get; set; }
[OptionalElement()]
public string creator { get; set; }
[OptionalElement()]
public string annotation { get; set; }
[OptionalElement()]
public string info { get; set; }
[OptionalElement()]
public string location { get; set; }
[OptionalElement()]
public string identifier { get; set; }
[OptionalElement()]
public string image { get; set; }
[OptionalElement()]
public DateTime date { get; set; }
[OptionalElement()]
public string license { get; set; }
[ComplexElement()]
public TrackCollection trackList { get; set; }
}
The track:
public class Track : Syndication.Core.IComplexElement
{
public string location { get; set; }
public string title { get; set; }
[OptionalElement()]
public string identifier { get; set; }
[OptionalElement()]
public string creator { get; set; }
[OptionalElement()]
public string annotation { get; set; }
[OptionalElement()]
public string info { get; set; }
[OptionalElement()]
public string image { get; set; }
[OptionalElement()]
public string album { get; set; }
[OptionalElement()]
public Int32 trackNum { get; set; }
[OptionalElement()]
public Int32 duration { get; set; }
}
And lastly a Collection of Track
s called trackList
.
We only need to implement classes for custom structures that are stored in a feed.
This is normally anything that is not a standard .NET DataType
such as in the case above - a Track
. These custom structures have to implement a custom Interface called
IComplexElement
which contains one routine
to parse the corresponding XmlNode
for that class.
Now here comes the fun bit..
Using a combination of Reflection, the structures discussed above, and XmlDocument
, I can parse an entire XSPF file in 24 lines of code and place the results into
a corresponding .NET class - strong typing rules OK! - The built-in functions in .NET for deriving type name and formatting values combined with some key
custom attributes
to specify optional or complex properties help a lot here as it enables the parsing routine to determine how to
set the property value correctly and/or parse child
values where required. Here you can see the parse routine at work. And because ComplexElements (custom classes) must implement their own
Parse
routine, these classes are created,
and their relevant parse routine is called, passing the current XML child node as a parameter.
public override void Parse(XmlDocument xml)
{
this.trackList.Clear();
XmlNode root = xml.GetElementsByTagName("playlist")[0];
if (root == null) { return; }
foreach (XmlNode node in root.ChildNodes)
{
if (ReflectionUtility.IsComplexElement(this, node.Name))
{
ReflectionUtility.SetComplexPropertyValue(this, node.Name, node);
}
else
{
if (ReflectionUtility.IsArray(this, node.Name))
{
ReflectionUtility.SetPropertyValue(this, node.Name, node.ChildNodes);
}
else
{
ReflectionUtility.SetPropertyValue(this, node.Name, node.InnerText);
}
}
}
}
Using this extensible framework, I have so far been able to add support for reading and
writing ATOM, RSS,
and XSPF feeds and would imagine the framework is sufficiently
expandable to allow parsing of other formats when required.
At some stage, a more formal article will appear on CodeProject along with the full
source code when I have fully implemented the project..
Peace y'all..
Senior Developer with over 10 years experience of Microsoft Technologies working on both Web and WinForms Client Applications.
Keeper of 3 Chickens and enjoys Archery.