La boucle (DATA)

C’est une boucle capable d’itérer n’importe quel tableau de données.
Source : http://www.spip.net/fr_article5444.html.

Sa syntaxe de base est la suivante :

<BOUCLE(DATA) {source ...}> #BALISES </BOUCLE>

Le critère {source methode, données} définit les données sur lesquelles la boucle va itérer.

La définition d’une source de données nécessite deux éléments :

La partie données

Cet élément peut être de plusieurs natures :

  • un tableau de données, par exemple #ENV*
  • le chemin d’un fichier sur le disque dur, ex : sources/definitions.csv
  • l’URL d’un fichier ou d’un webservice, ex : http://per.sonn.es/bases/phobia.fr.yaml
  • ou encore, une chaîne quelconque que la methode saura transformer en tableau de données, ex : "select * from flickr.photos.search where text='spip'"

La partie methode

C’est la méthode avec laquelle on va interpréter les données. Elle porte en général un nom identique au format des données :

  • table (alias array ou tableau), pour un tableau déjà créé
  • csv, json, yaml pour un fichier composé dans l’un de ces formats
  • rss (alias atom) pour lire un flux de nouvelles
  • ics pour boucler sur des calendriers (nécessite le plugin icalendar : lire Plugin iCalendar)
  • json pour boucler sur des données aux format JSON (issues d’une API par exemple)

La méthode peut aussi parfois porter le nom d’une fonction qui sert à lire les données :

  • simplexml pour lire un fichier XML à l’aide de SimpleXML
  • file pour boucler sur les lignes d’un fichier
  • glob ou pregfiles pour boucler sur les fichiers d’un répertoire (et plus...)

La méthode peut aussi porter le nom de l’API utilisée :

  • yql pour envoyer une requête sur le webservice de Yahoo Query Language
  • sql pour envoyer une requête brute au serveur SQL (utiliser {source sql, connecteur:requete} pour envoyer la requête sur une base externe)

Ou enfin un nom court arbitraire pour une méthode spécifique sur mesure :

  • plugins pour lister les plugins actifs sur le site

Toutes ces méthodes sont déjà disponibles, et il est très aisé d’en créer de nouvelles, en créant une simple fonction inc_METHODE_to_array($u).
A titre d’exemple voici la fonction qui transforme un fichier JSON en tableau de données :

  1. function inc_json_to_array_dist($u) {
  2. if (is_array($json = json_decode($u, true))
  3. return $json;
  4. }

Télécharger

#CLE et #VALEUR

Lorsque les données sont lues avec la methode indiquée à au critère {source…}, SPIP construit un tableau de données, et le contenu de la boucle est alors executé pour chaque ligne de donnée.

Les balises #CLE et #VALEUR permettent d’afficher clé et valeur de ce tableau de données, comme ici avec une source de données YAML :

Le code

  1. <dl>
  2. <BOUCLE_yaml(DATA){source yaml,http://per.sonn.es/Fil.yaml}{0,4}>
  3. <dt>#CLE</dt>
  4. <dd>[(#VALEUR)]</dd>
  5. </BOUCLE_yaml>
  6. </dl>

Télécharger

Le résultat

name
Fil
sex
F
birthday
1966-08-17
job
Calorifugeur

Le filtre |print

La balise #VALEUR peut être de n’importe quelle nature : ce peut être une chaine de caractères, mais à son tour un tableau. Si l’on réprend l’exemple du fichier YAML en affichant toutes les données :

Le code

  1. <dl>
  2. <BOUCLE_yaml(DATA){source yaml,http://per.sonn.es/Fil.yaml}>
  3. <dt>#CLE</dt>
  4. <dd>[(#VALEUR)]</dd>
  5. </BOUCLE_yaml>
  6. </dl>

Télécharger

Le résultat

name
Fil
sex
F
birthday
1966-08-17
job
Calorifugeur
friends
Array
friends_lang
Array
status
Moi, c’que j’en dit...
info
Array
city
Mouxy (Rhone-Alpes)

On voit que certaines données ne sont pas visibles, remplacées par un simple "Array". Cela correspond aux cas où la donnée est elle-même un tableau.

Pour l’afficher simplement on utilise le filtre |print :

Le code

  1. <dl>
  2. <BOUCLE_yaml(DATA){source yaml,http://per.sonn.es/Fil.yaml}>
  3. <dt>#CLE</dt>
  4. <dd>[(#VALEUR|print)]</dd>
  5. </BOUCLE_yaml>
  6. </dl>

Télécharger

Le résultat

name
Fil
sex
F
birthday
1966-08-17
job
Calorifugeur
friends
Maude Guérin, Zohra Robin, Pierre-Yves Philippe, Lauriane Bertin, Jeannine Pichon, Vanessa Michel, Wendy Allard, Sylvie Michaud, Gwenaël Voisin, Paule Mary, Maia Ribeiro, Josianne François, Lucas Fernandes, Nora Berger, Marie-Line Alves, Aurore Müller, Marylène Girard, Eléa Maurice, Younès Bourgeois, Raymonde Simon, Grégoire Laurent, Magali Hervé, Théo Pérez, Malvina Gomez, Josephine Huet, Marie-Madeleine Hoarau, Janine Laroche, Béatrice Maillot, Lucie Dupuy, Axelle Texier, Lolita Hubert, Gisèle Paris, Maïlys Bourgeois, Melissa Vallee, Ema Teixeira, Marjorie Boyer, Jean-François Lefebvre, Christelle Bouvier, Jacques Lévy, Lila Lebrun, Lukas Clément, Mélanie Girard, Maxence Morin, Sandra Daniel, Killian Michaud, Aurélia Colas, Maël Dijoux, Louna Labbé, Théo Sanchez, Pascale Roche, Stephen François, Léonie Leroy, Hedi Charles, Roxane Mercier, Morgan Bourgeois, Marielle Laurent, Erwin Bertrand, Malvina Durand, Rémy Rossi, Amel Grégoire, Rodrigue Michel, Noémie Royer, Dominique Garcia, Sabrina Chauvin, David Prévost, Christianne Hervé, James Pinto, Christèle Petit, Maxime Guichard, Louise Barre
friends_lang
fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, en, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, en, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, en, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr
status
Moi, c’que j’en dit...
info

title: Le temps l’emporte
link: http://petiteracine.net/wordpress/2015/03/le-temps-l-emporte/?utm_source=rss&utm_medium=rss&utm_campaign=le-temps-l-emporte
author: admin
summary:   C’est une toute petite fille. Ce n’est déjà plus un bébé. Elle a ces déjà longs cheveux qui font toute la différence. Pour qu’ils soient si longs il a fallu du temps. Ils ondulent sagement, en deux courants calmes et épais autour du visage. On dirait un fleuve sombre contournant une île endormie. C’est [...]
city
Mouxy (Rhone-Alpes)

Le filtre |print produit un affichage humainement lisible de #VALEUR.

Lorsque #VALEUR est une simple liste comme pour les entrées friends ou friends_lang, celle-ci est affichée comme une énumération, séparée par des virgules.

Lorsque #VALEUR est un tableau plus compliqué, comme pour info, le filtre affiche une ligne par entrée, avec le nom de la clé du sous-tableau suivi de la valeur (elle même affichée selon les mêmes règles : chaine, énumération, ou tableau en lignes). On voit donc ici que l’entrée info se compose elle-même des sous entrées title, link, author et summary.

Filtrage, tri, pagination, fusion

Source : http://www.spip.net/fr_article5444.html.

Filtres

Comme les boucles traditionnelles de SPIP, les boucles (DATA) peuvent être filtrées par des critères du type {valeur=x} ; les opérateurs disponibles sont =, >, <, >=, <=, == (expression rationnelle) et LIKE.

Cependant ce filtrage s’effectue non pas en amont lors de la requête, comme en SQL, mais en aval, sur le tableau de données initialement récupéré.

Tris

Les tris {par xx} sont également possibles, avec leur variante {!par xx} pour trier en ordre inverse.

Pagination

La pagination {pagination 10} fonctionne comme sur toutes les boucles de SPIP, ainsi que le critère "offset/limit" {a,b}.

Fusion

Le critère {fusion /x/y} fonctionne aussi. Par exemple, pour un fichier d’adresses au format CSV, si l’email est le champ n° 3, on pourra ne retenir qu’un seul enregistrement par email avec la boucle suivante :

  1. <BOUCLE_csv(DATA){source csv, adresses.csv}
  2. {fusion /3}
  3. {par /0}{'<br />'}>
  4. #VALEUR{0} : #VALEUR{3}
  5. </BOUCLE_csv>

Télécharger

La fusion se fait après le tri, et retient le premier élément
rencontré. De cette manière, si un tableau est trie {!par date} puis fusionné sur l’email, l’enregistrement retenu pour chaque email sera le plus récent.

Le critère {datapath ...}

Les tableaux de données construits à partir des données sont parfois asses complexes, et il peut être compliqué ou lourd de les parcourir en profondeur à l’aide de nombreuses boucles imbriquées.
Source : http://www.spip.net/fr_article5443.html.

C’est là qu’intervient le critère {datapath ...}, qui permet d’indiquer à la boucle (DATA) le chemin du sous-tableau de données qui nous intéresse. Le chemin s’indique sous une forme Xpath : {datapath root/children/citation}.

Pour vous aider à déterminer le datapath, vous pouvez visualiser le tableau des résultats en l’affichant tout d’abord avec le filtre |print en insérant le code [<pre>(#VALEUR|print)</pre>] dans votre boucle (DATA).

Exemple complet pas à pas

Construisons un exemple de lecture d’un fichier XML, traditionnellement les plus compliqués à lire, avec la méthode simplexml.

On ecrit notre boucle (DATA) qui va chercher un fichier XML en ligne, et on affiche simplement le résultat. Comme notre exemple est très long on le coupe ici en ajoutant un filtre |substr{0,500})..., mais c’est tout à fait facultatif :

Le code

  1. <BOUCLE_cite(DATA)
  2. {source simplexml, http://zone.spip.org/trac/spip-zone/browser/_plugins_/citation_aleatoire/trunk/citations/citations_fr.xml?format=txt}>
  3. #CLE:: [(#VALEUR|print|substr{0,500})...]
  4. </BOUCLE_cite>

Télécharger

Le résultat

root::
name: citations
children:
 citation:
  0:
   name: citation
   children:
    auteur:
     0:
      name: auteur
      text: Victor Hugo
    texte:
     0:
      name: texte
      text: L’Homme est une prison où l’Âme reste libre.
  1:
   name: citation
   children:
    auteur:
     0:
      name: a...

Le filtre |print produit un affichage humainement lisible (qui ressemble à du YAML) du tableau de données construit à partir du fichier XML lu par la méthode simplexml : on voit ici que #VALEUR est un tableau à 2 entrées : name et children. Cette dernière entrée est elle même un tableau avec une seule entrée citation qui est un tableau à N entrées 0, 1

On va pouvoir alors renseigner le critère {datapath} pour se limiter à la partie des données qui nous intéressent, à savoir root/children/citation, en limitant la boucle au premier résultat pour vérifier notre {datapath}

Le code

  1. <BOUCLE_cite(DATA)
  2. {source simplexml, http://zone.spip.org/trac/spip-zone/browser/_plugins_/citation_aleatoire/trunk/citations/citations_fr.xml?format=txt}
  3. {datapath root/children/citation}{0,1}>
  4. #CLE:: [(#VALEUR|print)]
  5. </BOUCLE_cite>

Télécharger

Le résultat

0::
name: citation
children:
 auteur:
  0:
   name: auteur
   text: Victor Hugo
 texte:
  0:
   name: texte
   text: L’Homme est une prison où l’Âme reste libre.

On voit qu’on a ici une seule citation, qui est bien ce qu’on voulait. Pour aller chercher des informations précises dans le tableau #VALEUR on peut la aussi préciser le chemin au sens Xpath de la donnée qu’on veut récupérer. Par exemple #VALEUR{children/auteur/0/text} va aller chercher la valeur Victor Hugo.

Il ne reste plus alors qu’à mettre en forme les données, avec une pagination des résultats 3 par 3 :

Le code

  1. <B_cite>
  2. <dl>
  3. <BOUCLE_cite(DATA)
  4. {source simplexml, http://zone.spip.org/trac/spip-zone/browser/_plugins_/citation_aleatoire/trunk/citations/citations_fr.xml?format=txt}
  5. {datapath root/children/citation}{pagination 3}>
  6. <dt>#VALEUR{children/auteur/0/text}</dt> <dd>[((#VALEUR{children/texte/0/text}))]</dd>
  7. </BOUCLE_cite>
  8. <dl>
  9. [<div class='pagination'>(#PAGINATION{precedent_suivant})</div>]
  10. </B_cite>

Télécharger

Le résultat

Victor Hugo
(L'Homme est une prison où l'Âme reste libre.)
Pierre Desproges
(En cas de morsure de vipère, sucez-vous le genou, ça fait marrer les écureuils.)
Chateaubriand
(La mémoire est souvent la qualité de la sottise.)

On voit que nos résultats sont affichés 3 par 3 et l’on bénéficie même d’une pagination AJAX automatique !