Cómo insertar un feed RSS en RMarkdown
Un feed RSS es un archivo XML donde se registran las páginas de un sitio web, e.g. los artículos de un blog; otros sitios web o aplicaciones pueden leer el feed regularmente para conocer cuándo hay nuevos artículos. Digamos que queremos insertar enlaces a esos artículos en un documento HTML generado con RMarkdown.
Cómo hacerlo
Por supuesto, podríamos hacerlo con código R, pero entonces los enlaces solo serían actualizados al renderizar el script RMarkdown, es decir, al producir el formato de salida. Por suerte RMarkdown soporta javascript, así que (sabiendo nada sobre este lenguaje) busqué algún método en línea; claro está, esto solo funcionará con formatos de salida de tipo HTML.
En el blog CSS-Tricks encontré un método que permite obtener e insertar los items de un feed en una página HTML. Para utilizarlo en RMarkdown bastaría (al menos en teoría) copiar y pegar el código dentro de un bloque como este:
```{js}
// some javascript
```
También sería bueno escribir {js echo=FALSE}
para que el código se ejecute sin
ser mostrado. Hice esto en un nuevo script RMarkdown y este es el resultado:
Una solución
Tras leer un poco sobre cómo este método funciona, entendí que insertAdjacentHTML()
estaba insertando el contenido del feed justo antes de que termine el elemento <body>
.
Esto no es ideal, pero la solución es sencilla: aplicar el mismo insertAdjacentHTML()
para colocar contenido en la sección que yo desee.
Para identificar en qué secciones podemos insertar contenido, es útil entender que RMarkdown
utiliza pandoc para producir el documento final. Cuando existe un título,
e.g. # Mi título
, y el documento debe ser de tipo HTML, pandoc genera algo así:
<div id="mi-título" class="section level1">
<h1>Mi título</h1>
</div>
Lo útil de esto es que podemos usar getElementById()
para seleccionar precisamente el
<div>
donde queremos insertar el feed. A continuación presento el método que encontré
en CSS-Tricks, modificado para que: permita insertar el feed en una sección específica;
permita definir un número máximo de items para insertar; y permita insertar también un texto
explicativo. En este ejemplo estoy utilizando el blog de Yihui Xie.
const FEED = 'https://yihui.org/en/index.xml';
const TEXT1 = 'Yihui’s blog currently has';
const TEXT2 = 'posts. Here are the last';
const SECTION = 'el-resultado';
const MAXITEMS = 5;
fetch(FEED)
.then(response => response.text())
.then(str => new window.DOMParser().parseFromString(str, 'text/xml'))
.then(data => {
const ITEMS = data.querySelectorAll('item');
let CONTENT = `<p>${TEXT1} ${ITEMS.length} ${TEXT2} ${MAXITEMS}:</p><ol>`;
for (let i = 0; i < MAXITEMS; i++) {
+= `<li><a href="${ITEMS[i].querySelector('link').innerHTML}">`;
CONTENT += `${ITEMS[i].querySelector('title').innerHTML}</a></li>`;
CONTENT
}+= '</ol>';
CONTENT document.getElementById(SECTION).insertAdjacentHTML('afterend', CONTENT);
; })
El resultado
Conclusión
Este método también funciona en otros convertidores, además de pandoc. Para usarlo
en goldmark, por ejemplo, se debe insertar el
código javascript en un elemento <script lang="javascript">
y aplicar la opción
html.WithUnsafe
(de lo contrario, goldmark ignorará los elementos HTML). A diferencia
de pandoc, goldmark transforma # Mi título
en:
<h1 id="mi-título">Mi título</h1>
El método funciona de igual manera. No funciona, en cambio, con feeds Atom, un formato diferente a RSS; sin embargo, debería ser fácil adaptarlo a Atom (pista: cambian los elementos item y link). Finalmente, muchos feeds no pueden ser accedidos debido a una política denominada CORS. ¿Cuál es la solución? Desafortunamente no lo sé, por ahora terminaron mis experimentos con javascript.