In the Part 1, I talked about some of the applications you can build for the Zune today, and specifically, my plans to create a wrapper for the Zune user card Web service using LINQ to XML. Note that this is a quick and dirty class I baked in a couple of hours. If you are looking for a more robust implementation, be sure to check out Mehfuz's WebLog - specifically his posting on integrating REST with LINQ to XML, and his custom LINQ.Flickr provider. Let's take a look at the namespaces:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
You'll notice that System.Linq (to access the core LINQ functionality) and System.Xml.Linq (to access LINQ to XML) are included as namespaces. Then a class called ZuneCard is defined and a bunch of public auto-implemented properties are defined (a feature of C# 3.5 - each property corresponds to a node in the Zune Card XML tree):
namespace ZuneCardApi
{
public class ZuneCard
{
// Exposed Properties
public string id { get; set; }
public string label { get; set; }
public string firstName { get; set; }
public string status { get; set; }
public string tileBig { get; set; }
public string tileSmall { get; set; }
public string name { get; set; }
public string location { get; set; }
public string bio { get; set; }
public string backgroundLarge { get; set; }
public string backgroundSmall { get; set; }
public string totalPlays { get; set; }
Then ZuneCard is implemented and the tag parameter is passed (corresponding to the user's Zune tag). The XDocument object is used to load in the XML data for the user card. Note that this operation happens only once, then the data can be manipulated and queried to your heart's content in memory (which has performance benefits).
public ZuneCard(string tag)
{
XDocument zCardXml = XDocument.
Load(@"http://zcards.zune.net/zcard/usercardservice.ashx?zunetag=" + tag);
Next, we need to call our LINQ queries. Essentially, we are transversing the nodes of our XML tree (found here) starting at the user node. Anonymous Types (another C# 3.5 feature) are used liberally here (as you can see below):
var user = from u in zCardXml.Descendants("user")
select new
{
_id = u.Element("id").Value,
_label = u.Element("label").Value,
_firstName = u.Element("firstName").Value,
_status = u.Element("status").Value,
_tileBig = u.Element("image").Value,
_tileSmall = u.Element("image").Value
};
var userData = from uD in zCardXml.Descendants("userData")
select new
{
_name = uD.Element("name").Value,
_location = uD.Element("location").Value,
_bio = uD.Element("bio").Value,
_backgroundLarge = uD.Element("image").Value,
_backgroundSmall = uD.Element("image").Value,
_totalPlays = uD.Element("totalPlays").Value
};
Finally, we need to iterate through the collections and load the values into the public properties (as shown below):
foreach (var u in user)
{
id = u._id;
label = u._label;
firstName = u._firstName;
status = u._status;
tileBig = u._tileBig;
tileSmall = u._tileSmall;
}
foreach (var uD in userData)
{
name = uD._name;
location = uD._location;
bio = uD._bio;
backgroundLarge = uD._backgroundLarge;
backgroundSmall = uD._backgroundSmall;
totalPlays = uD._totalPlays;
}
}
}
}
In the next part in the series, we'll take a look at how to handle collections corresponding to playlists, badges and other user preferences. In the meantime, if you have any suggestions on how to improve this code, feel free to post a comment.