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 :

#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

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

Le résultat

name
Fil
sex
F
birthday
1966-08-17
job
Calorifugeur
friends
Array
friends_lang
Array
status
Pour votre gouverne, je vous signale qu’un grand nombre de sociologues et de psychologues postulent qu’un magasin est un espace qui n’est ni public, ni privé, mais intermédiaire car combinant des éléments de l’un et de l’autre. Ainsi, un étalage dans une vitrine peut être considéré comme une image mentale projetée sur la conscience collective, permettant de promouvoir une conformité qui ne participe pourtant que du domaine censément privé constitué par les goûts personnels des clients…
city
Lescheraines (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

Le résultat

name
Fil
sex
F
birthday
1966-08-17
job
Calorifugeur
friends
Maude Deschamps, Romain Robin, Alix Marie, Gil Bertin, Tatiana Pichon, Matthieu Noël, Xavier Allard, Jean-Noël Lopes, Gwenaël Voisin, Adam Schmitt, Brenda Ribeiro, Elie Legrand, Téo Fernandes, Léopold Sanchez, Marie-Line Merle, Cyril Müller, Marylène Blanc, Salim Maurice, Raymonde Hardy, Mathis Simon, Grégoire Laurent, Jackie Gillet, Théo Pérez, Martin Faure, Guy Sauvage, Daniel Hoarau, Renaud Mallet, Aymen Maillot, Clément Lefèvre, Killian Texier, Laurence Hubert, Jason Vincent, Delphine Bourgeois, Giovanni Leduc, Ema Benoît, Ahmed Boyer, Marinette Rivière, Jonas Bouvier, Nolwenn Roche, Martin Lebrun, Véronique Clément, Hervé Guyot, Albane Morin, Davy Millet, Ines Ferrand, Rémy Colas, Marie-Paule Bourgeois, Steve Labbé, Claudine André, Hedi Roche, Camille François, Yvonnick Marie, Ines Charles, Enzo Adam, Valentine Masson, Manuel Laurent, Cindy Hervé, Sébastien Durand, Yaël Pierre
friends_lang
fr, fr, fr, fr, fr, fr, en, en, fr, fr, fr, fr, fr, en, fr, fr, fr, fr, fr, en, fr, fr, fr, en, fr, fr, fr, fr, fr, en, fr, fr, fr, fr, fr, en, fr, fr, fr, en, fr, en, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, fr, en, fr, fr
status
Pour votre gouverne, je vous signale qu’un grand nombre de sociologues et de psychologues postulent qu’un magasin est un espace qui n’est ni public, ni privé, mais intermédiaire car combinant des éléments de l’un et de l’autre. Ainsi, un étalage dans une vitrine peut être considéré comme une image mentale projetée sur la conscience collective, permettant de promouvoir une conformité qui ne participe pourtant que du domaine censément privé constitué par les goûts personnels des clients…
city
Lescheraines (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 :

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

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

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

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 !