Click here to Skip to main content
15,881,172 members
Articles / Programming Languages / C#

Using Reflection to Parse and Generate Content Feeds

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
21 Nov 2011CPOL2 min read 11.8K   1   1
Uses Reflection to translate a feed into a corresponding .NET class structure.

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:

C#
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:

C#
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 Tracks 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.

C#
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..

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
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.

Comments and Discussions

 
QuestionI do not understand Pin
scalp15-Mar-12 3:11
scalp15-Mar-12 3:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.