Cuaderno de GNUtas

Encabezados con «Capítulo…» en la exportación de Org Mode a HTML

Este caso proviene de mi traducción de la Odisea (work in progress), donde lo que necesito es exportar como «Canto…». Pero se me ocurrió extraer lo más parecido a una situación general, por si pudiese serle de utilidad a alguien. Partamos, pues, de la siguiente premisa. Tenemos un documento de Org cuyos encabezados de primer nivel queremos exportarlos, tanto a LaTeX como a HTML, de manera que antes aparezca un «Capítulo…» seguido del correspondiente número. La solución rápida sería, por supuesto, indicarlo literalmente en cada título de encabezado. Pero eso es, precisamente, lo que queremos evitar. Primero, porque si queremos mantener la exportación a LaTeX de manera paralela a HTML, en la primera no sería necesario escribir los títulos con «Capítulo…» literalmente, ya que es el propio LaTeX (junto al muy recomendable paquete titlesec de Javier Bezos) el que se encargará de generarnos esos encabezados con la disposición y formato que hayamos definido en nuestro preámbulo personalizado para exportar con la clase book de LaTeX. Y segundo, es una verdadera lata tener que escribir esas cosas a mano y no delegar la numeración automática, encima, en el proceso de exportación.

LaTeX, ya decimos, no es problema. La pelota estaría más bien en el tejado de HTML si nuestra salida también va a ser en este formato. Pero, como siempre, se soluciona fácil. En este caso, se me ocurrieron un par de soluciones, una simple y la segunda un pelín más elaborada, pero nada que no se pueda hacer de forma rápida.

La solución simple

Si no precisamos de una tabla de contenido en nuestra exportación a HTML, o sí, pero no nos importa que en el índice no se incluyan los nobres de «Capítulo…» sino una simple numeración, ésta es la vía más rápida. Basta con añadir un poco de estilo HTML a la cabecera de nuestro documento Org, y crear un contador:

#+HTML_HEAD: <style>body{counter-reset: capitulo;}</style>
#+HTML_HEAD: <style>h2::before{counter-increment:capitulo;content: "Capítulo " counter(capitulo) ".";}</style>

Al hacer esto, modificamos el formato de los encabezados de 2º nivel (los que nos interesan) en el documento HTML (el de primer nivel sería el propio título del documento), de tal forma que se añada antes un contador (capitulo) previamente definido. Es importante que añadamos también a la cabecera la opción de exportación #+OPTIONS: num:nil, para desactivar la numeración que añade Org al exportar y no nos resulte una doble numeración. Algo así como «capítulo 1. 1. Título del capítulo». ¿Y si queremos que el formato de nuestro nuevo contador sea en números romanos? Pues lo indicamos en la segunda línea, tal que así:

#+HTML_HEAD: <style>h2::before{counter-increment:capitulo;content: "Capítulo " counter(capitulo, upper-roman) " – ";}</style>

La solución más larga (y fetén)

Esta es la que prefiero porque nos da más control (dentro de las habituales limitaciones del HTML, claro) y, además, podemos extender los nombres de «Capítulo…» a la tabla de contenido. Consiste en definir dos funciones que nos reemplacen (mediante expresiones regulares) los pasajes concretos del HTML resultante, pero ancladas a dos contextos de la exportación: la primera función irá anclada a la exportación de los encabezados, mientras que la segunda lo estará al output final. Podemos hacerlo de manera local para que estos filtros afecten sólo a nuestro documento. Encerramos, primero, ambas funciones en un bloque de código, y añadimos los parámetros pertinentes de cara a cuando ese código se evalúe (ergo se ejecute) durante la exportación:

#+begin_src emacs-lisp :exports results :results none
(defun capitulos-html (titulo backend info)
  "añade capítulo y núm. a los encabezados"
(when (org-export-derived-backend-p backend 'html)
(replace-regexp-in-string "<span class=\"section-number-2\">\\([[:digit:]]\\)"  "<span class=\"section-number-2\">Capítulo \\1. " titulo)))

(defun indice-html (titulo backend info)
  "añade capítulo y núm. en índice"
(when (org-export-derived-backend-p backend 'html)
(replace-regexp-in-string "<li><a href=\"\\#\\([[:graph:]]+\\)>\\([[:digit:]]\\)"  "<li><a href=\"#\\1>Capítulo \\2" titulo)))
#+end_src

Y, justo antes de este bloque, añadimos los anclajes necesarios:

#+BIND: org-export-filter-headline-functions (capitulos-html)
#+BIND: org-export-filter-final-output-functions (indice-html)

Por supuesto, debemos indicar también en nuestro documento (por ejemplo, al final del mismo), la variable local:

# Local Variables:
# org-export-allow-bind-keywords: t
# End:

Entonces, si tenemos algo como esto:

* Esto es un título de capítulo
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec hendrerit tempor tellus. Donec pretium posuere tellus. Proin quam nisl, tincidunt et, mattis eget, convallis nec, purus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla posuere. Donec vitae dolor. Nullam tristique diam non turpis. Cras placerat accumsan nulla. Nullam rutrum. Nam vestibulum accumsan nisl.

* Otro título de capítulo

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec hendrerit tempor tellus. Donec pretium posuere tellus. Proin quam nisl, tincidunt et, mattis eget, convallis nec, purus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla posuere. Donec vitae dolor. Nullam tristique diam non turpis. Cras placerat accumsan nulla. Nullam rutrum. Nam vestibulum accumsan nisl.

* Y un tercer título

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec hendrerit tempor tellus. Donec pretium posuere tellus. Proin quam nisl, tincidunt et, mattis eget, convallis nec, purus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla posuere. Donec vitae dolor. Nullam tristique diam non turpis. Cras placerat accumsan nulla. Nullam rutrum. Nam vestibulum accumsan nisl.

obtendremos, al exportar a HTML lo que se muestra en la fig. 1

¿Y si, nuevamente, queremos que la numeración de capítulos esté en numerales romanos? Pues en este caso tendremos que dar algún rodeo adicional, pero nada del otro mundo. Lo primero que hice fue escribir un sencillo script en Perl, ya que Perl dispone de un módulo muy eficiente para transformar números arábigos en romanos y viceversa. Y dicho script lo llamamos desde nuestro propio documento de Org una vez ejecutada la exportación. Ahora bien, ojo, debemos encerrar los números que queremos que se reemplacen por sus correspondientes romanos entre dos caracteres comodín; de lo contrario, el script efectuará el reemplazo en cualquier número arábigo de nuestro documento, y no queremos eso. Así pues, hacemos una mínima modifcación en nuestras dos funciones anteriores, encerrando los números resultantes entre dos <<...>>:

#+begin_src emacs-lisp :exports results :results none
(defun capitulos-html (titulo backend info)
  "añade capítulo y núm. a los encabezados"
(when (org-export-derived-backend-p backend 'html)
(replace-regexp-in-string "<span class=\"section-number-2\">\\([[:digit:]]\\)"  "<span class=\"section-number-2\">Capítulo <<\\1>>. " titulo)))

(defun indice-html (titulo backend info)
  "añade capítulo y núm. en índice"
(when (org-export-derived-backend-p backend 'html)
(replace-regexp-in-string "<li><a href=\"\\#\\([[:graph:]]+\\)>\\([[:digit:]]\\)"  "<li><a href=\"#\\1>Capítulo <<\\2>>" titulo)))
#+end_src

Nuestro script en Perl, que nombramos como int2romanos.pl:

#!/usr/bin/perl

# Busca en el documento HTML resultante todos los núms. arábigos encerrados entre "<< >>" y los transforma en romanos

use strict;
use warnings;

use Text::Roman 'int2roman';

$^I = '.bak';

while (<>) {
          s/<<\b(\w+)\b>>/int2roman($1) || $1/ge;
   print;
}

Y un bloque de código en nuestro documento Org para llamar al script:

#+begin_src shell :exports results :results none
./int2romanos.pl nuestro-archivo.html
#+end_src

Una vez realizada la exportación, situamos el cursor en este bloque de código y lo evaluamos (secuencia C-c C-c). Automágicamente, nuestros capítulos ya estarán numerados en romanos, como se muestra en la fig. 2

org-capi1.png

Figura 1: Capítulos numerados con índice en la exportación de Org a HTML

org-capi2.png

Figura 2: Capítulos numerados en romanos con índice en la exportación de Org a HTML

Publicado: 03/07/2019

Última actualización: 16/08/23


Índice general

Acerca de...

Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.

© Juan Manuel Macías
Creado con esmero en
GNU Emacs