Chapitre 11. Introduction aux liaisons de données

Table des Matières

1. Introduction
2. Les bases
2.1. Plusieurs lignes de données
3. Façons d'inclure des données
3.1. Données embarquées
3.2. Données incluses
3.3. Données HTTP
4. Pointeurs de données

1. Introduction

Nous allons voir comment interagir avec les données en LZX.

2. Les bases

En ce qui concerne l'import des données dans les applications LZX, nous travaillons toujours en XML. Une déclaration XML n'est pas nécessaire, mais le XML doit avoir un seul noeud racine. Les données sont contenues dans la balise <dataset>.

Exemple 11.1. Ensemble de données

<canvas height="80" width="500" >
  <dataset name="myData">
    <myXML>
      <person show="simpsons">
        <firstName>Homer</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Marge</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Montgomery</firstName>
        <lastName>Burns</lastName>
      </person>
    </myXML>
  </dataset>
  
  <text datapath="myData:/myXML[1]/person[1]/firstName[1]/text()"/>
</canvas>

Dans l'exemple précédent, le noeud racine unique est myXML. L'attribut datapath de la balise <text> crée la liaison avec les données.

Les "datapaths" (chemins de données) utilisent des attributs au format XPath pour naviguer à traver les données XML. Le nom du groupe de données (dataset) à utiliser se trouve avant les deux points dans l'expression myData:, suivi des noeuds séparés par le symbole '/'. Les crochets permettent de préciser le noeud particulier recherché. Par défaut, la valeur est [1], donc l'exemple précédent pourrait être réécrit sans aucun "[1]".

De façon littérale, l'exemple précédent pourrait être formulé ainsi : "donne-moi le texte du premier noeud 'firstName', du premier noeud 'person' du premier noeud (il n'y en a qu'un) 'myXML'". L'appel à la méthode text() renvoie le texte du noeud.

Pour obtenir le nom de 'Marge', nous pourrions réécrire la balise <text> de la façon suivante :

<text datapath="myData:/myXML/person[2]/firstName/text()" /> 

Nous avons ici omis les "[1]" car ils sont implicites. Pour obtenir l'attribut "show" de 'Montgomery', nous pourrions écrire :

<text datapath="myData:/myXML/person[3]/@show" /> 

Le code /text() est nécessaire avec l'attribut datapath.

Nous avons donc utilisé la balise <text> avec un chemin de données simple. Si nous voulions présenter des données sous forme de tableau, chaque élément texte devrait avoir son propre chemin de données, ce qui serait à la fois difficile et fastidieux à écrire. Au lieu de cela, construisons le tableau en associant un chemin de données à une vue (<view>) :

Exemple 11.2. Affectation d'un chemin de données à une vue

<canvas height="80" width="500">
  <dataset name="myData">
    <myXML>
      <person show="simpsons">
        <firstName>Homer</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Marge</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Montgomery</firstName>
        <lastName>Burns</lastName>
      </person>
    </myXML>
  </dataset>

  <view name="rowOfData" datapath="myData:/myXML[1]/person[1]">
    <simplelayout axis="x" />
    <text datapath="firstName/text()" /> 
    <text datapath="lastName/text()" /> 
    <text datapath="@show" />
  </view>
</canvas>

Le chemin de données de la vue 'rowOfData' la fait pointer sur l'ensemble du noeud person correspondant à Homer. Les éléments fils de ' rowOfData' héritent de cela, leur chemin de données pouvant alors être défini de façon relative.

2.1. Plusieurs lignes de données

Dans l'exemple précédent, nous avons utilisé un noeud 'rowOfData' simple. Maintenant nous pouvons parcourir un ensemble de noeuds :

Exemple 11.3. Ensemble de noeuds

<canvas height="80" width="500" >
  <dataset name="myData">
    <myXML>
        <person show="simpsons">
          <firstName>Homer</firstName>
          <lastName>Simpson</lastName>
        </person>
        <person show="simpsons">
          <firstName>Marge</firstName>
          <lastName>Simpson</lastName>
        </person>
        <person show="simpsons">
          <firstName>Montgomery</firstName>
          <lastName>Burns</lastName>
        </person>
      </myXML>
  </dataset>

  <view name="myTable">
    <simplelayout axis="y" />
    <view name="rowOfData" datapath="myData:/myXML[1]/person">
      <simplelayout axis="x" />
      <text datapath="firstName/text()" /> 
      <text datapath="lastName/text()" /> 
      <text datapath="@show" />
    </view>
  </view>
</canvas>

Une balise qui contient l'attribut datapath sera répétée autant de fois que nécessaire.

Souvenez-vous que les chemins de données sont liés à des vues, et qu'ainsi, si les données changent, les vues aussi. Nous reviendrons là-dessus un peu plus tard.

3. Façons d'inclure des données

Jusque là, nous avons utilisé des données embarquées, c'est à dire que les données XML étaient contenues dans le document. C'est parfait pour un petit nombre de données statiques, mais il y a d'autres méthodes qui conviennent mieux aux grandes quantités de données (et aux données dynamiques).

Type d'inclusion Quand sont-elles chargées ? Syntaxe
Données Embarquées A la compilation
<dataset name="myData">
  <myXML>
     <!-- ... other XML tags ... -->
  </myXML>
</dataset>
Données incluses A la compilation
<dataset name="myData" src="myXMLDoc.xml"/>
Données HTTP Pendant l'exécution
<dataset name="myData" request="true" 
         type="http" src="myXMLDoc.xml" />

3.1. Données embarquées

Les données sont embarquées sous forme de XML à l'intérieur de balises <dataset>. Quand le Serveur OpenLaszlo compile l'application, les données sont associées. Les données peuvent être changées après le lancement de l'application. Les données embarquées sont statiques.

3.2. Données incluses

Les données incluses le sont de la même façon que les données embarquées sauf que le XML contenant les données est placé dans un fichier séparé. La durée du chargement initial sera la même que pour des données embarquées.

Le fichier est référencé localement dans le système de fichiers, il peut donc être placé dans d'autres répertoires. Les données incluses sont statiques.

3.3. Données HTTP

Les données distantes sont transmises via HTTP, ce qui signifie qu'elles peuvent (mais pas obligatoirement) être dynaniques. Si elles sont statiques, alors la seule différence entre ce mode et le mode inclus ou embarqué, c'est qu'elles sont téléchargées après le chargement de l'application. L'attribut type="http" précise que c'est une requête HTTP. Les requêtes peuvent être à la fois de type GET et POST.

Le client peut demander les données à différents moments :

  • Le client peut demander les données dès que l'application est chargée si l'attribut request du groupe de données (dataset) est positionné à 'true'.

  • Si l'attribut request vaut 'true', le client demandera aussi les données à chaque fois que la chaîne de requête ou le chemin URL du groupe de données changera (en utilisant respectivement les méthodes setQueryString() et setSrc() de l'objet LzHTTPDataset).

  • Quand la méthode doRequest() du groupe de données (dataset) est invoquée.

Dans le tableau ci-dessus, nous avons référencé un fichier localement (myXMLDoc.xml), mais nous aurions pu le faire de façon absolue ou nous aurions pu appeler un serveur distant (PHP, ASP, JSP ou un CGI) pour renvoyer un document XML. Nous pourrions ajouter la chaîne de requête à la balise <dataset> :

<dataset name="myData"
         src="http://www.myServer.com/cgi-bin/myXMLDoc.cgi?return=addresses"/>

L'attribut type="http" devient implicite quand l'attribut src contient "http://".

4. Pointeurs de données

Les chemins de données (datapaths) sont extrêmement pratiques, mais si vous avez besoin de plus de contrôle sur les données, ils peuvent devenir fastidieux à utiliser. Les chemins de données (datapaths) sont en fait des extensions des pointeurs de données (datapointers), mais sont plus faciles à apprendre, c'est pourquoi nous les avons introduits en premier. Un pointeur de données est un pointeur dans un groupe de données (dataset), qui peut être déplacé. Il ne peut être qu'à une position du groupe de données en même temps, mais vous pouvez avoir plusieurs pointeurs de données, chacun pointant sur un endroit différent du groupe de données.

Les pointeurs de données (datapointers) ne sont pas liés à des vues comme les chemins de données (datapaths), mais ils ont une position dans la hiérarchie de vues (c'est à dire qu'ils connaissent parents et enfants).

Nous utiliserions un pointeur de données si nous devions travailler sur les données. Par exemple, en utilisant le même format de données que dans les exemples précédents, supposons que vous vouliez trouver toutes les personnes présentes au 'South Park show' :

Exemple 11.4. Utilisation des pointeurs de données

<canvas height="180" width="500" debug="true">
  <dataset name="myData" src="../myShowData.xml" />
  
  <datapointer xpath="myData:/" ondata="processData()">
    <method name="processData">
      this.selectChild(2); 
      do {
        if (this.xpathQuery( '@show' ) == 'south park') {
            Debug.write(this.xpathQuery('firstName/text()'));
        }
      } while (this.selectNext()); 
    </method>
  </datapointer>
</canvas>

Pour limiter le code, nous avons écrit dans le débogueur, et avons récupéré les données dans un fichier local. Vous pouvez télécharger le fichier XML en haut de cette page.

L'appel à selectChild(2) commence par sélectionner le premier noeud <myXML>, puis le noeud <person> correspondant à Homer. Il en parcourt 2 à cause de l'argument de profondeur "2" passé en argument (la valeur par défaut est 1).

L'appel à selectNext renvoie true tant qu'un noeud peut être sélectionné (c'est à dire jusqu'à ce qu'il n'y en ait plus). Nous utilisons une boucle do while de façon à parcourir tous les noeuds <person> dans la même itération.

Nous aurions aussi pu récupérer les erreurs en définissant des gestionnaires d'événements sur les événements onerror et ontimeout de la balise <datapointer>.