RSS con XmlSerializer para ASP.NET


RSS (Really Simple Syndication) se ha convertido en el estándar de facto en Internet para la sindicación de información... ¿Sindicación de información?... dicho de otro modo, el estándar RSS propone el formato en que la información (por ejemplo las noticias de un periódico o los artículos en un blog) debe mostrarse de cara al público. No se trata más que de otro "dialecto" XML.

Por ejemplo, imaginemos que tenemos una Web con una sección sobre noticias relacionadas con las discotecas y el mundo de la noche. Por la filosofía de nuestra página, queremos compartir las noticias de modo que cualquiera pueda tener acceso a éstas sin necesidad de acceder a la Web. Para ello no tenemos más que proporcionar estas noticias en formato RSS, de modo que pueda ser leído tanto por programas lectores (llamados comúnmente agregadores) como por otros webmasters que decidan incorporar esas noticias en sus propias Webs.

Veamos, por ejemplo un trozo representativo del RSS de este mismo Blog (en el momento en que este artículo ha sido escrito):

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Subgurim.NET</title>
    <link>http://www.subgurim.net</link>
    <description>Blog ASP.NET 2.0 con C# en castellano</description>
    <ttl>1200</ttl>
    <language>es</language>
    <generator>RSS.Subgurim.NET 1.1</generator>
    <item>
      <title>Galerías de código e iconos en GoogleMaps.Subgurim.NET</title>
      <description>
        Cuerpo del artículo 1º
    </description>
      <link>http://www.subgurim.net/Articulos/asp-net-general-articulo125.aspx</link>
      <pubDate>Thu, 11 Jan 2007 12:44:46 GMT</pubDate>
      <guid>http://www.subgurim.net/Articulos/asp-net-general-articulo125.aspx</guid>
    </item>
    <item>
      <title>GoogleMaps.Subgurim.NET versión 2.0</title>
      <description>
        Cuerpo del artículo 2º
    </description>
      <link>http://www.subgurim.net/Articulos/controles-de-usuario-articulo124.aspx</link>
      <pubDate>Fri, 05 Jan 2007 20:50:08 GMT</pubDate>
      <guid>http://www.subgurim.net/Articulos/controles-de-usuario-articulo124.aspx</guid>
    </item>
  </channel>
</rss>


Con lo que vemos, podemos intuir que el formato RSS 2.0 define unos primeros campos donde se define en general al RSS para, posteriormente posteriormente definir los items bajo su campo "Item" en el que vendrá la información específica de (en nuestro caso específico) los artículos escritos en el Blog.

Para una completa especificación del formato RSS 2.0, podéis visitar http://www.rssboard.org/rss-specification. A continuación mostraremos los campos que nosotros vamos a manejar.

Elementos de Canal
Mostraremos los campos que definen al RSS en general. Los tres primero son obligatorios, el resto opcionales:
- title: Es el título que le daremos a nuestro documento RSS y con el que se dará a conocer en cualquier lector de RSS. En nuestro ejemplo es "Subgurim.NET"
- link: enlace a la página a la que se refiere el documento RSS. En nuestro ejemplo mostramos un enlace a éste Blog: http://www.subgurim.net.
- description: algo sencillito y descriptivo de lo que se puede encontrar en este RSS, como por ejemplo: "Blog ASP.NET 2.0 con C# en castellano".
- ttl: sugiere la cantidad de minutos que debería ser cacheada la información. Es como decirle al lector de RSS "en tantos minutos no suelo añadir más información, por lo que puedes dejarlo en tu cache".
- language: idioma en que está escrita la información.
- generator: el programa o algoritmo que ha creado el RSS. En nuestro ejemplo lo llamamos "rss.subgurim.net 1.1" (por poner algo ;) )

