Friday, May 11, 2012

Generic XML attribute parser

I may just end up using something like LINQ to XSD for this (if possible), but I wanted to see how easy it would be to write an XML parser that takes in an element of any kind, and returns a strongly-typed value. Here's what I came up with:

private T parseAttr<T>(XElement x, string elemName)
{
    Type type = typeof(T);
    T parsedValue;

    try
    {
        parsedValue = type.IsEnum ? (T)Enum.Parse(typeof(T), x.Element(elemName).Value) : (T)Convert.ChangeType(x.Element(elemName).Value, typeof(T));
    }
    catch
    {
        parsedValue = default(T);
    }

    return parsedValue;
}

which can be used like this (example is from a LINQ projection):

let picks =
    from pick in playerPicks.Element("PlayerList").Descendants("Player").Elements("Picks")
    select new PlayerPick
    {
        TickerSymbol = parseAttr<string>(pick, "TickerSymbol"),
        Status = parseAttr<Status>(pick, "Status"),
        PickCall = parseAttr<PickCall>(pick, "PickCall"),
        StartPrice = parseAttr<double>(pick, "StartPrice"),
        EndPrice = parseAttr<double>(pick, "EndPrice"),
        StartDate = parseAttr<DateTime>(pick, "StartDate"),
        EndDate = parseAttr<DateTime>(pick, "EndDate")
    }

It works on regular types as well as enums. I'm not completely happy with it - "Convert" is generally less useful than .Parse(), but I couldn't figure out how to use Parse with generics on static methods (i.e. (T).Parse()).

Also, it's hardly bulletproof, but I think I may validate the whole XML document first anyway if it doesn't take too long. Not sure if I'll end up using this or not - I was just amazed about how easy this was to write using generics, and thought it might be useful to somebody.

No comments: