Hasta ahora no había realizado más que pequeñas pruebas de LINQ, pero recientemente he cambiado de proveedor de hosting (al de momento magnífico discountASP) que ya proporciona soporte para .NET 3.5 y me he decidido a usarlo un poco más.
En concreto he creado una nueva página de links, donde he puesto de momento los links que tengo alojados en del.icio.us y mis elementos compartidos de Google Reader, que es el lector RSS que utilizo.
Tanto del.icio.us como Google Reader proporcionan acceso a los elementos públicos mediante una URL que ofrece un documento RSS en el primer caso (http://del.icio.us/rss/amezcua) y un documento ATOM en el segundo (http://www.google.com/reader/public/atom/user/06770480527490995101/state/com.google/broadcast).
Teniendo esto en cuenta, el funcionamiento de la página es realmente sencillo. Sin entrar en detalles los pasos realizados son:
1º Al cargar la página se obtiene un documento XML a partir de la URL para cada uno de los documentos anteriores. Esto es tan sencillo como:
XDocument xmlDoc = XDocument.Load(urlServicio);
2º Una vez se dispone del documento se obtiene, mediante una consulta LINQ, una colección de elementos extrayendo los datos deseados del XML original. Por ejemplo, para el caso de del.icio.us se quiere obtener una colección de objetos con dos campos, ‘title’ y ‘url’:
var itemList = from item in xmlDoc.Descendants(«{http://purl.org/rss/1.0/}item»)
select new
{
title = (string)item.Element(«{http://purl.org/rss/1.0/}title»),
url = (string)item.Element(«{http://purl.org/rss/1.0/}link»)
};
3º Cuando se tiene la colección creada (itemList) se puede utilizar DataBinding para vincular esta lista de elementos a cualquier control. En mi caso lo he vinculado a un control DataList. En el control DataList simplemente se especifica que se quieren mostrar los campos ‘title’ y ‘url’ definidos antes:
dlDelIcioUsItems.DataSource = itemList;
dlDelIcioUsItems.DataBind();
Como se puede ver hay, sin contar el control de errores, 4 líneas de código para cargar un documento XML remoto y mostrarlo en una página Web, bastante impresionante, teniendo en cuenta que para hacer algo similar hasta ahora lo que hacía era disponer de una clase que defina la estructura del documento, cargar el XML remoto en un XmlReader, deserializar el documento a la clase y finalmente obtener la colección de items interna de esa clase.
Una de las cosas que hay que destacar es el uso de los namespaces de XML. Como se ve en la consulta LINQ, para acceder a cada uno de los elementos del documento hay que especificar el namespace XML en el que se encuentra
{http://purl.org/rss/1.0/}
lo que define completamente al elemento XML concreto. Esta sintaxis, tal como está en el ejemplo, no me acaba de gustar, así que se puede mejorar de la siguiente forma:
XNamespace deliciousNS = «http://purl.org/rss/1.0/»;
var itemList = from item in xmlDoc.Descendants(deliciousNS + «item»)
select new
{
title = (string)item.Element(deliciousNS + «title»),
url = (string)item.Element(deliciousNS + «link»)
};
En este caso se define un objeto XNamespace con el namespace adecuado y se utiliza en todos aquellos sitios donde se necesite especificar el nombre completo del elemento. Como el tipo XNamespace sobrecarga el operador ‘+’ se puede usar simplemente añadiendo entre comillas el nombre del elemento XML. Esto no se encuentra en la mayoría de los ejemplos publicados por ahí sobre LINQ to XML, donde se utilizan documentos XML sin definición de namespaces, cosa que no es muy habitual en el mundo real ¿no?