XMLSerializer y XML Attributes

Debido a la gran cantidad de información externa que debes tratar en tus aplicaciones, y la necesidad de llegar a un acuerdo de comunicación entre distintas tecnologías, hoy me gustaría mostrarte cómo es posible pasar información XML a objetos en .NET de una forma eficiente y clara para ti.

Para mostrar un ejemplo que está a la orden del día, he recuperado uno de mis estados de Twitter en formato XML, desde su API, para poder tratarlo y montar algunos de sus elementos en los objetos de mi aplicación.

<?xml version="1.0" encoding="UTF-8"?>
<status>
  <created_at>Mon May 24 17:24:07 +0000 2010</created_at>
  <id>14636452344</id>
  <text>Status en XML</text>
  <source>&lt;a href=&quot;http://apiwiki.twitter.com/&quot; rel=&quot;nofollow&quot;&gt;API&lt;/a&gt;</source>
  <truncated>false</truncated>
  <in_reply_to_status_id></in_reply_to_status_id>
  <in_reply_to_user_id></in_reply_to_user_id>
  <favorited>false</favorited>
  <in_reply_to_screen_name></in_reply_to_screen_name>
  <user>
    <id>51491702</id>
    <name>Gisela Torres</name>
    <screen_name>0GiS0</screen_name>
    <location>Madrid (Spain)</location>
    <description>ASP.NET, ASP.NET MVC, JQuery,C#, NHibernate, Windows Azure</description>
    <profile_image_url>http://a1.twimg.com/profile_images/881811810/Picture_7_normal.jpg</profile_image_url>
    <url>http://geeks.ms/blogs/gtorres/</url>
    <protected>false</protected>
    <followers_count>235</followers_count>
    <profile_background_color>C6E2EE</profile_background_color>
    <profile_text_color>663B12</profile_text_color>
    <profile_link_color>1F98C7</profile_link_color>
    <profile_sidebar_fill_color>DAECF4</profile_sidebar_fill_color>
    <profile_sidebar_border_color>C6E2EE</profile_sidebar_border_color>
    <friends_count>105</friends_count>
    <created_at>Sat Jun 27 17:04:48 +0000 2009</created_at>
    <favourites_count>0</favourites_count>
    <utc_offset>3600</utc_offset>
    <time_zone>Madrid</time_zone>
    <profile_background_image_url>http://a1.twimg.com/profile_background_images/60722374/free_twitter_designer.jpg</profile_background_image_url>
    <profile_background_tile>false</profile_background_tile>
    <notifications>false</notifications>
    <geo_enabled>false</geo_enabled>
    <verified>false</verified>
    <following>false</following>
    <statuses_count>1401</statuses_count>
    <lang>en</lang>
    <contributors_enabled>false</contributors_enabled>
  </user>
  <geo/>
  <coordinates/>
  <place/>
  <contributors/>
</status>

Si te fijas en la estructura que nos ofrece Twitter para representar un status, vemos que el elemento principal se trata del status en sí con una serie de elementos relacionados directamente con él y, como un conjunto, tenemos un elemento compuesto representando al usuario propietario de ese status. Como te puedes imaginar, es posible obtener claramente dos objetos bien diferenciados de esta respuesta de Twitter.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace XMLSerializer
{
    [XmlType(TypeName = "status")]
    public class Status
    {
        [XmlElement("id")]
        public long Id { get; set; }
        [XmlElement("text")]
        public string Text { get; set; }
        [XmlElement("source")]
        public string Source { get; set; }
        [XmlElement("in_reply_to_status")]
        public int InReplyToStatus { get; set; }
        [XmlElement("user")]
        public User User { get; set; }
    }
}

Crea una clase adornada con el atributo del tipo XmlType que indica el nombre del miembro que vas a almacenar en la misma. Además, decora cada una de sus propiedades con los valores correspondientes en su representación en XML. No es necesario seguir el mismo orden ni recuperar todos los elementos. Si te fijas en la propiedad User, vemos que hace referencia al elemento compuesto que vimos anteriormente y, además, que recibe y devuelve un objeto del tipo User declarado también en la aplicación.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace XMLSerializer
{
    [XmlType(TypeName = "user")]
    public class User
    {
        [XmlElement("id")]
        public long Id { get; set; }
        [XmlElement("name")]
        public string Name { get; set; }
        [XmlElement("screen_name")]
        public string ScreenName { get; set; }
        [XmlElement("location")]
        public string Location { get; set; }
    }
}

Para comprobar que estas clases son compatibles con lo establecido en formato XML, recupéralo de la siguiente manera:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
namespace XMLSerializer
{
    class Program
    {
        static void Main(string[] args)
        {
            var xml = File.ReadAllText("../../XMLs/Status.xml");
            var xmlSerializer = new XmlSerializer(typeof(Status));
            var reader = new StringReader(xml);
            var status = (Status)xmlSerializer.Deserialize(reader);
            Console.WriteLine("Status Id: {0}", status.Id);
            Console.WriteLine("Status text: {0}", status.Text);
            Console.WriteLine("Status source: {0}", status.Source);
            Console.WriteLine("Status in reply to status id: {0}", status.InReplyToStatus);
            Console.WriteLine("User Id: {0}", status.User.Id);
            Console.WriteLine("User name: {0}", status.User.Name);
            Console.WriteLine("User location: {0}", status.User.Location);
            Console.WriteLine("User screen name: {0}", status.User.ScreenName);
            Console.ReadLine();
        }
    }
}

Como ves, puedes conseguir de una forma rápida y limpia (tan sólo 4 líneas de código) la conversión de los distintos elementos en aquellos objetos que formarán parte del dominio de tu aplicación. Si lo que necesitas es un ejemplo de cómo utilizar XMLSerializer con un listado de elementos, en lugar de uno solo, puedes encontrarlo aquí.

Espero que sea de utilidad.

¡Saludos!