Crea un Lector RSS multiplataforma… con 25 líneas de código

Nuesta app de ejemplo sólo necesita consultar el URL en el que se encuentra la información (en este caso un feed RSS en formato XML de Faq-mac y que puedes adaptar a tus propias necesidades), parsear los elementos que nos interesan de la información recibida y presentarlos al usuario en un control ListBox. La interfaz de usuario se completa con un control de tipo HTMLViewer sobre el que se muestra la página web correspondiente al URL asociado con cada una de las entradas presentadas en el ListBox. Sencillo, ¿verdad?

Para realizar este tutorial necesitarás descargar e instalar en tu equipo el IDE de Xojo. Recuerda que es gratuito para aprender y hacer todas las pruebas que quieras. Para compilar y distribuir tus productos finales necesitarás una licencia. Puedes descargar Xojo desde aquí.

Descarga el proyecto Xojo de este tutorial con todo el código fuente desde este enlace.

HTTPSocket: uso del protocolo HTTP 1.1

El elemento principal de esta aplicación consiste en una clase derivada (subclase) de HTTPSocket, de modo que añadiremos el comportamiento especializado que esperamos de un parseador RSS al que se obtiene por omisión con dicha clase. De hecho esta nueva subclase será la responsable de contener la mayoría del código necesario en este tutorial.

Tal y como indica la documentación de Xojo sobre HTTPSocket, dicha clase permite recibir y enviar información mediante el protocolo HTTP. Así, usando simplemente una nueva instancia (objeto) creada a partir de dicha clase, podremos obtener los datos XML correspondientes a un feed RSS mediante el uso del método Get al que pasaremos el URL en cuestión (como por ejemplo el feed RSS de Faq-mac.com):

