Embeber OpacMarc en DokuWiki

Es atractiva la posibilidad de “embeber” (“encajar”, “incrustar”) el OPAC como parte del sitio web de la biblioteca, en lugar de presentarlo como una página o sitio que debe ser visitado en forma separada. La idea puede encontrarse, por ejemplo, en esta presentación de Daniel Forsman (2007), de la Biblioteca de Jönköping University (Suecia).

La manera de implementar esto dependerá de las características de la herramienta usada para administrar el sitio; en el caso particular del INMABB nos interesaba poder hacerlo con DokuWiki. Con ese fin, hubo que realizar varias modificaciones en OpacMarc, y crear un plugin para DokuWiki. A continuación se describen los pasos efectuados y los problemas encontrados.

Es importante resaltar que los cambios hechos en OpacMarc posiblemente sean suficientes para permitir que también sea embebido en otras aplicaciones.

Cambios en OpacMarc

Para hacer el opac “embeddable”, tuvimos que hacerle algunas modificaciones.

Generación parcial de la página

Definimos un nuevo parámetro output en opac.xis. Un cliente puede especificar --mediante output=embed-- que sólo desea recibir el contenido propiamente, es decir, que opac.xis debe omitir generar el comienzo (hasta el header inclusive) y el final de la página (posiblemente un footer, y el string “</body></html>”)

Generación de enlaces a scripts (''href'' en links, ''action'' en forms)

Definimos un parámetro script_url en opac.xis. Mediante este parámetro, un cliente puede sobrescribir el valor del parámetro de configuración SCRIPT_URL. El valor es utilizado como “prefijo” en todas las URLs que apuntan al OPAC, tanto links como formularios.

Por ejemplo, para DokuWiki tendríamos script_url=/doku.php/catalogo (si se configura DokuWiki con userewrite=2), o script_url=/doku.php?id=catalogo (con el default userewrite=0).

Para poder hacer uso de este parámetro, tuvimos que efectuar este reemplazo en varios archivos:

getenv('SCRIPT_NAME') => v6001^u (o v6001^u[1] dentro de un grupo repetible)

Para tener en cuenta el caso en que script_url ya incluye un query string (e.g. script_url=/doku.php?id=catalogo), hicimos este otro reemplazo en múltiples archivos:

?IsisScript= => &amp;IsisScript=

Pero esto aún deja sin resolver el caso de los formularios. Para evitar el problema, podríamos limitarnos a admitir como script_url solamente valores sin query string, para evitar la complicación de los parámetros adicionales en los formularios; de ahí la conveniencia de utilizar en DokuWiki un valor de userewrite diferente de 0.

Sería mejor si pudiéramos quitar estos dos parámetros de todas las URLs:

&IsisScript=xis/opac.xis&db=demo

pues pueden ser insertados por el plugin, como sucede con la portada del OPAC. Pero no es una necesidad.

Generación de enlaces a archivos estáticos (''src'' en <img>, ''href'' en <link>)

Creamos un nuevo parámetro para OpacMarc, path_htdocs, con el que un cliente puede sobrescribir el parámetro de configuración PATH_HTDOCS.

Adecuación de CSS

El primer problema a resolver es: cómo hacer que las reglas de estilo del opac se mantengan acotadas y no “contaminen” el resto de la página que aloja al opac. La solución es simple:

a nivel de HTML, hacemos que un <div class=“opacmarc”> envuelva el contenido propio del opac

a nivel de CSS, modificamos las hojas de estilo del opac, anteponiendo div.opacmarc a todos los selectores.

Por ahora, sólo hice esas modificaciones en una copia de los archivos .css para ser usada por DokuWiki; creo que el cambio finalmente habría que hacerlo en las .css originales de OpacMarc.

Ver qué partes del css del opac son para header/footer (i.e. fuera de ese div) y por lo tanto no deberían llevar ese prefijo en los selectores.

El segundo problema es: cómo evitar que las reglas de estilo de la página host (DokuWiki) causen “interferencias” sobre la porción de la página correspondiente al opac. Aquí a su vez se presentan dos posibles situaciones:

Que una regla de estilo del host compita con una regla de estilo del opac y le gane. Para evitar esto, nos gustaría poder tener un important! para las reglas del opac.

Que una regla de estilo del host se aplique a un elemento del opac, sin que haya una regla de estilo del opac para competir. Para evitar esto, ¿podríamos “blindar” nuestro <div class=“opacmarc”> para suprimir el efecto de reglas externas al opac?

El tercer problema: cómo ajustar los paths de las imágenes usadas por las hojas de estilo, p.ej.

background-image: url(../img/0180_bullet.gif);

Cuarto problema: ¿cómo obtiene el cliente las hojas de estilo e imágenes asociadas? Hay hojas de estilo default, locales, por base, para IE, ...

Las hojas de estilo de los templates son cargadas después de las de los plugins (devel:css).

JavaScript

Title de la página

Así como agregamos elementos link y script al <head> de la página del catálogo, también nos gustaría poder alterar el <title>, para que muestre un título generado por el OPAC. ¿Cómo hacemos?

HTML vs XHTML

DokuWiki usa XHTML 1.0 Transitional. Para que la inclusión de contenido del OPAC no altere la validez del código XHTML, vamos a tener que hacer algunos ajustes, de manera que OpacMarc produzca XHTML válido.

<br> => <br/>

<hr> => <hr/>

<img ...> => <img .../>

<input ...> => <input .../>

selected => selected=“selected”

checked => checked=“checked”

& => &amp;

Hice varios ajustes, pero habrá que revisar más exhaustivamente (sé que dejé algunas cosas colgadas).

Arreglos pendientes, según validador de W3C:

thead, tfoot en Etiquetado

Plugin para DokuWiki

Implementamos la funcionalidad “encajar OpacMarc en una página del wiki” mediante un plugin llamado opacmarc.

El plugin define esta sintaxis:

{{OPAC>nombre_de_la_base}}

(Para usar algo como {{OPAC>demo}} (análogo a la sintaxis de blog o rss), tenemos que elegir adecuadamente el valor retornado por la función getSort, para poder “ganarle” a la sintaxis usada para insertar media. Ver devel:syntax_plugins#sort_number y devel:parser:getsort_list.)

Los archivos creados son:

syntax.php

action.php

conf/metadata.php

conf/default.php

lang/en/settings.php

lang/es/settings.php

El archivo action.php (action plugin) se ocupa de insertar elementos script y link en el head de la página, para solicitar CSS y JavaScript directamente al servidor del OPAC. Esto lo hace solamente para la página del catálogo. Así, el plugin no necesita mantener una copia del CSS ni del JS del OPAC. Un inconveniente a resolver: ¿cómo hacer que esta modificación sólo suceda en la página del catálogo? No queremos tener que reconocer la página mediante su id; se supone que es la presencia de la sintaxis {{OPAC...}} lo que caracteriza a la página como “catálogo”. Ver si se puede registrar el event handler desde syntax.php (devel:events#registering_to_receive_an_event). Probé y no dio resultado. Consultar en la lista.

Problemas

Múltiples ejecuciones

El primer síntoma fue que por cada “búsqueda por autor”, que normalmente genera un único archivo temporal, al usar DokuWiki se generaban siete archivos iguales.

Usando estas líneas en opac.xis:

<file action="append" type="output">/tmp/opacmarc-dokuwiki.log</file> <display><pft>'ejecutando opac.xis'/</pft></display> <file action="close" type="output">/tmp/opacmarc-dokuwiki.log</file>

quedó claro que el problema está en que opac.xis se está ejecutando siete veces, incluso al visitar la página de inicio del catálogo.

Usando estas líneas en syntax.php:

$fp = fopen('/tmp/opacmarc-dokuwiki-syntax', 'a'); fwrite($fp, "syntax-render\n"); fclose($fp);

nos enteramos de que es la función render en syntax.php la que se está ejecutando siete veces. (El resto del código en ese archivo aparentemente sólo se ejecuta una vez.)

Haciendo un test similar con el plugin now, encontramos que:

al hacer el preview, render se ejecuta una vez

al guardar la página, render se ejecuta tres veces

En pruebas posteriores, el número siete baja a dos, pero en cualquier caso la pregunta es: ¿por qué render() se ejecuta más de una vez?

Consulta enviada al foro.

Instalé Xdebug para PHP (sudo apt-get install php5-xdebug) para tratar de ver mejor lo que está pasando. Ver Understanding PHP code better with Xdebug

Usando Xdebug veo que en renderer.php, class Doku_Renderer, la función plugin es llamada 7 veces; quien llama es call_user_func_array en parserutils.php.

Consulta enviada a la lista de desarrolladores.

Probar con una instalación completamente limpia del wiki (template default, etc.).

Para ver si influye la presencia de links hacia la misma página: Creé una página “instituto/test”, con el contenido “[OPAC>demo]”. Al ver la página no aparecen links a ella misma. La función render se sigue ejecutando 7 veces. ver efecto de los breadcrumbs. OJO! Ver la config:useheading. También ver valor de $mode en cada ejecución de render.

Al desactivar config:useheading se producen tres llamadas a render: una con $mode=xhtml y dos con $mode=metadata. Antes eran una con $mode=xhtml y seis con $mode=metadata.

Si bien la función render se sigue ejecutando muchas veces (lo que parecería ser un comportamiento normal del wiki), resolví lo de las múltiples llamadas al OPAC mediante un sencillo cache: almaceno la respuesta del OPAC en una variable la primera vez que se ejecuta render, y en las siguientes veces no vuelve a ejecutar ese bloque de código.

Mejor solución: moví el bloque de código al interior del if:

if($mode == 'xhtml') { ... }

ya que es allí donde lo necesitamos; las llamadas extra a render tienen $mode='metadata'.

Explicar por qué no podemos realizar la llamada al OPAC dentro de la función handle (cuyo resultado sí es guardado en cache), y en cambio debemos hacerla desde render (que no se cachea).

PHP Warning

Warning: preg_replace_callback() [function.preg-replace-callback]: Compilation failed: invalid UTF-8 string at offset 20 in /home/fernando/www/html/dokuwiki/inc/html.php on line 271

Cómo se produce: entrar por índice de autores a Raúl Alfonsín, ver el registro, clic en el punto de acceso para Raúl Alfonsín. Se repite si desde ahí hago clic en “Catálogo”, y desaparece cuando insisto.

Esto está relacionado con el resaltado de términos, al hacer una búsqueda con términos acentuados. Ver abajo.

Resaltado de términos

El wiki aplica un resaltado en algunas páginas, mediante un <span class=“search_hit”>. Esto se debe a una interferencia del parámetro query usado para el OPAC. Detalles:

En doku.php se define $HIGH:

$HIGH = $_REQUEST['s']; if(empty($HIGH)) $HIGH = getGoogleQuery();

que a su vez puede depender de getGoogleQuery, definida en inc/common.php:

/** * extracts the query from a search engine referrer * * @author Andreas Gohr <andi@splitbrain.org> * @author Todd Augsburger <todd@rollerorgans.com> */ function getGoogleQuery(){ $url = parse_url($_SERVER['HTTP_REFERER']); if(!$url) return ''; $query = array(); parse_str($url['query'],$query); if(isset($query['q'])) $q = $query['q']; // google, live/msn, aol, ask, altavista, alltheweb, gigablast elseif(isset($query['p'])) $q = $query['p']; // yahoo elseif(isset($query['query'])) $q = $query['query']; // lycos, netscape, clusty, hotbot elseif(preg_match("#a9\.com#i",$url['host'])) // a9 $q = urldecode(ltrim($url['path'],'/')); if(!$q) return ''; $q = preg_split('/[\s\'"\\\\`()\]\[?:!\.{};,#+*<>\\/]+/',$q,-1,PREG_SPLIT_NO_EMPTY); return $q; }

En inc/html.php se utiliza $HIGH para aplicar el resaltado:

/** * show a wiki page * * @author Andreas Gohr <andi@splitbrain.org> */ function html_show($txt=''){ global $ID; global $REV; global $HIGH; global $INFO; ... ... if ($REV) print p_locale_xhtml('showrev'); $html = p_wiki_xhtml($ID,$REV,true); $html = html_secedit($html,$secedit); if($INFO['prependTOC']) $html = tpl_toc(true).$html; $html = html_hilight($html,$HIGH); echo $html; ... }
/** * Highlights searchqueries in HTML code * * @author Andreas Gohr <andi@splitbrain.org> * @author Harry Fuecks <hfuecks@gmail.com> */ function html_hilight($html,$phrases){ $regex = join('|',array_map('preg_quote_cb',array_filter((array) $phrases))); if ($regex ==== '') return $html; $html = preg_replace_callback("/((<[^>]*)|$regex)/ui",'html_hilight_callback',$html); return $html; } /** * Callback used by html_hilight() * * @author Harry Fuecks <hfuecks@gmail.com> */ function html_hilight_callback($m) { $hlight = unslash($m[0]); if ( !isset($m[2])) { $hlight = '<span class="search_hit">'.$hlight.'</span>'; } return $hlight; }

El resaltado está atrasado; es decir, se resaltan términos correspondientes a la búsqueda previa.

Cuestiones a resolver:

¿Queremos que DokuWiki aplique el resaltado en páginas del OPAC? Posiblemente no lo aplique de manera satisfactoria (desfasaje, problemas con acentos), así que en una primera etapa será mejor prescindir de esa funcion.

¿Cómo la desactivamos? Una posibilidad (no muy limpia) es mediante CSS (.search_hit {background-color: inherit; color: inherit;}), pero esto no resuelve el problema de las expresiones con acentos, donde se produce un error de PHP. Entonces, como solución de emergencia, comenté en inc/common.php las dos líneas de getGoogleQuery donde se hace referencia a un parámetro “query”. Claro que esto no es bueno, porque estamos alterando código core de DokuWiki.

Charset/encoding de términos de búsqueda

No funcionan las búsquedas cuando se ingresan términos con acentos.

Resuelto aplicando utf8_decode a ciertos parámetros, en base a la presencia de $_REQUEST['form']. Es importante tener en cuenta que el decode es necesario para términos procedentes de un form (i.e. ingresados por un usuario), pero no para aquellos procedentes de un link (i.e. generados por el OPAC). Esto llevó a crear un parámetro oculto form en los formularios del OPAC.

Queda algún problema pendiente. Buscar registros de “Unión Matemática Argentina”, y desde uno de ellos clic en “Listado”, da error.

Hojas de estilo para IE

¿Cómo podemos usar comentarios condicionales para cargar las hojas de estilo que sólo debe ver IE?

Mediante action.php: no parece que se puedan añadir comentarios.

Mediante el template (archivo meta.html): no parece buena idea introducir elementos propios del plugin dentro de un template, pero podría ser aceptable para nuestro caso.

Display de ficha AACR2

Si entramos a un registro directamente desde el índice de autores y pasamos a la ficha, no la muestra; si en cambio pasamos antes por otro estilo y luego intentamos otra vez la ficha, sí se ve. La diferencia que pude detectar en las URLs:

&curr=1&total=1&cn=&style=Ficha

versus

&curr=1&total=&cn=&style=Ficha

Ahora aparece RESUELTO (no sé por qué).

Logs

Los logs que almacene OpacMarc carecerán de datos sobre el cliente (número de IP, browser), a menos que el plugin se ocupe de incluirlos en la petición.

Conflictos

La presencia de otro contenido en la página del OPAC impide el uso del catálogo, cuando no está presente ~~NOCACHE~~