Les Itérateurs pour SPIP 2.1

Les itérateurs sont une fonctionnalité de la branche SPIP 3.*. Ils permettent de faire des boucles non plus seulement sur des articles et autres objets de la base de données SQL de SPIP, mais sur n’importe quoi : fichiers, tableaux de données, web services, etc. En savoir +

Ce plugin met cette fonctionnalité à disposition dans SPIP 2.1 (intégrée dans SPIP3). Prenez le temps de lire la documentation et de regarder les nombreuses démos disponibles dans le plugin « Démos des itérateurs ».

Voici quelques exemples des boucles que permettent les itérateurs de SPIP :

  • lire un tableau de données produit par une fonction quelconque
  • afficher le contenu d’un fichier local au format XML, CSV, JSON, YAML, iCalendar, etc.
  • boucler sur la liste des fichiers présents dans un répertoire du serveur
  • faire une requête sur un webservice et afficher les résultats.

Concrètement, on peut sans grand effort faire des boucles « Web 1.0 » sur toutes sortes de fichiers déposés sur le serveur. On peut aussi boucler en « Web 2.0 » sur des vidéos YouTube, sur des photos Flickr, des livres (par titre ou par numéro ISBN), sur des requêtes de traduction sur google.translate, sur un tableur édité sur Google Documents, etc.

Pour ne prendre qu’un seul exemple, voici une boucle qui permet d’afficher le contenu d’un tableur Google Documents :

Boucle :

[(#REM) Identifiant de notre tableur]
#SET{key,0AolUP3c6K9JodGwxRjJzb2hyTGZLU29qRVItRXk1VXc}
<B_csv>
<table>
<BOUCLE_csv(DATA)
{source csv, https://spreadsheets.google.com/pub?key=#GET{key}&hl=en&output=csv}>
<tr>
<td>#VALEUR{0}</td>
<td>#VALEUR{1}</td>
<td>#VALEUR{2}</td>
</tr>
</BOUCLE_csv>
</table>
</B_csv>

Résultat :

Pays PIB Population
Rémitanie 12 1
Baldoghistan 23 2
Républiques Unies 43 3
Diloduristan 12 4
Zarlatie 9 5

Ce plugin a été intégré dans SPIP 3 : https://www.spip.net/fr_article5444.html

Les liens de la documentation originale/officieuse (et en version bêta) :

 

Si vous utilisez ce plugin, n’hésitez pas à partager dans le forum ci-dessous vos formats, et toutes vos astuces pour boucler sur différents services et fichiers.

Discussion

24 discussions

  • bonjour, je me suis inspiré des réponses données à mirobulus pour mettre en place une liste déroulante pour sélectionner le nom d’un élève. Pour l’affichage des données de l’élève adapté son code à mon cas. j’ai juste modifié GET en POST et cela ne fonctionne pas.
    Je suis sur un serveur test :http://preuilly.preuillysurclaise.fr/?tap-derniere-periode
    j’ai utilisé ce code
    merci de votre aide si vous pouvez me dire ce que j’ai manqué car en GET je reviens sur la page d’accueil en POST j’affiche la liste complète des élèves.

    pj le code en image

    Répondre à ce message

  • 8
    AlainF

    Bonjour,
    Merci pour votre travail qui m’intérresse particulièrement.
    Avec comme configuration Spip 2.1.14 et le plugin Itérateurs pour Spip 2.1, je souhaite récupérer les éléments d’un fichier xml : soit le prix (pppp) d’un système de réservation.

    Fichier XML :

    <?xml version="1.0" encoding="utf-8"?>
    <message>
      <success />
      <pricingRangeResponse groupId="xxxx" beginDate="2012-06-01" endDate="2012-06-01" defaultCurrency="EUR">
        <hotel id="yyyy">
          <rate id="zzzzz" type="LowestMinimumPrice">
            <room id="rrrrr" price="pppp" />
          </rate>
        </hotel>
      </pricingRangeResponse>
    </message>

    En utilisant la boucle issue du plugin Itérateurs :

    <BOUCLE_r8(DATA){source xml, http://adresse.dufichier.xml}{datapath }>
    "#CLE":
    <B_f>
    <ul>
    <BOUCLE_f(DATA){source table, #VALEUR**}>
    <B_g>
    <li>"#CLE":
    	<BOUCLE_g(BOUCLE_f)/>
    </B_g><li>#VALEUR</li><//B_g></BOUCLE_f>
    </ul>
    </B_f>
    </BOUCLE_r8>

    je récupère tous les éléments :
    -  « success »
    -  « pricingRangeResponse »
    -  « xxxx »
    -  etc.
    dont « pppp » alors que je ne souhaite que la valeur « pppp » de « price= » :

    Je n’arrive pas à indiquer le(s) critère(s) nécessaire dans la boucle, si vous avez une idée, je suis preneur.

    Merci par avance.

    • En attendant une intégration un jour (c’est un peu tout neuf et en test), je vous propose de créer un fichier mes_fonctions.php dans votre squelettes contenant cette fonction :

      <?php
      
      /**
       * xml -> tableau
       * @param  string $u
       * @return array
       */
      function inc_simplexml_to_array_dist($u) {
      	return @xmlObjToArr(simplexml_load_string($u));
      }
      
      // http://www.php.net/manual/pt_BR/book.simplexml.php#108688 (17 mai 2012)
      function xmlObjToArr($obj) {
      # Cette fonction getDocNamespaces est tres gourmande sur de gros fichiers
      # $namespace = $obj->getDocNamespaces(true);
      
              $namespace[NULL] = NULL;
      
              $children = array();
              $attributes = array();
              $name = strtolower((string)$obj->getName());
      
              $text = trim((string)$obj);
              if( strlen($text) <= 0 ) {
                  $text = NULL;
              }
      
              // get info for all namespaces
              if(is_object($obj)) {
                  foreach( $namespace as $ns=>$nsUrl ) {
                      // atributes
                      $objAttributes = $obj->attributes($ns, true);
                      foreach( $objAttributes as $attributeName => $attributeValue ) {
                          $attribName = strtolower(trim((string)$attributeName));
                          $attribVal = trim((string)$attributeValue);
                          if (!empty($ns)) {
                              $attribName = $ns . ':' . $attribName;
                          }
                          $attributes[$attribName] = $attribVal;
                      }
      
                      // children
                      $objChildren = $obj->children($ns, true);
                      foreach( $objChildren as $childName=>$child ) {
                          $childName = strtolower((string)$childName);
                          if( !empty($ns) ) {
                              $childName = $ns.':'.$childName;
                          }
                          $children[$childName][] = xmlObjToArr($child);
                      }
                  }
              }
      
              return array(
                  'name'=>$name,
                  'text'=>$text,
                  'attributes'=>$attributes,
                  'children'=>$children
              );
          }
      
      ?>

      De la sorte vous pourrez utiliser

      <BOUCLE_r8(DATA){source simplexml, http://adresse.dufichier.xml}>

      Avec beaucoup plus d’information présentes. Utilisez [<pre>(#VALEUR|print_r{1})</pre>] pour les afficher et étudier comment récupérer votre info.

      #VALEUR{children} 
      #VALEUR{attributes}
      Peut être :
      #VALEUR{children/pricingRangeResponse/0/children/hotel/0/children/rate/0/children/room/0/attributes/price}
    • Pour http://spip3.quejai.me/xml-afficher-le-cours-du-dollar-des-30-derniers-jours j’ai corrigé la fonction inc_simplexml_to_array_dist ci-dessus pour en faciliter la lecture par la boucle DATA :

      /**
       * xml -> tableau
       * @param  string $u
       * @return array
       */
      function inc_simplexml_to_array_dist($u){
              return array('root'=>@xmlObjToArr(simplexml_load_string($u)));
      }
    • Hello,

      Cette fonction ça rend le xml utilisable dans SPIP ;-). Du coup, je l’ai :
      -  intégrée dans ce plugin (DATA, simplexml)
      -  mise dans un plug SPIP3 en attendant l’intégration au core http://files.spip.org/spip-zone/ite...
      -  accessoirement, dans la foulée, les démos ont été sorties dans un plugin séparé...

      Le tout dans le cadre du grand complot ircien.

    • Bonjour,

      j’ai une question un peu en rapport mais différente dans la structure.

      J’ai installé le plugin iterateurs simplexml qui permet de récupérer la clé d’une balise or à présent ce n’est pas la cle que je veux mais spécifier dans une liste ou un tableau les éléments du noeud ma valeur

      Donc je pensais faire un truc comme ça :

      #SET{xml, monfichierxml.xml}
      #SET{trier,#ARRAY}
      <BOUCLE_xml(DATA){source xml, #GET{xml}}
      {datapath Resultat/0}>
        #SET{trier,#GET{trier}|push{
                  #ARRAY{
                      produit,#VALEUR{0/PRODUIT/0},
                      hebergement,#VALEUR{0/NOM/0},
                      ville,#VALEUR{0/ADRPROD_LIBELLE_COMMUNE/0}
              }
        }
      <BOUCLE_crit(DATA){source simplexml, #GET{xml}}
      {datapath root/children/resultat/0/children/sit_liste/0/children/criteres}>
      #SET{trier,#GET{trier}|push{
           #ARRAY{
                photo,#VALEUR{children/crit/0/attributes/clef_criterephotos???}
            }
        }
      </BOUCLE_crit>
      </BOUCLE_xml>

      Suis-je sur la bonne voie ? Je pense que oui mais j’ai toujours le problème de récupérer la valeur par rapport à la clé pour spécifier, et si j’ai plusieurs valeurs sur la même clé comment je fais ? Encore un tableau dans le tableau ?

    • Hi

      Je m’arrache un peu les cheveux avec simple xml (qui par ailleurs fonctionne extrêmement bien). J’explique : lorsque je souhaite afficher une valeur (ici « paragraphe ») qui contient des balises imbriquées comme ceci

      <Paragraphe>
      <Valeur>9 605,40</Valeur> + <Valeur>4 802,70</Valeur> par enfant</Paragraphe>

      Je me retrouve avec des arrays parfaits mais sous forme arborescente dans le désordre :

      paragraphe: 
       0: 
        name: paragraphe
        text: + par enfant
        attributes: 
        children: 
         valeur: 
          0: 
           name: valeur
           text: 9 605,40
           attributes: 
           children: 
          1: 
           name: valeur
           text: 4 802,70
           attributes: 
           children:

      Dans l’exemple ci-dessus j’ai donc une partie de mon texte rassemblée au premier niveau puis d’autres parties au niveau inférieur et rien ne permet de replacer les valeurs de chaque côté du signe + pour reconstituer la phrase d’origine.

      Existe-t-il une solution ? Y aurait-il un filtre qui permette éventuellement de récupérer le contenu de la balise « paragraphe » tel quel et non en array ? Bref : AU SECOOOOUUUURS ! ;-)

    • A mon sens pas moyen de s’en sortir sans coder ton propre itérateur ; l’analyseur de XML qu’on exploite est assez sommaire, et ne correspond pas à ton besoin. Mais heureusement l’API interne des itérateurs est très facile à programmer : tu reçois en entrée le texte du XML, et en sortie tu dois fourninr un tableau des éléments sur lesquels tu vas itérer.

    • regarde quand même sur http://plugins.spip.net/itersimplexml.html, malheureusement pas documenté, sauf dans le forum juste au dessus.

      Et si tu dois faire ton propre iterateur, tu peux peut être utiliser http://plugins.spip.net/querypath.html

    • Mince. Comme le plugin simplexml n’est pas encore documenté j’espérais secrètement qu’il existe une astuce ou un filtre qui permette de stopper l’itération juste avant qu’elle n’entre dans la balise « paragraphe » et me permette d’en récupérer le contenu brut ou de le restaurer pour y appliquer ensuite autre chose. Je vais donc me pencher là-dessus. merci ;-)

    Répondre à ce message

  • 1

    Hello,

    Voici une technique pour lister un répertoire en triant les fichiers par date. J’ignore s’il y a plus simple, mais j’ai du recourir à deux boucles.

    #SET{table,#ARRAY}
    <BOUCLE_ls(DATA){source glob, #CHEMIN{lol/*.html}>[(#SET{table,#GET{table}|array_merge{#ARRAY{#VALEUR,#VALEUR|filemtime}}})]</BOUCLE_ls>
    <BOUCLE_ls2(DATA){source table, #GET{table}}{!par valeur}>#CLE : [(#VAL{Y-m-d H:i:s}|date{#VALEUR})]</BOUCLE_ls2>
    • il existe la méthode ’ls’ fournie avec iterateurs (Version : 1.0.0 [72598]) pour spip 2 et qui permet de faire :

      <BOUCLE_mon_ls(DATA) {source ls, squelettes-dist/*.html} {"<br >"} {!par mtime}>
         [(#VALEUR{file})] : [(#VALEUR{mtime})]
      </BOUCLE_mon_ls> 
        

      et on peut utiliser [(#VALEUR|foreach)] dans la boucle pour afficher toutes les clefs utilisables :

      - dirname => squelettes-dist
      - basename => test_boucle.html
      - extension => html
      - filename => test_boucle
      - dev => 234881026
      - ino => 8235281
      - mode => 33188
      - nlink => 1
      - uid => 501
      - gid => 501
      - rdev => 0
      - size => 607
      - atime => 1371188432
      - mtime => 1371188431
      - ctime => 1371188431
      - blksize => 4096
      - blocks => 16
      - file => test_boucle.html

    Répondre à ce message

  • 2

    Bonjour,

    je souhaiterai savoir si on peut faire une boucle DATA sur un lecteur réseau, je souhaite parcourir certains dossiers du lecteur et en afficher les fichiers.
    J’ai fait quelques tests avec glob sans résultat, je n’ai pas d’erreurs mais aucun resuĺtats.
    Je me suis basé sur ce code ci dessous en remplaçant IMG/jpg/*.jpg par le chemin de mon lecteur réseau, mais ça ne fonctionne pas.

    <BOUCLE_ls2(DATA){source glob, IMG/jpg/*.jpg}>
    [(#VAL{Y-m-d H:i:s}|date{#VALEUR|filemtime})] / #VALEUR
    </BOUCLE_ls2>

    Merci de votre aide !

    • Bonjour

      On peut avoir le code que tu as fait ?
      Avec le code IMG/ ça fonctionne ?

    • Bonjour,

      Avec IMG/ oui ça fonctionne, voici le code que j’ai utilisé :

        <BOUCLE_ls2(DATA){source glob, IMG/doc/*.doc}>
            [(#VAL{Y-m-d H:i:s}|date{#VALEUR|filemtime})] / #VALEUR
            </BOUCLE_ls2>

      Et voici le code utilisé pour accéder au lecteur réseau

        <BOUCLE_ls2(DATA){source glob, D:\\DF\\DSE\\PS\\Procedures\\Appli\\*.doc}>
            [(#VAL{Y-m-d H:i:s}|date{#VALEUR|filemtime})] / #VALEUR
            </BOUCLE_ls2>

      merci par avance !

    Répondre à ce message

  • J’ai bien cherché partout sur le forum et je n’ai pas vu un endroit où ce point aurait été abordé, alors voilà, je voulais signaler un point important à mes yeux :

    Les itérateurs c bôôôô

    -  même le mercredi soir à 23h23
    -  même dans le core

    Si, merci.

    Répondre à ce message

  • 5

    Bonjour,

    j’ai une question préalable stupide mais qui vient de me faire tourner en rond pendant une heure : comment fait-on pour afficher du code ici sans qu’il soit transformé (comme le font certains plus haut) ?
    J’avais un beau message de 50 lignes que j’ai finalement abandonné car mes boucles étaient explosées ... j’ai tenté tout ce que je connais, ma barre d’outil ne comporte pas les habituels boutons pour ça, aucun html n’est accepté, je ne peux pas mettre la balise code ... google n’est pas mon ami sur ce coup là ... bref j’ai fini par poster sur le forum ou tout ça marche nickel, mais je pense toujours que ma question serait mieux ici donc j’espère qu’une bonne âme me donnera le truc ... (d’ailleurs il me semble avoir déjà utilisé ça avant ...).

    Merci. Pierre.

    Répondre à ce message

  • 4

    Humm
    sur un spip tout neuf avec les plugins agenda , bonux ,cfg et crayons j’ai

    Parse error : syntax error, unexpected T_STRING, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ’}’ in /home/www/monsite/www/agenda/plugins/auto/iterateurs/public/iterateur.php on line 23.

    Les modifications du 30/12 réparent ça où c’est autre chose.

    En tout cas cette série de plugins à l’air très prometteuse .

    • N’oublions pas de dire qu’il faut PHP 5.1 minimum :) ... Et 5.3 pour utiliser glob() il me semble.

    • Non, pas glob ! glob fonctionne à partir de (PHP 4 >= 4.3.0, PHP 5)

    • Rectification... glob() c’est 4.3 pas 5.3... reste que les itérateurs, c’est PHP 5 qu’il faut. Nous allons le mentionner.

    • reda aourag

      bonjour

      si dans une requête sql avec itérateur je veux interroger une seconde base déclarer dans spip, pouvez vous me donner la syntaxe ?

      ex :

      #SETreq,« select libelle_commune, id_entree from spip_commune »

      • #LIBELLE_COMMUNE" - #ID_ENTREE

      merci par avance pour votre reponse

    Répondre à ce message

  • Hello

    Serait-il envisageable de pouvoir « paramétrer » la boucle ENUM afin de la faire tourner à l’envers ? (ça évite de faire un calcul ensuite)... Et p’têt même aussi que ça servirait si on pouvait faire varier le pas ?

    Répondre à ce message

  • 3

    Je viens de le faire, j’ai tout rechargé sur le serveur, et mon menu déroulant par famille de produits est toujours vide. Je ne comprends pas. Y a-til un cache au niveau du plugin ? Ou des fichiers qui se crèent ailleurs ? La page est ici

    • Vérifie bien ton squelette, car si le deuxième menu est vide, le premier est lui bien rempli

    • Merci pour ton aide.
      Pour le squelette, c’est justement le 2e formulaire que j’ai touché aujourd’hui en tentant d’inclure dans la boucle {cle>0}. Ensuite, j’ai enlevé cette chaîne de caractères et rebalancé sur le serveur. Et depuis, çà ne veut plus revenir comme avant.
      Précision : chaque formulaire de recherche est indépendant dans un fichier, dans le dossier formulaires.
      Je ne vois pas... Cà semble venir de la mémoire quelque part.

    • Çà remarche : j’ai vidé tout le contenu de mon dossier cache et renvoyé le fichier du formulaire famille.
      En tout cas, merci pour ta dispo. Maintenant, cette histoire de tri dans le contenu du menu déroulant reste à régler (comme tu le vois, il y a une cellule vide et l’item famille qui est la clé de ma colonne)..

    Répondre à ce message

  • 1

    {cle>0} ne fonctionne pas (mon menu disparaît de l’écran).
    {cle=0} m’affiche le menu avec une seule cellule vide.

    Depuis cet essai, impossible de faire refonctionner le bastringue : Rechargement dans l’espace privé + cache navigateur vidé + renvoi sur le serveur du fichier csv (et même déplacement) + réinstall du plugin : le menu déroulant reste à son dernier état (1 cellule vide) et la page de résultat de ma recherche ne m’affiche plus rien.

    Ce qui est étrange, c’est que ce n’est pas la 1re fois que çà m’arrive : ce matin, la recherche ne fonctionnait pas du tout alors que je n’avais rien touché depuis des jours.. Et çà se remet à fonctionner sans que je comprenne vraiment pourquoi. Avez-vous des soucis de ce genre ?
    Tiens, d’ailleurs, là, la page de résultat remarche, mais le menu déroulant reste vide.

    Répondre à ce message

Ajouter un commentaire

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Qui êtes-vous ?
[Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom