Xojo: Crea un lector RSS… ¡en 33 líneas de código!

En este tutorial veremos lo sencillo que resulta crear un lector de RSS para equipos de escritorio con Xojo (macOS, Windows y Linux), utilizando para ello un total de tan sólo 33 líneas de código… ¡y lo que ya encontramos hecho gracias a las capacidades del framework de Xojo!

Para crear una aplicación de escritorio sencilla de lector RSS multiplataforma sólo necesitaremos realizar cuatro pasos generales, por así decirlo; creando una aplicación capaz de acceder al URL indicado, obtener la información encontrada en dicho URL (en este caso un feed RSS en formato XML), 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.

URLConnection: uso del protocolo HTTP

El elemento principal de esta aplicación consiste en una clase derivada (subclase) de URLConnection, 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 URLConnection, 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 Send al que pasaremos el “Método” —Get en este caso— y el URL en cuestión (como por ejemplo el feed RSS de AprendeXojo.com):

Var http As New URLConnection
Var feedXML As String = http.Send("GET", "https://www.aprendexojo.com/feed/“)

Como puedes observar, el método Send acepta dos parámetros obligatorios. El primero de ellos es el método que queremos utilizar (pueden ser “Get” o “Post”), mientras que el segundo se corresponde con el URL del que deseamos obtener los datos, mientras que el tercer parámetro es opcional y nos permite indicar el timeout o tiempo de espera máximo para la operación (por omisión, 60 segundos).

Tanto si hacemos uso del parámetro de timeout como si no, en ambos casos estaremos empleando el método de forma asíncrona. Esto significa que el programa proseguirá con la siguiente línea de código y no interrumpirá la interacción del usuario.

Una vez que la clase URLConnection complete la petición en modo asíncrono, recibiremos la información solicitada a través del evento (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 ContentReceived.

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 la instancia creada a partir de nuestra clase mediante la creación de nuestro propio manejado de evento.

Creando nuestra clase: 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 ‘URLConnection’ en el campo ‘Super’. Con ello estaremos indicando que RSSReader es una clase derivada (subclase) de URLConnection, heredando por tanto todas sus propiedades, métodos y eventos.
  3. Añade a continuación una propiedad, utilizando ‘items(-1)’ en el campo ‘Name’, definiendo su tipo de dato como ‘pair’ y manteniendo el ámbito en Publico. 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.

Con el icono de nuestra clase RSSReader seleccionado en el Navegador de Proyecto, utiliza la opción Insert > Method y escribe ‘GetFeed’ como nombre del método, introduciendo ‘url As String’ 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:

If url <> "" Then Me.Send("Get",url)

Añadir evento ContentReceived

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 URLConnection 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 ContentReceived. 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)
  RaiseEvent 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), 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 tratar 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, invocaremos nuestro propio manejado de evento pasando la información ya tratada. Esta es la forma que tenemos para que una clase pueda “comunicarse” con las instancias creadas a partir de ellas. Es una forma de romper la dependencia entre una clase y sus instancias. Por ejemplo, cuando la instancia implemente este manejado de evento tendrá la libertad de poder actuar sobre el resto de componentes de la interfaz de usuario o código (métodos) del proyecto.

Por tanto, definamos el manejador de eventos “Refresh” en nuestra clase. Con el elemento de nuestra clase RSSReader seleccionado en el Navegador de proyectos, utiliza el menú contextual para seleccionar la opción Add to “RSSReader” > Event Definition. En la paleta inspector resultante, introduce “Refresh” en el campo “Event Name” y “items() as Pair” en el campo “Parameters”. ¡Así de simple!

XMLDocument y XPath

Añadamos ahora 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:

Try
  Var xml As New XmlDocument(content)
  If xml <> Nil Then 
    Var nodes As XmlNodeList = xml.Xql("//item")
    Var 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
  End If
Catch e As XmlException
  MessageBox e.Reason
End Try

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 sobre 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.

También verás en la parte inferior del Editor de Diseño que hemos añadido una instancia de nuestra clase al “Tray”. Esto es tan simple como arrastrar el elemento RSSReader del navegador de proyecto y soltarlo sobre esta área del Editor de Diseño y… voilà, ya tenemos una instancia lista para usar!

Añadir manejador de Evento Refresh a la instancia

