Handling XML files on Windows Phone through deserilization


XMLDeserializationMany times your application will need to read and manipulate xml-files. This can be because you’re downloading a RSS-feed or saving your data as xml-files to let’s say isolated storage. Now we’ll look at a quick way to deserialize an XML-file so you can easily use its data in our application. There are many ways to handle XML files but deserialization and LINQ-to-XML are definitely the most powerful ones.

Let’s get jiggy with it so start up Visual Studio and create a new Windows Phone Application for our exercise. In this post we won’t go through the basics so I suggest that if you’re new to Windows Phone you check out the Introduction to Windows Phone articles.

Downloading content

You can download content from outside the .xap-file using a WebClient. You can use it to do asynchronous downloads for example from a website. We’re going to use CNN as the source of our RSS feed.

How to use the WebClient?

First of you need to create a new instance of the WebClient object, we’ll do this in the constructor of our MainPage.
 
MainPage.xaml.cs
public partial class MainPage : PhoneApplicationPage
{
    // Constructor
    public MainPage()
    {
        InitializeComponent();
        WebClient downloader = new WebClient();
    }
}
After that you can use the WebClient object to download data. You can use the DownloadStringAsync-method to asynchronously download content by passing the Uri of the content. So first off create a new Uri object.
 
MainPage.xaml.cs 
public MainPage()
{
    InitializeComponent();
    WebClient downloader = new WebClient();
    Uri rssUri = new Uri("http://rss.cnn.com/rss/edition.rss", UriKind.Absolute);
}
After that we’ll add an event handler for the DownloadStringCompleted-event, so we know when the RSS-feed has been downloaded and then we’ll start downloading from the predefined Uri. Remember that Visual Studio has great IntelliSense so when you type
downloader.DownloadStringCompleted +=
Visual Studio will suggest to press the TAB-key twice to generate the event handler, of course you can also write it by hand.
 
MainPage.xaml.cs
public partial class MainPage : PhoneApplicationPage
{
    // Constructor
    public MainPage()
    {
        InitializeComponent();
        WebClient downloader = new WebClient();
        Uri rssUri = new Uri("http://rss.cnn.com/rss/edition.rss", UriKind.Absolute);
        downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Downloaded);
        downloader.DownloadStringAsync(rssUri);
    }

    void Downloaded(object sender, DownloadStringCompletedEventArgs e)
    {
        throw new NotImplementedException();
    }
}
In the completed event-handler (Downloaded) you should always make sure that the received result isn’t empty and has no errors. In the simplest case you could do something like this
 
MainPage.xaml.cs
void Downloaded(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Result == null || e.Error != null)
    {
        MessageBox.Show("There was an error downloading the RSS-file");
    }
    else
    {
        // Deserialize if download succeedes
    }
}

XML Deserialization

In XML Deserilization we load an xml document and pass it’s data to a deserializer. From there we get a CLR-representation of the data. In our sample, we’re going to parse the previously downloaded rss-file and create a collection of CNNNews, through the XmlDeserializer.
First off add a reference System.Xml.Serialization to the Silverlight project, by right-cliking “References” and selecting “Add new reference”.
 
image
Next for the sake of clarity let’s add two new classes to the Silverlight project, name one CNNNews and the other one CNNItem. Right-click on the Silverlight project and select Add=>Class… and add those classes.
 
Before we go into C# take a look at the XML-file that was downloaded. You’ll se that <channel>, which we will define in CNNNews.cs, actually contains a collection of <item>-tags like this one:

 
Downloaded RSS-file
<item>
  <title>Ash cloud grounds Australian flights</title>
  <guid>http://edition.cnn.com/2011/WORLD/asiapcf/06/21/australia.ash.cloud/index.html?eref=edition</guid>

  <link>http://edition.cnn.com/2011/WORLD/asiapcf/06/21/australia.ash.cloud/index.html?eref=edition</link>
  <description>An ash cloud from a Chilean volcano is once again grounding commercial jets</description>
  <pubDate>Tue, 21 Jun 2011 09:11:01 EDT</pubDate>
</item>
 
The item-tag contains title, guid, link, description and a pubDate. We’ll define our CNNItem.cs to represent this. Let’s start with CNNNews by defining the root for the XML-document to “rss” and add the appropriate using-statement so right-click on the XmlRoot and select Resolve –> + using System.Xml.Serialization.
 
CNNNews.cs
[XmlRoot("rss")]
public class CNNNews
{

}
After that we’ll just define the that we have a array called channel and it contains items called item. We’ll place these in an ObservableCollection of type CNNItem. You’ll also need to add a using statement to be able to access ObservableCollection, so right click on it and select Resolve –> + using System.Collections.ObjectModel;
 
CNNNews.cs
[XmlRoot("rss")]
public class CNNNews
{
    [XmlArray("channel")]
    [XmlArrayItem("item")]
    public ObservableCollection<CNNItem> Collection { get; set; }
}
That’s it! Now you have completed the CNNNews.cs-file. Let’s move on to the CNNItem.
In our XML-file each Item had elements for title, guid, pubDate and so on. So you now need to define them, using the [XmlElement]. If you had a XML-file with attributes you could use the [XmlAttribute]-tag.
 
The following code is pretty self explanatory, we just tell what elements we have in each Item. Remember to add the appropriate using statement again, right-click on XmlElement and select “Resolve->+ using System.Xml.Serialization”.
 
