Cómo recibir el RSS de los posts de un blog en wordpress

En esta entrada les comparto cómo hacer un pedido de feeds de sitios que usan
cómo sindicación RSS 2.0. Para el caso concreto lo que yo necesitaba era recibir
de un blog de wordpress las últimas entradas, con el fin de poderlas mostrar en
algún recurso web o una aplicación de escritorio.

Dado a que wordpress lo único que nos ofrece es una url de donde jalar los feeds
de RSS de cada blog, en lugar de ofrecer alguna manera "sexy" de hacer algo cómo:

WordpressRSS wordpressRSS = new WordpressRSS("http://ummestesimon.wordpress.com");
List<WordpressPost> postList = wordpressRSS.getPosts(3);
for(WordPressPost wpp : postList){
----System.out.println(wpp.toString());
}

Nosotros tenemos que procesar tremendo XML enviado por el binding de sindicación
RSS que wordpress nos ofrece. Pero, ¿cómo lo ofrece wordpress?, es simple, cada sitio
con wordpress cuenta con una URL que nos da esa sindicación y eso basta con agregar
"/feed/", por ejemplo, si quieren acceder a la sindicación de mi blog ustedes pueden
probar en su navegador con: http://ummestesimon.wordpress.com/feed/ . Debido a que
los exploradores modernos saben que es un archivo RSS, pues nos lo muestra de una
manera bonita y entendible; pero para darnos una idea de que es lo que nos muestra
podemos usar alguna utilerí­a cómo curl. Si damos en nuestra terminal

curl <a href="http://ummestesimon.wordpress.com/feed" title="http://ummestesimon.wordpress.com/feed">http://ummestesimon.wordpress.com/feed</a>

veremos muchas lí­neas cómo las siguientes:

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
        xmlns:content="http://purl.org/rss/1.0/modules/content/"
        xmlns:wfw="http://wellformedweb.org/CommentAPI/"
        xmlns:dc="http://purl.org/dc/elements/1.1/"
        xmlns:atom="http://www.w3.org/2005/Atom"
        xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
        xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
        xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
        >

<channel>
        <title>ummestesimon</title>
        <atom:link href="http://ummestesimon.wordpress.com/feed/" rel="self" type="application/rss+xml" />
        <link>http://ummestesimon.wordpress.com</link>
        <description>Algo de tecnologí­a, anime, etc...</description>
        <lastBuildDate>Fri, 14 Oct 2011 16:11:25 +0000</lastBuildDate>
        <language>es</language>
        <sy:updatePeriod>hourly</sy:updatePeriod>
        <sy:updateFrequency>1</sy:updateFrequency>
        <generator>http://wordpress.com/</generator

Son sólo unas de las lí­neas, no son todas (después se harí­a un post más largo,
aunque lo duden).

Ahora, procesar todo ese XML es un problema y seguro que muchos después de ésta entrada
dirán: "hubieras usado ${herramienta}, es más sencillo"; quizás, en mi caso no tení­a (tengo)
tiempo de aprender alguna herramienta especí­fica, además para el tipo de proyectos que hago
XML no es algo de todos los dí­as (usamos JSON para casi todo), aunque nunca está de más.

Volviendo al tema, pues si seguimos viendo el XML que nos arroja wordpress, veremos unos elementos
parecidos a estos:

<item>
                <title>Y el origen nos dice: &#8220;Me voy yo, pero les dejo lo mí­o&#8221; &#124; Dennis MacAlistair Ritchie, Descanse en paz</title>
                <link>http://ummestesimon.wordpress.com/2011/10/13/y-el-origen-nos-dice-me-voy-yo-pero-les-dejo-lo-mio-dennis-macalistair-ritchie-descanse-en-paz/</link>
                <comments>http://ummestesimon.wordpress.com/2011/10/13/y-el-origen-nos-dice-me-voy-yo-pero-les-dejo-lo-mio-dennis-macalistair-ritchie-descanse-en-paz/#comments</comments>
                <pubDate>Thu, 13 Oct 2011 16:22:56 +0000</pubDate>
                <dc:creator>ummestesimon</dc:creator>
                                <category><![CDATA[Tecnologí­a]]></category>

                <guid isPermaLink="false">http://ummestesimon.wordpress.com/?p=266</guid>
                <description><![CDATA[¡Hola!, Espero que se encuentren de lo mejor. El dí­a de ayer me enteré que el señorón Dennis MacAlistair Ritchie habí­a fallecido, una noticia que seguro nos afecta a más de un informático. Este señor es uno de los pilares de la informática cómo la conocemos y si que ha dejado un gran legado. Muerto [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ummestesimon.wordpress.com&amp;blog=2388015&amp;post=266&amp;subd=ummestesimon&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>

Y son los "item" los que nos interesan (o almenos a mí­ era lo que me interesaba),
ya que estos elementos con los que cuentan con la información de cada post.

Bien, pues ahora a picar código.

Primero es necesario (porqué siendo honesto, me
dio pereza recibir el xml desde Java) contar con curl instalado en el sistema operativo
instalado, si cómo yo usas alguna distro GNU/Linux (Ubuntu, Debian, SuSE, ArchLinux, etc.)
puedes buscar en los repositorios oficiales de tu distro si viene el paquete de curl, en
caso de usar Debian, Ubuntu o cualquier otra distro en base a Debian puedes usar el clásico
sudo apt-get install curl. En el caso de Mac OS X creo que viene
por defecto, de lo contrario con instalar las herramientas de desarrollador deberí­a estar
instalado. Con Windows lo puedes conseguir desde aquí

Luego ahora si pues vamos a revisar algo de código Java:

import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;

class ProcesoWordpress{

----/*
---------Este método lo que hace es llamar al
---------programa curl del sistema operativo
---------para recibir la salida XML arrojada
---------por wordpress. De ahí­ por medio de un
---------BufferedReader mandamos la salida.
-----*/

----public BufferedReader callCurl(String url){
--------try{
------------Runtime runtime = Runtime.getRuntime();
------------Process process = runtime.exec("curl" + url);
------------process.waitFor();
------------BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
------------return bufferedReader();
--------}catch(Exception e){
------------System.out.println("==================Algo malo pasó aquí­======================");
------------e.printStackTrace();
------------System.out.println("==================/Algo malo pasó aquí­======================");
--------}
----}

----/*
--------Lo único que hace este método es crear
--------un xml, en una carpeta temporal, hay que
--------poner algo de atención a ello, ya que
--------la nomenclatura y árbol de directorios
--------varí­a según el sistema operativo.
----*/

----public Boolean writeXml(BufferedReader bufferedReader){
--------Boolean escritoBien = false;
--------try{
------------File archivoXml = new File("/tmp/feeds.xml");
------------if(archivoXml.exists()){
----------------archivoXml.delete();
------------}
------------archivoXml.createNewFile();
------------FileWriter fileWriter = new FileWriter(archivoXml);
------------BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
------------String linea = "";
------------while((linea = bufferedReader.readLine()) != null){
----------------bufferedWriter.write(linea);
------------}
------------bufferedWriter.close();
------------fileWriter.close();
------------escritoBien = true;
--------}catch(Exception e){
------------System.out.println("==================Algo malo pasó aquí­======================");
------------e.printStackTrace();
------------System.out.println("==================/Algo malo pasó aquí­======================");
--------}
--------return escritoBien;
----}

----/*
------Este método es el encargado de recibir el archivo xml
------y procesarlo, nos auxiliamos del método processElement
------para no tener una sopa de código aquí­. A partir del xml
------creamos una lista de los últimos posts.
-----*/

----public List<Post> procesarArchivoXml(File archivoXml){
---------List<Post> postList = null;
---------try{
------------final String ETIQUETA = "item";
------------DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
------------DocumentBuilder documentBuilder = documentBuilderFactory.newDocument();
------------Document document = documentBuilder.parse(archivoXml);
------------NodeList itemElementList = document.getElementsByTagName(ETIQUETA);
------------for(int x=0; x < itemElementList.getLength(); x++){
----------------Node node = itemElementList.item(x);
----------------if(node.getNodeType == Node.ELEMENT_NODE){
--------------------Element element = (Element)node;
--------------------Post auxiliarPost = processElement(element);
--------------------if(auxiliarPost != null){
                        if(postList == null) postList = new ArrayList<Post>();
------------------------postList.add(auxiliarPost);
--------------------}else{
------------------------throw new Exception("Parece que el archivo xml recibido no contiene lo esperado.");
--------------------}
----------------}
------------}
---------}catch(Exception e){
------------System.out.println("==================Algo malo pasó aquí­======================");
------------e.printStackTrace();
------------System.out.println("==================/Algo malo pasó aquí­======================");
--------}
--------return postList;
----}

----/*
------Aquí­ la cosa es simple, se crea un nuevo objeto
------de tipo Post, nos apoyamos en recibirAtributoEspecifico,
------para tener un código un poco más organizado.
-----*/

----public Post procesarElemento(Element element){
--------Post post = null;
--------try{
------------final String ETIQUETA_TITULO = "title";
------------final String ETIQUETA_ENLACE = "link";
------------final String ETIQUETA_DESCRIPCION = "description";
------------post = new Post();
------------post.setTitulo(recibirAtributoEspecifico(ETIQUETA_TITULO, element));
------------post.setEnlace(recibirAtributoEspecifico(ETIQUETA_ENLACE, element));
------------post.setDescripcion(recibirAtributoEspecifico(ETIQUETA_DESCRIPCION, element));
--------}catch(Exception e){
------------System.out.println("==================Algo malo pasó aquí­======================");
------------e.printStackTrace();
------------if(post != null) post = null;
------------System.out.println("==================/Algo malo pasó aquí­======================");
--------}
--------return post;
----}

----/*
------Este snippet lo que hace es recibir un elemento,
------después busca todas las etiquetas (elementos hijos)
------que hay dentro de él, en nuestro caso, sabemos que
------cada elemento "item" regresado por la sindicación de
------Wordpress cuenta con 1 sólo tí­tulo, 1 sólo enlace y
------1 sola descripción, por eso es que siempre pedimos
------el item 0 dentro del elemento "title" o "description".
------Y por último regresamos ese valor.
-----*/

----public String recibirAtributoEspecifico(String etiqueta, Element elemento){
--------NodeList nodeList = elemento.getElementsByTagName(etiqueta);
--------Element elementoEspecifico = (Element)nodeList.item(0);
--------NodeList valorCrudo = elementoEspecifico.getChildNodes();
--------String valor = (valorCrudo.item(0)).getNodeValue();
--------return valor;
----}

}

/*Y en la clase Post, un POJO*/
class Post{
----private String descripcion;
----private String titulo;
----private String enlace;

----public String getDescripcion(){
--------return descripcion;
----}

----public String getTitulo(){
--------return titulo;
----}

----public String getEnlace(){
--------return enlace;
----}

----public void setDescripcion(String descripcion){
--------this.descripcion = descripcion;
----}

----public void setTitulo(String titulo){
--------this.titulo = titulo;
----}

----public void setEnlace(String enlace){
--------this.enlace = enlace;
----}
}

Y pues básicamente sería todo. Tengo una versión que
ya no necesita el uso de curl, pero no encuentro el snippet
:P, de modo que de momento no me es posible ponerlo.

Ya con este snippet + curl es posible que crees tu cliente
de para wordpress (cuando menos para seguir los blogs que te
agraden :D).

Sin más.