Dim http as new HTTPSocket
dim feedXML as string = http.get("https://www.faq-mac.com/feed/“, 30)

Como puedes observar, el método get acepta dos parámetros. El primero de ellos es siempre el URL del que deseamos obtener los datos, mientras que el segundo parámetro es opcional y nos permite indicar el timeout o tiempo de espera máximo para la operación. Si no indicamos dicho valor, la instancia esperará de forma indefinida hasta que se reciban los datos o bien hasta que se produzca un error.

Tanto si hacemos uso del parámetro de timeout como si no, en ambos casos estaremos empleando el método de forma síncrona. Esto significa que el programa no proseguirá con la siguiente línea de código hasta que se hayan recibido los datos devueltos por el método Get.

Para que la clase HTTPSocket funcione en modo asíncrono (es decir, que el programa continúe con su ejecución normal una vez se lance la petición ‘Get’), es preciso crear una subclase de HTTPSocket y no pasar ningún valor de tiempo de espera. En este caso, los datos recibidos por la petición se obtendrán en el evento PageReceived.

Esta será precisamente la fórmula que utilizaremos en este tutorial, poniendo así en práctica también el modo en el que podemos comunicar la finalización de un proceso a otro objeto mediante un patrón de diseño tipo Observador; aunque en este caso limitaremos la suscripción a un único objeto. Para ello nos ayudaremos de una Interface de Clase.

Interfaz de clase RSS: RSSReaderDelegate

Comenzaremos precisamente creando la Interface de Clase responsable de definir el método a implementar por cualquier objeto que quiera ser tratado también como un ‘RSSReaderDelegate’. Ten en cuenta que Xojo es un lenguaje de programación de tipado fuerte y que esta, y otras muchas cuestiones, son las que se explican con todo detalle en mi libro “Programación Multiplataforma Xojo”.

  1. Una vez hayas creado un nuevo proyecto de tipo Desktop, selecciona Insert > Class Interface. En el panel Inspector resultante, introduce ‘RSSReaderDelegate’ en el campo Name.
  2. A continuación, selecciona el nuevo elemento creado RSSReaderDelegate en la columna del Navegador de Proyecto. Con dicho elemento seleccionado, elige la opción Insert > Method del menú.
  3. En el panel Inspector resultante, introduce ‘refresh’ como nombre del nuevo método, e introduce ‘items() as pair’ en el campo de Parámetros.

Ajustes de Interfaz de clase en Xojo

 

Creando nuestra clase RSS: RSSReader

Es el momento de crear la subclase que hará las funciones de obtener los datos XML correspondientes a la fuente RSS que le pasemos y, una vez descargados, parsearlos o “tratarlos” para quedarnos sólo con la información que nos interesa.

En este tutorial, solo nos quedaremos con el título de cada entrada y el URL asociado. De este modo, cuando posteriormente el usuario seleccione cada una de las entradas podremos mostrar el artículo completo accediendo a la página web donde se encuentre publicada la entrada en cuestión.

Una vez que compruebes la mecánica que se lleva a cabo para el procesado, no te costará mucho adaptarlo y ampliarlo para que, por ejemplo, también se parsee la información correspondiente a la descripcion, contenido o cualquier otro de los elementos encontrados en el formato RSS.

  1. Crea una nueva clase (Insert > Class) y escribe ‘RSSReader’ en el campo ‘Name’
  2. A continuación añade ‘HTTPSocket’ en el campo ‘Super’. Con ello estaremos indicando que RSSReader es una clase derivada (subclase) de HTTPSocket, heredando por tanto todas sus propiedades, métodos y eventos.
  3. Selecciona ahora el icono correspondiente a nuestra nueva clase RSSReader en el Navegador de Proyecto y añade una nueva Propiedad (Insert > Property). En el panel Inspector resultante, introduce ‘rssReaderDelegate’ en el campo ‘Name’, ‘RSSReaderDelegate’ en el campo Type (observa que se corresponde con la interface de clase creada en el punto anterior), y con el ámbito (scope) definido como privado. Esta será la propiedad encargada de contener el objeto sobre el que se ejecutará el método ‘Refresh’ una vez que se haya completado la descarga y extracción de los elementos del feed RSS.
  4. De hecho añadiremos a continuación una segunda propiedad, utilizando en este caso ‘items(-1)’ en el campo ‘Name’, definiendo su tipo de dato como ‘pair’ y manteniendo el ámbito en Privado. Este será el array encargado de almacenar todos los elementos que hayamos extraido del feed, y que se pasará posteriormente en la llamada al método ‘Refresh’ del objeto que se haya registrado.

Podríamos haber creado una ‘Computed Property’ (Propiedad Calculada) para asignar el objeto a la propiedad ‘RSSReaderDelegate’, pero en esta ocasión utilizaremos un método estándar. Si lo deseas puedes hacer dicha variación como ejercicio. Entre tanto, crearemos el método encargado de realizar dicha asignación:

  1. Con el icono de nuestra clase RSSReader seleccionado en el Navegador de Proyecto, utiliza la opción Insert > Method y escribe ‘setDelegate’ como nombre del método, introduciendo ‘objectDelegate as RSSReaderDelegate’ en el área de texto reservada a los parámetros. Introduce la siguiente línea de código en el Editor de Código resultante:
rssReaderDelegate = objectDelegate

Añadir evento PageReceived

Es el momento de comenzar a dotar a nuestra clase de su funcionalidad propiamente dicha, y lo haremos añadiendo el Evento que se dispara cuando la clase HTTPSocket y cualquiera derivada de ella, como es nuestro caso, recibe los datos correspondientes al URL indicado.

Asegúrate de que está seleccionado el icono correspondiente a nuestra clase RSSReader en el Navegador de Proyecto y, seguidamente, elige la opción Insert > Event Definition en el menú. En la hoja resultante, selecciona la entrada PageReceived. Al hacerlo comprobaras que Xojo te proporciona una descripción con su funcionalidad; es decir, bajo qué casos se dispara y ejecuta el código asociado. Confirma la selección.

En el caso de que no esté seleccionado el evento recién añadido, selecciónalo en el Navegador de Proyecto e introduce el siguiente fragmento en el Editor de Código resultante:

if httpStatus = 200 then
        content = DefineEncoding(content, encodings.UTF8)
        parseNodes(content)
        if rssReaderDelegate <> nil then rssReaderDelegate.refresh(items)
end

Como puedes observar en la parte superior del Editor de Código, con PageReceived seleccionado, cuando se dispara dicho evento lo hace proporcionándonos una serie de parámetros. Por ejemplo, en la variable ‘url’ tendremos la URL original indicada por nosotros, la variable ‘httpStatus’ contendrá el código de estado resultante de la operación (definidos por el estándar HTTP), en la variable ‘headers’ hallaremos las cabeceras proporcionadas por el servidor remoto al entregar los datos solicitados por nuestro URL, y en la variable ‘content’ obtendremos finalmente los datos producto de nuestra petición.

De este modo, lo primero que hace nuestro fragmento de código no es otra cosa si no comprobar que no se ha producido ningún error, lo que equivale al número 200 en la variable ‘httpStatus’.

A continuación también nos encargamos de asignar al contenido recibido en la variable ‘content’ la codificación de texto con la que deseamos trabajar, y que no es otra si no la más común actualmente (UTF8). Esto nos permitirá posteriormente manipular dicho contenido sin que sea vean alterados los caracteres acentuados u otros símbolos especiales que se encuentren más allá del limitado ASCII estándar.

Precisamente la siguiente línea es la que se encarga de llamar a un método de la clase que aun no hemos definido: ‘parseNodes’, pasando como argumento el contenido recibido. Aquí es donde se realiza realmente el trabajo de trabajar con el formato XML correspondiente al feed RSS solicitado y de extraer solamente aquellos elementos en los que estamos interesados: título y URL para cada uno de los elementos.

Finalmente, se comprueba que la propiedad ‘rssReaderDelegate’ contenga un objeto válido y, de ser así, se llama a su método ‘refresh’ pasando como argumento todos los elementos que se hayan extraído al tratar el feed RSS.

XMLDocument y XPath

Añadamos pues el método ‘ParseNodes’, introduciendo ‘content as String’ en el área del Inspector reservada a los parámetros y marcando el ámbito como Privado. Después de todo, se trata de un método que se utilizará desde dentro de la clase, impidiendo así que pueda invocarse desde cualquier otro objeto. En el Editor de Código resultante introduciremos el siguiente código:

dim xml as new XmlDocument(content)
dim nodes as XmlNodeList = xml.Xql("//item")

dim title, url as string

for n as integer = 0 to nodes.Length - 1

    title = nodes.item(n).Xql("title").Item(0).firstChild.value
    url = nodes.item(n).Xql("link").Item(0).firstChild.value

    items.Append( new pair( title, url ) )

next

En el extenso y potente framework de Xojo encontramos una clase XMLDocument que nos permite recorrer y editar con facilidad cualquier archivo o conjunto de datos que se correspondan con una estructura XML válida, y los feed RSS lo son.

La potencia de las clases relacionadas con el tratamiento de XML por parte de Xojo queda patente cuando utilizamos el XPath (1.0) para realizar consultas, de modo que en este caso sólo hemos de emplear la expressión “//item” en combinación con el método Xql, para obtener con una única instruccion un listado con todos los nodos del documento XML correspondientes a los items del feed RSS recibido (estos son los elementos o nodos definidos por el par <item> </item> en el estándar para archivos RSS).

Por tanto, posteriormente solo hemos de recorrer dichos nodos mediante un bucle de tipo ‘For… Next’ estándar, dado que la clase XMLNodeList no implementa la interfaz Iterable.

Como se puede observar, en el cuerpo del bucle volvemos a utilizar consultas ‘Xql’ para acceder a los nodos correspondientes al título (<title </title>) y enlace (<title> </title>) para cada una de las entradas del canal RSS, almacenando el resultado como strings en sendas variables declaradas previamente. Esto es lo que logramos accediendo a la propiedad ‘value’ del nodo hijo (firstChild).

Por último añadimos tanto el título como el URL de cada una de las entradas en un nuevo tipo de dato ‘Pair’ y lo añadimos en el array. En este caso las entradas más recientes ocuparan las posiciones más bajas del array.

Diseñar la interfaz de usuario

Con nuestra clase RSSReader completada, es el momento de diseñar la interfaz de usuario. Será muy sencilla, pero suficiente para ver nuestro ejemplo en acción. Para comenzar selecciona el control Window1 que se añade por omisión con cada nuevo proyecto de escritorio. A continuación arrastra sobre el Editor de Diseño un control ListBox y un HTMLViewer de modo que su disposición tenga un aspecto similar al mostrado en la imagen.

Observa especial atención para que cada uno de los controles tenga los ajustes del apartado ‘Locking’ (bloqueo) que se muestra bajo ellos. Este es el apartado del Inspector que permite anclar cada uno de los márgenes del control sobre los mismos márgenes del control que lo contiene, en este caso la ventana.

Añadir conformidad con RSSReaderDelegate

Las Interfaces de Clase son en Xojo el modo en el que podemos hacer que un mismo objeto pueda presentarse como si fuera dos o más tipos de datos a la vez. En este caso, por ejemplo, haremos que la ventana, Window1, mantenga su tipo de dato nativo como instancia que es de la clase Window pero que también responda como si fuera un RSSReaderDelegate, la Interfaz de Clase definida en el primer punto. Para ello añadiremos la conformidad con dicha interfaz. ¿Cómo? Sencillo.

Selecciona el elemento Window1 en el Navegador de Proyecto y pulsa a continuación sobre el botón ‘Choose…’ en el panel Inspector. Como resultado de la acción se abrirá una hoja que lista todas las Interfaces de Clase disponibles, incluyendo la definida por nosotros.

Recorre el listado hasta encontrarla, teniendo en cuenta que se presentan por orden alfabético. Selecciónala y pulsa sobre el botón Ok. Como resultado comprobarás que se añade automáticamente el método definido por la Interfaz de clase y, de hecho, se activará el Editor de Código correspondiente a dicho método —refresh( items() as Pair )—. Recuerda que este es el método que llamará nuestra clase RSSReader una vez que haya finalizado de extraer y procesar las entradas encontradas en el canal RSS descargado desde el URL que indiquemos.

Introduce el siguiente fragmento de código:

Listbox1.DeleteAllRows
for each item as pair in items
   Listbox2.AddRow item.Left.StringValue
   listbox2.RowTag(Listbox2.LastIndex) = item.Right.StringValue
next

La implementación del método consiste en borrar todas las entradas del listado (control ListBox1) y añadir posteriormente las recibidas en el array ‘items’. En este caso utilizamos el truco de asociar el URL (parte derecha del elemento Pair) en la propiedad RowTag de la fila correspondiente a la entrada que se esté añadiendo. Es una práctica bastante común para guardar valores asociados que no queremos que se vean y que, en este caso, nos permitirá acceder posteriormente al URL de la entrada cuando el usuario seleccione cualquiera de los elementos del listado.

Mostrar una página web en HTMLViewer

De hecho esto es lo que haremos a continuación. Selecciona el control ListBox1 en el Navegador de Proyecto y añade el Evento Change. La única linea de código que tendrás que incluir como respuesta de dicho evento es la siguiente:

if me.ListIndex <> -1 then HTMLViewer1.LoadURL me.RowTag(me.ListIndex)

Como puedes observar indicamos al control HTMLViewer1 que cargue el URL que recuperamos desde la propiedad RowTag correspondiente a la fila que estamos seleccionando. Algo destacable en este caso es que el control HTMLViewer no requiere de una sola línea de código para proporcionar su funcionalidad.

Evento Open: poner todo en marcha

Ya solo nos queda añadir una propiedad sobre la instancia Window1 y que será la responsable de almacenar la instancia que creemos desde nuestra clase RSSReader. Por tanto, selecciona Window1 en el Navegador de Proyecto y elige Insert > Property. En el panel Inspector resultante, utiliza ‘myRSSReader’ como nombre de la propiedad, introduciendo ‘RSSReader’ en el campo de Tipo.

Por último, añade el evento Open en Window1 con el siguiente código:

myRSSReader = new RSSReader
myRSSReader.setdelegate me

myRSSReader.get( "http://www.aprendexojo.com/feed/" )

Como puedes ver, creamos una nueva instancia de nuestra clase RSSReader y la asignamos a la propiedad recién creada. En la siguiente línea asignamos Window1 como el objeto al que ha de llamar la instancia de RSSReader una vez que finalice su tarea y, por último, utilizamos el método Get sobre la instancia para obtener el feed XML correspondiente al canal RSS de AprendeXojo. Una vez que se ejecute dicha línea de código, ¡el resto va solo! (siempre que dispongamos de conexión a Internet, claro).

Conclusión

En este tutorial hemos visto como es posible crear los alambres de una aplicación lectora de canales RSS ¡en tan solo 25 líneas de código! Evidentemente se han dejado fuera algunas cuestiones como comprobación de errores y otras cuestiones para que el tutorial sea lo más contenido posible. ¡Fácil, rápido, multiplataforma y nativo!

Este tutorial también nos ha servido como punto de introducción a dos clases realmente potentes: XMLDocument y el uso de las expresiones regulares mediante RegEx, sobre las que te animo que eches un vistazo más en detalle y que aprovecehes en el diseño de tus propias aplicaciones.

Javier Rodríguez

Javier Rodríguez (@bloguintosh) es desarrollador y autor del eBook "Programación Multiplataforma Xojo". Puedes contactar con él para el desarrollo de aplicaciones y soluciones multiplataforma, así como consultoría y formación en www.aprendexojo.com

0 0 votos
Article Rating
Subscribe
Notify of
0 Comments
Opiniones Inline
Ver todos los comentarios

Lost your password? Please enter your email address. You will receive mail with link to set new password.

wpDiscuz
0
0
Me encantaría saber tu opinión, por favor, deja un comentariox
()
x
Salir de la versión móvil