Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

Converting XML Data to CLR Object using XmlSerializer

5.00/5 (1 vote)
12 Apr 2011CPOL5 min read 15.3K   136  
How to convert the XML to a CLR object and use it as a datasource in a Silverlight app

Introduction

My last post (Consuming a WebService from Silverlight) was all about accessing a Web Service/API from Silverlight. In the article, I described how to consume an external API, with a sample from the GeoName Web Services. This post is a continuation of that article. Here, I am going to demonstrate how to convert the result output, which is in XML, to a CLR object, and of course use it as a datasource in a Silverlight app.

Source Code and Links

GeoSearch, the Example Project

GeoName is a provider of various Web Services/API, exposing information about geographic details of places. You can visit the website here. Using their service, I am going to design a search page where the user can get the geo details based on the name.

GeoSearch

On accessing the service URL (http://api.geonames.org/search?q=orissa&username=demo), it returns a set of data in XML format. Let's take a look at the XML file. You can try the same service URL in your browser and check the XML file.

GeoSearch

In my last post, I had mentioned this result XML can be parsed in a Silverlight project using any of the methods mentioned below:

  • Using XmlReader
  • Using XLINQ
  • Using XmlSerializer

As XmlReader and XLINQ are quite straightforward, I am going to skip them for the time being, but you can take a look into those topics from these links: parsing XML with Xlinq, XmlReader. This post describes how to deserialize the XML file to a collection of CLR objects using the XMLSerializer class and attributes.

A Little Bit About System.Xml.Serialization

This namespace contains classes and attributes that allow us to convert an object to XML and vice versa. Attributes can be defined against CLR object members for serializing and deserializing. This MSDN resource will give you a detailed insight about the namespace. As this post is concerned about converting XML to CLR objects, let's focus on that.

Project GeoSearch

Converting XML to objects basically involves three steps:

  1. Create the schema/class from XML
  2. Apply attributes to the members of the generated class
  3. Use the XMLSerializer class to deserialize it

1. Create the Schema /Class from XML

Using VS2010, create an XML schema over the XML result file.

image

To generate the class structure from the schema, I am going to use the XSD2CODE tool available at CodePlex (http://xsd2code.codeplex.com/). Once installed, select your generated schema file in Solution Explorer and run Code Generator.

image

This way, you will be able to generate the skeleton of classes and members based on the supplied XML schema. But as we don't want our class/property name to be the same as that generated by the tool, let's change that. By modifying some member names of the generated classes, the output (by default, the names will be based on the tag and element names of XML) will be as below:

C#
namespace GeoSearch 
{ 
    /// <summary> 
    /// Class For geonames 
    /// class containing the collection of location 
    /// </summary> 
    public partial class Location 
    { 
        public ushort totalResultsCount { get; set; } 
        public List<GeoDetail> GeoDetails { get; set; } 
        public string style { get; set; } 
    } 

    /// <summary> 
    /// Class For geoname 
    /// Details about each location 
    /// </summary> 
    public class GeoDetail 
    { 
        public string toponymName { get; set; } 
        public string name { get; set; } 
        public decimal lat { get; set; } 
        public decimal lng { get; set; } 
        public uint geonameId { get; set; } 
        public string countryCode { get; set; } 
        public string countryName { get; set; } 
        public string fcl { get; set; } 
        public string fcode { get; set; } 
    } 
}

2. Apply Attributes to the Members of the Generated Class

As you will notice, I have changed the class name of both the generated classes. By doing so, I have to add some attributes to the class so that it can relate itself to the XML. Let's compare the XML and the class side by side and map the elements to the class.

GeoSearch

The XMLRoot attribute directs the deserialization process saying that Location targets the geonames root of the XML. Similarly, for the GeoDetail class. Now we will have a look at the Location class. Structuring the class as per the XML, Location is going to have a collection of GeoDetails (geoname in the XML), and an attribute of XMLElement specifying the name of the element in XML. One point should be kept in mind: if the class and its members carry the same name as the XML root and element, then there is no need for adding extra attributes.

More details about attribute uses on a case based scenario can be found here: MSDN.

3. Using the XmlSerlizer Class to Deserialize It

C#
string baseServiceURL = @"http://api.geonames.org/search?q={0}&username=demo"; 
public MainPage() 
{ 
    InitializeComponent(); 
} 
private void btnCallService_Click(object sender, RoutedEventArgs e) 
{ 
    //Check For Empty Text value 
    if (String.IsNullOrWhiteSpace(txtPlace.Text)) 
    { 
        MessageBox.Show("Provide a location name for result"); 
        return; 
    } 
    WebClient client = new WebClient(); 
    //Apply Callback 
    client.OpenReadCompleted += (s, ev) => 
    { 
        XmlSerializer serializer = new XmlSerializer(typeof(Location)); 
        try 
        { 
            Stream stream = ev.Result; 
            Location Loc = (Location)serializer.Deserialize(stream); 
            lstSearchResult.ItemsSource = Loc.GeoDetails; 
            lblNoOfRows.Content=string.Format("About {0} results ", 
                        Loc.totalResultsCount.ToString()); 
        } 
        catch (Exception exp) 
        { 
            MessageBox.Show(exp.InnerException.Message); 
        } 
        finally 
        { 
            biSearch.IsBusy = false; 
        } 
    }; 
    string serUrl = String.Format(baseServiceURL, txtPlace.Text); 
    biSearch.IsBusy = true; 
    client.OpenReadAsync(new Uri(serUrl)); 
    } 
}

For sending and receiving data on the web, Silverlight exposes the classes WebClient and HTTpWebrequest. Both use basic GET and POST based verbs for retrieval and invocation. As compared to HTTPWebRequest, WebClient is quite simple and straightforward, and supports event based callbacks. However, HttpRequest is more suitable for advanced REST service calls allowing more control over an HTTP request.

The XmlSerializer class in the System.Xml.Serialization namespace has methods responsible for converting plain XML to objects. In this example, we are creating an instance of XmlSerlizer with a Location type as the constructor says the type of object it is going to operate it Location.

image

Once the OpenReadAsync operation completes, the results are taken into a stream and passed to the Deserialize methods for conversion.

Assign the Data Source and Let's Run …

The code above is ready to return a collection of GeoDetails which we have assigned to the list box with a defined DataTemplate. The ItemTemplate for the list box is quite simple with a XAML based declarative binding expression.

image

Hooo.. Now it's ready to go live. Take a look at a working demo with the link below.

Conclusion

The strongly typed XML with objects and serialization gives the application the power of transportability although it comes with a bit of extra effort in the initial stage of development. Still, there is lot more to be rediscovered and more complex XML format can be handled. That’s all for this time. Keep learning. I will BRB.

Source Code and Links

License

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