Una vez realizado lo anterior, verás que se ha añadido el nuevo elemento “RSSReader1” al navegador de proyecto. Selecciónalo y elige la opción Add to “RSSReader1” > Event Handler. Selecciona el manejado de evento “Refresh” en la ventana resultante e introduce las siguientes líneas de código. Estas serán las encargadas de actualizar el listado con las entradas ya parseadas del RSS:

Listbox1.RemoveAllRows

For Each item As pair In items
  Listbox1.AddRow item.Left.StringValue
  listbox1.RowTagAt(Listbox1.LastAddedRowIndex) = 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 SelectionChanged. Las únicas lineas de código que tendrás que incluir como respuesta de dicho evento son las siguiente:

If Me.SelectedRowIndex <> -1 Then HTMLViewer1.LoadURL me.RowTagAt(me.SelectedRowIndex)

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 Opening: poner todo en marcha

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

RSSReader1.GetFeed("https://blog.xojo.com/feed" )

Como puedes ver, indicamos a la instancia que hemos añadido al proyecto que cargue el URL correspondiente al feed del Blog de Xojo. ¡Eso es todo lo que hemos de hacer! Una vez que se reciban los datos de forma asíncrona y se hayan parseado, será nuestra clase quien los pase a la instancia mediante el disparo del evento correspondiente.

Conclusión

En este tutorial hemos visto como es posible crear los alambres de una aplicación lectora de canales RSS ¡en tan solo 33 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.

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.

Como de costumbre, ¡espero tus comentarios!

6 comentarios en “Xojo: Crea un lector RSS… ¡en 33 líneas de código!

  1. Vince

    Hola Great rss reader. I have a problem, keep getting error when I work in my own projects.

    http://francia.dk/wp-content/uploads/2015/12/error.png

    1. Javier Rodriguez

      Hi Vince,

      myRSSReadder expects a delegate that full fit to RSSReaderDelegate Interface contract, so… you have to implement such interface on Window1.

      Please, refer to the example code listed on the original post, where you can see that the “Window1” object has implemented that interface (Inspector Panel > Interfaces).

      Please, let me know if this solves your problem or if you need further help.

      Thank you!

      Javier

  2. Kaliche Rodriguez

    Hola Sr. Javier.
    Muy interesante tu lector rss.
    Muchas gracias por ese aporte.
    He descargado el proyecto y al correrlo, la app arranca y trata de cargar, pero no aparece ningun dato en la Listbox ni muestra la pagina referida en el HTML.
    Que sera?
    Nuevamente, muchas gracias por compartir tus conocimientos.

    1. Javier Rodriguez

      Hola Kaliche,

      Desde la publicación del artículo se han producido muchos cambios en muchas cosas… y probablemente tenga que ver con el hecho de que ahora la mayoría de los accesos se realizan de forma segura (HTTPS). Si me pasan un enlace de la fuente del RSS al que intentas acceder podría echarle un vistazo…

      Javier

  3. Kaliche Rodriguez

    Sr. Javier
    Muchas gracias por responder.
    las fuentes a las que quiero acceder son las mismos que tiene el demo.
    myRSSReader.get(“http://appleinsider.com/rss/news/”) .
    ah… y tambien lo ensaye de forma segura agregando la “s”, asi…
    myRSSReader.get(“https://appleinsider.com/rss/news/”)y tampoco arranco
    atte kaliche
    xojo 2016r1.1

  4. Kaliche Rodriguez

    Sr. Javier
    Muchas gracias de antemano, por responder.
    Mi asunto es sobre browsers.

    Estoy tratando de crear un pequeño web browser dentro de mi aplicacion.
    He hecho pruebas con el HTMLvewer usando el render nativo el webkit,y tambien con el Microsoft Web Browser(Shell.Explorer), pero han quedado limitados para lo que necesito. Asi que quiero ver si puedo implementar la posibilidad con MozillaBrowser.

    Para hacerlo he hecho lo siguiente…

    *** new project
    *** insert activeX component
    *** seleciono MozillaBrowser Class (MozillaBrowser) en la ventana COM components
    *** arrastro el icono del MozillaBrowser1 a la ventana
    *** En un PushButton coloco el code:
    MozillaBrowser1.Navigate(“http://www.mozilla.org/”)
    *** Produce un error…

    An exception of class COM.COMEsception was not handled
    Exception Message: Failed on Navigate
    Exception Error Number: -2147352567.

    Como puedo hacer que funcione y utilizar todas las funciones de este MozillaBrowser?

    Es necesario que Mozilla FireFox esté instalado en el PC, para que la aplicacion funcione?
    Muchisimas Gracias.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *