HTTP et JSON : la boucle (DATA)
de SPIP peut nativement parler à CouchDB. Comme exemple d’application, voici un squelette permettant d’afficher les « câbles » diplomatiques américains révélés par Wikileaks.
(Pour en savoir plus sur CouchDB : http://couchdb.apache.org/)
La base de données
Le 6 décembre 2010, Benoît Chesneau annonçait qu’il mettait les cablegate à disposition dans une base CouchDB :
You can now replicate cables in your couchdb via https https://upondata.com/cablesgate , more mirroring soon. #cablesgate #wikileaks
On peut explorer cette base de données en utilisant la superbe interface Futon, associée à CouchDB : https://upondata.com/_utils/
- Futon
Sous CouchDB, la liste des documents disponibles se trouve derrière une adresse du type URL_BASE_DONNEES/_all_docs
, et les résultats sont renvoyés sous forme d’un tableau au format JSON, dont l’élément rows
contient les résultats.
Une simple boucle permet de vérifier rapidement le contenu de cette base :
<BOUCLE_liste(DATA)
{source json, https://upondata.com/cablesgate/_all_docs}
{datapath rows}
{pagination 10}
>
[(#VALEUR|print)<br />]
</BOUCLE_liste>
(On a ajouté la pagination car la base contient déjà plus de 1500 documents).
Résultat :
00HARARE5461, 00HARARE5461, 1-ab2f3b839699e38a0ade9a69580d3807
00HARARE6677, 00HARARE6677, 1-ff69b744322ed2ad40684a3049438a76
01PRETORIA1173, 01PRETORIA1173, 1-17ae5eba0e6fa54f756e11c33db3c12c
01VATICAN1261, 01VATICAN1261, 1-5b2bb5179171b8fdb6cf5c49e70f7efc
01VATICAN3507, 01VATICAN3507, 1-cf8f30b56ae3b022a9a13c18e9861fdf
02BRASILIA4227, 02BRASILIA4227, 1-618545c581de8c36034e69125ab91b91
02ROME1196, 02ROME1196, 1-c3886574e19883f1710941c5306f58c8
02VATICAN819, 02VATICAN819, 1-118b2bb09f1aeb02771368f88ec03439
03ABUDHABI2641, 03ABUDHABI2641, 1-9253471e5f4f776c89032acb245cab44
03BRASILIA3122, 03BRASILIA3122, 1-03f664271441db15b2a72730af841c11
Ces valeurs sont la clé, l’identifiant (dans ce cas, égal à la clé), et le numéro de révision de chaque document.
Pour aller chercher un document particulier il suffit de solliciter l’URL correspondant à son identifiant : par exemple https://upondata.com/cablesgate/00H... ; le document s’affiche alors au format JSON.
Une deuxième boucle (DATA)
permet d’afficher proprement les champs du document :
<BOUCLE_cable(DATA)
{source json, https://upondata.com/cablesgate/00HARARE5461}
>
[<dt>#CLE</dt>
<dd><kbd>(#VALEUR|print)</kbd></dd>]
</BOUCLE_cable>
Résultat :
- _id
- 00HARARE5461
- _rev
- 1-ab2f3b839699e38a0ade9a69580d3807
- origin
- CONFIDENTIAL
- date_time
- 2000-09-27 14:02
- body
- C O N F I D E N T I A L SECTION 01 OF 02 HARARE 005461 SIPDIS NSC FOR SENIOR AFRICA DIRECTOR GAYLE SMITH LONDON FOR CHARLES GURNEY PARIS FOR BISA WILLIAMS PASS USTR FOR ROSA WHITAKER EO 12958 DECL : 09/21/10 TAGS PGOV, PINS, ZI, MDC, ZANU-PF (...)
- classification
- 2010-12-18 21:09
- header
- This record is a partial extract of the original cable. The full text of the original cable is not available. (...)
- refererence_id
- 00HARARE5461
Remarque : à l’inverse des boucles standard de SPIP, basées sur SQL, on voit donc qu’il faut ici appeler des services différents pour obtenir soit un document, soit une liste de documents.
Ajoutons maintenant quelques bidouilles décoratives :
— pagination
— passage de l’identifiant du câble par la variable #ID
— utilisation du critère {si #ID}
pour ne lancer la <BOUCLE_cable ...>
qu’en présence d’un identifiant
— gestion des sauts de ligne, marqués dans le champ body
par la séquence 

Et nous obtenons, en deux boucles, une première version de notre application :
<B_liste>
[<p class="pagination">(#PAGINATION)</p>]
<ul>
<BOUCLE_liste(DATA)
{source json, https://upondata.com/cablesgate/_all_docs}
{datapath rows}
{pagination 10}
>
<li><a href="[(#SELF|parametre_url{id,#VALEUR{id}})]"
>#VALEUR{id}</a></li>
</BOUCLE_liste>
</ul>
</B_liste>
<B_cable>
<h2>#ID</h2>
<BOUCLE_cable(DATA)
{source json, https://upondata.com/cablesgate/#ID}
{si #ID}
>
[<dt>#CLE</dt>
<dd><kbd>(#VALEUR|print|replace{
,<br />})</kbd></dd>]
</BOUCLE_cable>
Trier par date, afficher le sujet
Pour aller plus loin, on veut pouvoir afficher notre liste de documents non pas dans l’ordre de stockage dans la base de données, mais selon leur date de publication (donnée dans le champ classification
de la base de Benoît... on dirait qu’il s’est un peu emmêlé les pinceaux dans ses nommages...) ; on veut aussi afficher à côté le sujet du câble, qu’il va falloir extraire du champ body
de chaque document.
Pour cela, il faut ajouter une vue à la base de données. Comme celle-ci est gérée par Benoît Chesneau, nous n’y avons pas accès en écriture, et ne pouvons donc rien y ajouter. Nous allons donc créer une base CouchDB nous appartenant, dans laquelle on va recopier (« replicate » en langage CouchDB) celle de Benoît, puis ajouter notre vue.
Deux méthodes :
— soit on installe CouchDB sur notre serveur http://wiki.apache.org/couchdb/Inst...
— soit on crée un compte hébergé sur www.couchone.com
Dans les deux cas, l’interface Futon permet de naviguer facilement dans les données. Une fois notre base créée, on utilise le menu Replicator pour lui dire de recopier la base source https://upondata.com/cablesgate
dans la nôtre.
- Replicator
Nous ajoutons ensuite une vue (view) :
- View
Voici le code de notre vue ; c’est un JSON décrivant une fonction map
écrite en javascript.
{
"classification": {
"map": "function (doc) {
if (doc.body && (doc.subject = doc.body.match(/SUBJECT:(.*?)

/))) {
doc.subject = doc.subject[1].substr(0,300);
}
else {
doc.subject = 'Untitled';
}
emit(doc.classification, {
date_time:doc.date_time,
subject:doc.subject,
origin:doc.origin||null
});
}"
}
}
Comme on l’a vu avec la boucle ci-dessus, chaque document contient un champ classification
avec la date de mise en ligne du document.
Notre fonction map:
va donc émettre, pour chaque document, une clé correspondant à cette valeur doc.classification
, ce qui permettra de trier les résultats selon cette valeur. On émet aussi, en valeur, un sujet extrait à coup d’expression rationnelle du doc.body
(quand c’est possible), ainsi que les champs date_time
et origin
du document.
Dès lors, si on appelle l’URL /_design/sort/_view/classification
sur notre base CouchDB, on obtient la liste des câbles triés par date de mise en ligne, ainsi que leur sujet et niveau de classification.
{
"id":"04ANKARA348",
"key":"2010-11-28 18:06",
"value":{
"date_time":"2004-01-20 12:12",
"subject":"Untitled",
"origin":"CONFIDENTIAL"
}
},
{
"id":"04ANKARA7211",
"key":"2010-11-28 18:06",
"value":{
"date_time":"2004-12-30 05:05",
"subject":"Untitled",
"origin":"SECRET"
}
},
{
"id":"05ABUDHABI2178",
"key":"2010-11-28 18:06",
"value":{
"date_time":"2005-05-16 09:09",
"subject":"Untitled",
"origin":"SECRET"
}
},
{
"id":"05ANKARA1730",
"key":"2010-11-28 18:06",
"value":{
"date_time":"2005-03-25 09:09",
"subject":" TURKEY ADRIFT",
"origin":"CONFIDENTIAL"
}
},
...
Pour les obtenir dans l’ordre inverse (les plus récents en premier), on utilise l’URL /_design/sort/_view/classification?descending=true
.
Notre application complète
Voici au final le squelette de notre application complète. Ici, on a installé CouchDB en local, l’URL de notre base est http://127.0.0.1:5984/cablegate
#SET{base,http://127.0.0.1:5984/cablegate}
<B_liste>
[<p class="pagination">(#PAGINATION)</p>]
<ul>
<BOUCLE_liste(DATA)
{source json, #GET{base}/_design/sort/_view/classification?descending=true}
{datapath rows}
{pagination 5}
>
<li><a href="[(#SELF|parametre_url{id,#VALEUR{id}})]"
>#VALEUR{id}</a><br />
<small>#VALEUR{value/subject}<br />
[(#VALEUR{value/date_time})] | #VALEUR{value/origin}
</small>
</li>
</BOUCLE_liste>
</ul>
</B_liste>
<B_cable>
<h2>#ID</h2>
<BOUCLE_cable(DATA)
{source json, #GET{base}/#ID}
{si #ID}
>
[<dt>#CLE</dt>
<dd><kbd>(#VALEUR|print|replace{
,<br />})</kbd></dd>]
</BOUCLE_cable>
Résultat :
0 | 5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | ...
- 09BRASILIA1239
HANDLING VISA REQUEST FROM BRAZILIAN INVOLVED IN THE 1969 KIDNAPPING OF THE U.S.
2009-10-15 17:05 | SECRET//NOFORN- 04BRASILIA2803
Untitled
2004-11-12 16:04 | UNCLASSIFIED//FOR OFFICIAL USE ONLY- 10SANTIAGO25
Meet Chile's President-Elect, Sebastian Pinera
2010-01-22 20:08 | CONFIDENTIAL- 09SANTIAGO867
CHILE: Conservatives Beat Back Skeleton in Pinera's Closet
2009-10-09 15:03 | CONFIDENTIAL- 08SANTIAGO249
CHILE'S "NEXT PRESIDENT" WILL PROPOSE A "NEW DEAL": A TAD EARLY FOR COMPARISONS TO FDR
2008-03-17 14:02 | CONFIDENTIAL04BRASILIA2803
_id 04BRASILIA2803 _rev 1-385f6e7e62f2249fb1877e04b9819021 origin UNCLASSIFIED//FOR OFFICIAL USE ONLY date_time 2004-11-12 16:04 body UNCLAS BRASILIA 002803
SIPDIS
SENSITIVE
PORT-AU-PRINCE FOR AMB. FOLEY
E.O. 12958 : N/A
TAGS : PREL PGOV BR HA POL MIL
¶ 1. (SBU) On November 9, Brazilian Federal Deputy Maninha paid a courtesy call on Ambassador Danilovich. Maninha is the current president of COPA (Confederation of the Parliaments of the Americas), and this week she...classification 2010-12-28 00:12 header This record is a partial extract of the original cable. The full text of the original cable is not available. refererence_id 04BRASILIA2803
La démo est visible ici : http://zzz.rezo.net/cablegate/.
* * *
J’espère que cet exemple vous aura donné envie de jouer avec SPIP et CouchDB. N’hésitez pas à utiliser le forum ci-dessous pour partager vos expériences.