As you can see in the below code you can automatically transform the values into an integer, string, bool and so on. You could also do all of this by implementing the IXmlSerializable-interface in your class, it would also give you more control over the types.
 
CNNItem.cs
public class CNNItem
{
    [XmlElement("title")]
    public string Title { get; set; }

    [XmlElement("description")]
    public string Description { get; set; }

    [XmlElement("pubdate")]
    public DateTime Date { get; set; }

    [XmlElement("link")]
    public string Link { get; set; }
}
Now let’s head back to our MainPage.xaml.cs and write up the deserialization in our WebClient’s completed-event handler. In MainPage.xaml.cs create a new instance of the XmlSerializer and define the type, in this case we are creating a XmlSerializer for the CNNNews class. Again you’ll need to add the using the appropriate using statement by right-clicking on XmlSerializer and selecting Resolve –> + using System.Xml.Serialization
 
MainPage.xaml.cs
void Downloaded(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Result == null || e.Error != null)
    {
        MessageBox.Show("There was an error downloading the RSS-file");
    }
    else
    {
        // Deserialize if download succeedes
        XmlSerializer serializer = new XmlSerializer(typeof(CNNNews));
    }
}
Next we need to add a new reference to the project, so add System.Xml.Linq-reference in the Silverlight project (in your Solution Explorer right-click on References->Add Reference) Then create a new XML-document in C# from the downloaded xml-file and add the appropriate using statement for the XDocument.
 
MainPage.xaml.cs
void Downloaded(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Result == null || e.Error != null)
    {
        MessageBox.Show("There was an error downloading the RSS-file");
    }
    else
    {
        // Deserialize if download succeedes
        XmlSerializer serializer = new XmlSerializer(typeof(CNNNews));
        XDocument document = XDocument.Parse(e.Result);
    }
}
So we create a new instance of the XDocument and parse the e.Result, which is the downloaded data. So now we have a XDocument based on the data that we downloaded. The last thing to do is deserialize that document. So create a new instance of CNNNews and deserialize the downloaded XML with the xmlSerializer that we created earlier, note that we’ll also cast it to the CNNNews-type.
 
MainPage.xaml.cs 
void Downloaded(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Result == null || e.Error != null)
    {
        MessageBox.Show("There was an error downloading the RSS-file");
    }
    else
    {
        // Deserialize if download succeedes
        XmlSerializer serializer = new XmlSerializer(typeof(CNNNews));
        XDocument document = XDocument.Parse(e.Result);
        CNNNews news = (CNNNews)serializer.Deserialize(document.CreateReader());
    }
}
There you have it. Now inside the news-object you have deserialized CNNNews collection based on the XML-file.

Visualize the result

To see the actual albums in your user interface, you could just simply add a ListBox-control to ContentPanel inside MainPage.xaml.
 
MainPage.xaml 
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" 
                   Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" 
                   Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <ListBox x:Name="newsList"></ListBox>
    </Grid>
</Grid>
We’ll also need to create a ItemTemplate for the ListBox, so we can see the news. A simple ItemTemplate could be something like this:
 
MainPage.xaml
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <ListBox x:Name="newsList">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Margin="0,10,0,10">
                    <TextBlock Text="{Binding Title}" FontSize="24" TextWrapping="Wrap" />
                    <TextBlock Text="{Binding Date}" />
                    <TextBlock Text="{Binding Description}" FontSize="18" TextWrapping="Wrap" />
                    <HyperlinkButton Content="Read more" NavigateUri="{Binding Link}"
                                        HorizontalAlignment="Left"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>
Now the last thing to do is to bind the downloaded news to our ListBox-control named newsList. So inside MainPage.xaml.cs, after the serialization is completed just set the ItemsSource property of the ListBox.
 
MainPage.xaml.cs 
void Downloaded(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Result == null || e.Error != null)
    {
        MessageBox.Show("There was an error downloading the RSS-file");
    }
    else
    {
        // Deserialize if download succeedes
        XmlSerializer serializer = new XmlSerializer(typeof(CNNNews));
        XDocument document = XDocument.Parse(e.Result);
        CNNNews news = (CNNNews)serializer.Deserialize(document.CreateReader());

        newsList.ItemsSource = news.Collection;
    }
}

DownloadSummary

There you go! With just a few simple steps you were able to create a News-reader for CNN. Now if you create a new Windows Phone Databound application and combine it with this guide you’ll get a master/details application for your CNN Newsreader ;) As always you can download the finished project by clicking on the icon on the right.
About these ads

6 Comments on “Handling XML files on Windows Phone through deserilization”

  1. Masum Islam says:

    wonderful explanation for XML. I read few other blog before. But this one gives a crystal clear picture.I’m hope would be kind enough to make another blog for JSON. It seems JSON for WP7 is not that much available in net.

  2. Vince McGowan says:

    Very elegant – but there’s a problem with pubdate. The source element is actually pubDate and when I changed it I get an error: System.InvalidOperationException, There is an error in the XML document, “The string ‘Sat, 09 Jul 2011 12:29:03 EDT’ is not a valid AllXsd value.”

  3. [...] So, go check it out at: XML Deserialization. [...]

  4. Jeraldo says:

    can you please help me in displaying an image from an rss? its not located inside tags but instead is an tag inside of a with CDATA. please help. thanks for your tutorial.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.