Trasformare un CSV in un feed RSS

GDAL/OGR fa anche il caffè

Il CSV (Comma-separated values) è oggi — pur avendo diversi limiti — un formato di output di molte applicazioni, librerie di sviluppo, API, CMS.
L’RSS (Really Simple Syndication) è uno dei formati più diffusi per distribuire contenuti sul web; lo uso moltissimo da anni per verificare i cambiamenti di una certa fonte (l’ultima notizia dal mio blog preferito, una nuova issue da progetto che seguo, un terremoto, un nuovo dataset pubblicato in un portale, l’annuncio di una nuova release di un software, un nuovo messaggio in una mailing list, ecc.).

Visto che molti dati/informazioni sono disponibili in CSV, poterne trasformare alcuni in RSS consente di sfruttare delle modalità “vecchie” (la release 1.0 è del 2000), standard, ben funzionanti e comode per rimanere aggiornati sui dati di input e/o attivare dei trigger correlati (per ogni nuovo elemento nel feed RSS, invia un’email a tizio, ecc).

Questa trasformazione è abbastanza semplice ed è realizzabile in molteplici modalità. L’obiettivo qui è quello di farla senza introdurre alcun linguaggio di scripting — senza for loop, condizioni if, ecc. — ed eseguire tutto "a riga di comando" in pochissimi e semplici passi.

GDAL/OGR

La libreria GDAL/OGR è senza dubbio la migliore libreria “generica” per leggere e trasformare dati spaziali. 
Usandola viene spesso da pensare “ma fa anche il caffè”? La risposta per me è sì!

Tra gli output nativi ha il GeoRSS, ovvero un feed RSS arricchito da informazioni spaziali. Qui sotto ad esempio un estratto del GeoRSS degli avvisi della polizia municipale di Palermo, in cui ad ogni nuova segnalazione sono associate le coordinate geografiche del luogo in cui è avvenuto quanto descritto.

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
<channel>
<atom:link href="https://www.comune.palermo.it/feed/rss.xml" rel="self" type="application/rss+xml" />
<title>Feed RSS – Comune di Palermo</title>
<link>https://www.comune.palermo.it</link>
<description>Polizia Municipale</description>
<item>
<guid>https://mobilitasostenibile.comune.palermo.it/news.php?func=1&amp;id=2862</guid>
<title>Incidente</title>
<description>Via M. Bonello altezza via incoronazione incidente stradale possibili rallentamenti.
</description>
<link>https://mobilitasostenibile.comune.palermo.it/news.php?func=1&amp;id=2862</link>
<author>webmaster@comune.palermo.it (Comune di Palermo)</author>
<category>Tweet PM</category>
<pubDate>Sun, 06 Aug 2017 10:27:19 GMT</pubDate>
<geo:lat>38.11422460304508</geo:lat>
<geo:long>13.355255316671787</geo:long>
</item>
</channel>
</rss>
“ma posso creare anche un RSS normale, anche non geo??”

La risposta ancora una volta è sì e mostrerò due modalità: la prima è un po’ una forzatura, la seconda è molto “pulita”.

Da CSV a RSS con GDAL/OGR — Modalità 1

Il CSV di input deve avere questi campi (in qualsiasi ordine), quelli previsti dal formato RSS:

  • title, il titolo;
  • link, il link;
  • description, la descrizione;
  • dataItemSource, la data secondo la specifica "RFC 822", ad esempio "Sat, 07 Sep 2002 0:00:01 GMT";
  • guid, un identificativo (spesso coincide con il link);
  • category (opzionale), per impostare - se si vuole - una categoria.

Quindi ad esempio qualcosa come quella di sotto:

Esempio di file CSV di input. Download qui.

Come campo per la data ho inserito dataItemSource e non pubDate - il nome standard per un RSS - perché se uso come input il nome campo pubDate GDAL/OGR mi darebbe un errore: si aspetta per questo campo un formato di tipo DateTime , ma in un file CSV non è possibile definire tipi di campo (salvo non creare un file .csvt, o altri file accessori di descrizione). 
Quindi per il campo con la data di pubblicazione ho scelto un nome fittizio temporaneo.

Il comando per fare la conversione, che sfrutta l’utility di GDAL/OGR ogr2ogr, è:

ogr2ogr -f geoRSS -dsco USE_EXTENSIONS=YES -dsco TITLE="Titolo del feed" -dsco LINK="http://urlDelMioFeed.it/output.xml" -dsco DESCRIPTION="La descrizione del feed" georss.xml input.csv

Nel dettaglio con -f imposto il formato di output e con -dsco (Dataset creation option) imposto titolo, descrizione e link del feed RSS di output.

Con -dsco USE_EXTENSIONS=YES invece forzo l'inserimento nel file di output anche di campi non standard come il suddetto dataItemSource.

L’output sarà:

<?xml version="1.0"?>
<rss version="2.0" xmlns:georss="http://www.georss.org/georss">
<channel>
<title>Titolo del feed</title>
<description>La descrizione del feed</description>
<link>http://urlDelMioFeed.it/output.xml</link>
<item>
<title>UK Earthquake alert: M 2.2: MOIDART</title>
<description>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</description>
<link>http://urlfinto.it/20170804173348.html</link>
<ogr:dataItemSource>Sat, 05 Aug 2017 16:44:29 GMT</ogr:dataItemSource>
<category>test1</category>
<guid>http://urlfinto.it/20170804173348.html</guid>
</item>
<item>
<title>UK Earthquake alert: M 3.4: MOIDART, WEST HIGHLAND</title>
<description>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</description>
<link>http://urlfinto.it/20170804144132.html</link>
<ogr:dataItemSource>Sat, 05 Aug 2017 16:44:29 GMT</ogr:dataItemSource>
<category>test1</category>
<guid>http://urlfinto.it/20170804144132.html</guid>
</item>
</channel>
</rss>

Il feed di sopra però non è valido, perché non è presente il campo obbligatorio pubDate. Per renderlo valido si può fare un "trova e sostitusci" di ogr:dataItemSource con pubDate, che a riga di comando con sedè:

sed -i 's/ogr:dataItemSource/pubDate/g' georss.xml

Adesso il feed RSS è valido. Il parametro -i per eseguire la sostituzione delle stringhe sul file di input (in questo caso georss.xml).

Da CSV a RSS con GDAL/OGR — Modalità 2 (più semplice)

Se nel CSV di input avete la data in formato ISO 8601 (quindi `AAAA-MM-GG HH:MM:SS`, 2007–07–11 15:38:21) è possibile utilizzare come nome campo pubDate e lanciare:

ogr2ogr -f geoRSS -dsco TITLE="Titolo del feed" -dsco LINK="http://urlDelMioFeed.it/output.xml" -dsco DESCRIPTION="La descrizione del feed" -oo AUTODETECT_TYPE=YES georss.xml input.csv

Aggiungendo l’opzione -oo AUTODETECT_TYPE=YES (grazie Even) GDAL/OGR è capace di riconoscere il contenuto del campo pubDate come DateTime e lo converte nel formato data nella specifica “RFC 822”. 
Uno solo passaggio, senza alcun “trova e sostituisci” o assegnazione temporanea di nome fittizio di campo.

Devono comunque essere presenti anche gli altri campi della prima modalità.

E per creare un GeoRSS a partire da un CSV?

Ringrazio Antonio Falciano per la domanda, che avevo lasciato off-topic nella prima versione dell’articolo e che in effetti è sensata.

Nel caso di dati puntuali basta che nel CSV di input ci sia una colonna denominata “WKT”, che contenga le coordinate dei punti di ogni riga secondo la rappresentazione WKT, quindi ad esempio POINT (13.256 38.2365).
E poi si potrà lanciare il comando di conversione visto sopra.

Ad ogni elemento di output sarà aggiunta la proprietà georss:point , qualcosa come:

<georss:point>38.2365 13.256</georss:point>

Avevo lasciato fuori il tema GeoRSS, perché l’obiettivo principale era mostrare come questa libreria risolve un problema generico, “per tutti”.

Conclusione

Quanto descritto è un po’ la copia “in bella” di appunti presi sul mio “quaderno dei tips & tricks”, niente di elegante o di fortemente consigliato. 
Ho deciso di trasformarla in un post perché la creazione di un RSS è qualcosa di molto utile e può essere di interesse per diverse persone.

Un pensiero ad Aaron Swartz, coautore della prima specifica del RSS.