Leyendo un feed OpenSearch con código Java

De forma muy resumida, OpenSearch es una colección de formatos abiertos y estándares desarrollados por A9 (Amazon), que persiguen resolver 2 escenarios principalmente:

  • Caso 1: Permitir a una aplicación publicar de una forma estándar resultados de búsqueda; estos resultados pueden ser consumidos posteriormente por una aplicación cliente. Se basa en un metamodelo estandarizado publicado bajo una fuente de sindicación estándar como RSS o Atom. Podemos ver un ejemplo de resultado de búsqueda en formato OpenSearch en esta URL de indeed.com.
  • Caso 2: Describir (autodescribir) servicios de búsqueda. Es lo que utiliza por ejemplo Firefox 3 para ofrecernos búsquedas inteligentes.

En este post vamos a describir cómo leer resultados de búsqueda en formato OpenSearch (caso 1). Para el caso 2, recomendamos la lectura de un post de 11870.com que describe a la perfección cómo describir nuestro buscador.

Si nos fijamos en el código fuente de respuesta de la URL comentada de indeed, veremos que en este caso se está devolviendo sobre RSS una información general sobre la búsqueda más un conjunto de resultados de búsqueda (items), los cuales pueden ser incluso geolocalizados.

En Java, este RSS (o Atom) podría ser leído con cualquier intérprete de XML, o mejor con alguna librería específica de este tipo de feeds, como Rome o Apache Abdera, o mejor aún, con librerías específicas para OpenSearch. En nuestro caso, debíamos leer la respuesta del API de 11870.com, dentro de un proyecto en el cual deseábamos proponer establecimientos propuestos por los usuarios que estén cercanos a nuestra localización.

A este respecto, cuando he hecho la búsqueda de librerías Java, personal he tenido una sensación agridulce. Si bien los desarrolladores Java solemos ser unos verdaderos privilegiados en cuanto a lo que se refiere a disposición de API’s, en ciertos casos relacionados con web semántica o API’s de web 2.0 tengo la sensación de que otras arquitecturas de desarrollo como PHP, Python o RoR a veces tienen cierta ventaja. En el caso de Java todo son versiones de incubadora, 0.X, etc.

En el caso de librerías Java, una rápida búsqueda nos llevó a decidirnos entre Rome (Sun) y Apache Abdera, escogiendo este último por disponer de mejores ejemplos de los que partir. Además dentro de los committers de Abdera está el supercrack David Calavera, desarrollador de la omnipresente 11870.com.

A continuación incluiremos unos pequeños recortes de código que muestran como leer la respuesta OpenSearch mediante Abdera. En primer lugar, necesitaremos disponer de las librerías. Para ello (en el caso de Maven) incluiremos estas dependencias en nuestro pom.xml:

<dependency>
<groupId>org.apache.abdera</groupId>
<artifactId>abdera-client</artifactId>
<version>0.4.0-incubating</version>
</dependency>

<dependency>
<groupId>org.apache.abdera</groupId>
<artifactId>abdera-extensions-opensearch</artifactId>
<version>0.4.0-incubating</version>
</dependency>

Para poder resolver estas dependencias incluiremos los repositorio Incubating y Snapshot de Apache dentro de <repositories>:

<repository>
<id>apache-incubating</id>
<name>Apache Incubating Repository</name>
<url>http://people.apache.org/repo/m2-incubating-repository/</url>
</repository>
<repository>
<id>apache-snapshots</id>
<name>Apache Snapshot Repository</name>
<url>http://people.apache.org/repo/m2-snapshot-repository/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>

Dado una dirección URL (String urlQuery) donde esté publicada una consulta que responde OpenSearch, podremos invocarla con el siguente código:

Abdera abdera = new Abdera();
Parser parser = abdera.getParser();
URL url = new URL(urlQuery);
Document<Feed> doc = parser.parse(url.openStream(), urlQuery);
Feed feed = doc.getRoot();

Podemos recuperar ciertas propiedades de la respuesta de OpenSearch:

IntegerElement totalResults = feed.getExtension(OpenSearchConstants.TOTAL_RESULTS);
int resultados = totalResults.getValue();

Del mismo modo se pueden recuperar datos como el número de items por página (OpenSearchConstants.ITEMS_PER_PAGE) o el índice inicial de la respuesta, útil cuando hay paginación (OpenSearchConstants.START_INDEX. Es decir, podemos obtener datos OpenSearch del feed mediante feed.getExtension().

A continuación mostramos cómo iterar los items de respuesta del feed:

for (Entry entry : feed.getEntries()) {

    System.out.println(«Title: «+entry.getTitle());
    System.out.println(«Summary: «+entry.getSummary());
    System.out.println(«Id: «+entry.getId().toString());
    System.out.println(«Id: «+entry.getId().toString());

}

También podemos evaluar para cada item (resultado de búsqueda) el valor de extensiones a OpenSearch. Por ejemplo, podemos pretender recuperar los datos de geolocalización en formato GeoRss. Para ello utilizaríamos un código como el que sigue:

QName qnameWhere = new QName(«http://www.georss.org/georss/10″,»where», «georss»);
Element where = entry.getExtension(qnameWhere);
try {
String geoPos = where.getFirstChild().getFirstChild()
.getText();
String[] posicion = geoPos.split(» «);
if (posicion.length == 2) {

System.out.println(«latitud: «+posicion[0]);
System.out.println(«longitud: «+posicion[1]);
}
} catch (Exception e) {
e.printStackTrace();
}

Es decir, podemos recuperar el valor de un parámetro de una extensión invocando a entry.getExtension, pasando como parámetro un objeto de tipo QName, instanciado como indicamos en el código anterior.

En definitiva, hemos hecho una breve introducción a OpenSearch y mostrado código de ejemplo para interactuar con una respuesta OpenSearch mediante Apache Abdera.