Elementos de Item
Vayamos ahora con los elementos Item. En nuestro ejemplo se trataría de los artículos
- title: título del artículo, y que será lo primero que se muestre en un lector RSS.
- link: url del artículo, de modo que desde el lector se pueda viajar hacia la fuente original del artículo.
- description: en nuestro ejemplo es el texto completo del artículo, pero habitualmente no suelen ser más que las primeras líneas. La idea es que el  que lea sobre un lector RSS se interese sobre la noticia y posteriormente enlace al artículo original mediante link.
- pubDate: representa la fecha y hora en que el artículo fue escrito. Debe estar en el formato de tipo "Fri, 05 Jan 2007 20:50:08 GMT". Esto se consigue con aplicando ToString("R") al DateTime correspondiente.
- guid: representa a un identificador global único... y aquí se acaba el estándar. Los lectores RSS lo van a ver como un string, y nosotros somos quienes nos debemos de preocupar de que este identificador sea único. Por ejemplo, yo he decidido que, dado que cada artículo representa una única URL, el guid sea esa misma url.


Como habréis visto en las especificaciones oficiales, hay más elementos de RSS, pero son opcionales y, por simplicidad, no los vamos a poner... además, tampoco hacen demasiada función ;)


La clase RSS
Ahora sólo nos queda la tarea de hacer unas clases C# que respondan convenientemente a la estructura de RSS. El fichero lo podéis descargar (el enlace está debajo del título).

En líneas generales, tenemos tres clases: RSS, RSSChannel y RSSItem.

RSS tiene un único elemento Channel, y éstetiene como propiedades los elementos de canal y un listado genérico de RSSItem. En RSSItem encontraremos las propiedades que representan los elementos del Item.


Leer y escribir RSS
En el mismo fichero de descarga habréis visto dos ficheros ".cs": RSS.cs y RSSBLL.cs

RSS.cs contiene las tres clases de las que hemos hablado. Fijaos que se han añadido algunos atributos XML a las propiedades de las clases (XmlElement, XmlRoot y XmlIgnore)... ¿qué es eso?

Para leer y mostrar el fichero RSS vamos utilizar la clase XmlSerializer, ubicada dentro del namespace System.Xml.Serialization.

XmlSerializer hace un poquito de magia, que nos facilita el trabajo tremendamente. Dándole el tipo de una clase, es capaz de mostrarnos su equivalente XML, y viceversa: rellenar una instancia de la clase a partir de un XML.

Aplicado a nuestro ejemplo, veremos que a partir de la clase RSS, el XmlSerializer lo transformará en un fichero RSS mediante su método "Serialize"; y también, a partir de cualquier fichero RSS, rellenará una instancia a un objeto RSS mediante su método "Deserialize".

¿Y cómo hace esto? XmlSerialize utiliza propiedades de refactoring, es decir, que lee los metadatos para saber el nombre de las propiedades de una clase, su tipo, etc. Y ahí viene lo que comentábamos con lo de los atributos XML (XmlElement, XmlRoot y XmlIgnore), pues de alguna forma debemos decirle al XmlSerializer que la propiedad pubdate_DateTime no la muestre por XML o que la raíz del XML es "rss" y no "RSS".

Pero lo mejor es que le echéis vosotros mismos un vistazo al código, porque, como digo siempre, un ejemplo vale más que mil palabras.

        public static void writeRSS(RSS rss)
        {
            XmlSerializer ser = new XmlSerializer(typeof(RSS));
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                using (XmlTextWriter writer = new XmlTextWriter(sw))
                {
                    writer.Formatting = Formatting.Indented;
                    ser.Serialize(sw, rss);
                }
            }

            HttpResponse response = HttpContext.Current.Response;

            response.Clear();
            response.ContentType = "text/plain";
            response.Write(sb.ToString());
            response.Flush();
            response.End();

        }

        public static RSS readRSS(string url)
        {
            RSS rss = new RSS();

            XmlSerializer ser = new XmlSerializer(typeof(RSS));

            using (XmlTextReader reader = new XmlTextReader(url))
            {
                rss = ser.Deserialize(reader) as RSS;
            }

            return rss;
        }


¡¡Absolutamente sencillo!!

Podéis hacer una prueba inmediata muy sencilla (tras importar el namespace Subgurim):

    RSSBLL.writeRSS(RSSBLL.readRSS("http://www.subgurim.net/rss/categorias.aspx"))