• Aucun résultat trouvé

Expressions avec arguments de type node-set

Un node-set, nous l’avons déjà dit, est un ensemble de nœuds provenant d’une source XML, et plus précisément de la représentation sous forme d’arbre XML de cette source. Qu’un élément appartienne à un node-set n’implique pas que sa descendance en fasse nécessairement partie : par exemple, on peut très bien avoir un node-set ne contenant qu’un seul élément, à savoir l’élément racine du document, sans que pour autant, tout le document se retrouve dans le node-set.

Un node-set est un ensemble au sens mathématique du terme : une collection non ordonnée de nœuds d’arbre XML, sans doublon.

Il n’y a qu’un seul opérateur ensembliste : l’opérateur "|" (la barre verticale), qui repré- sente l’union ensembliste. Il est toutefois possible d’écrire une expression, pas très com- pliquée en termes de nombre de caractères, mais très difficile à imaginer quand on ne connaît pas la solution, qui donne l’intersection de deux node-sets.

Il n’y a pas non plus d’opérateur ou de fonction prédéfinie permettant de tester l’apparte- nance d’un nœud à un node-set (sinon il aurait été trivial de construire une expression donnant l’intersection), ou l’inclusion d’un node-set dans un autre. Par contre, on a une fonction prédéfinie, count(), qui renvoie le nombre d’éléments du node-set donné, ce qui permet (entre autres) de tester si un node-set est vide.

Les choses amusantes arrivent maintenant. Il est possible, grâce aux opérateurs = et !=, de comparer des node-sets. Les règles de comparaison sont à première vue assez cu- rieuses, et en tout cas, ont des conséquences assez étonnantes, comme par exemple celle- ci : si $p est un node-set, alors $p = $p n’est pas une expression toujours vraie.

Comparaison de deux node-sets avec l’opérateur =

Si $p et $q sont deux node-sets, alors $p = $q est une expression booléenne vraie si et seulement si on peut trouver dans $p un nœud N1 et dans $q un nœud N2 qui ont même valeur textuelle.

Note

C’est d’ailleurs si peu évident à trouver que les concepteurs du standard XPath étaient loin d’imaginer que c’était faisable lorsque le standard est paru dans sa version définitive, en 1999. En fait, il a fallu attendre l’année 2000 pour que quelqu’un (Michael Kay, en l’occurrence) découvre cette fameuse expression, que voici :

$p[count (.|$q) = count($q)], qui donne l’intersection des deux node-sets $p et $q. Il n’est pas possible d’expliquer dès maintenant pourquoi le résultat obtenu est le bon, car il faut attendre d’avoir vu la notion de prédi- cat, qui est ici utilisée, ainsi que celle de nœud contexte (le point, juste avant la barre verticale).

Remarque

Avant de voir ceci plus en détail, demandons-nous pourquoi aller chercher des règles diaboliques qui parsèment la route de chausse-trappes, au lieu de mettre en place de règles classiques qui seraient intuitivement évi- dentes ? A nouveau, il ne faut pas imaginer que le standard XPath est un document loufoque, pratiquant l’humour par l’absurde. En fait ces règles sont bizarres quand on les examine en dehors de leur contexte, et qu’on les replace dans le contexte général (mathématique) de manipulation d’ensembles. Mais ce n’est pas dans ce contexte-là que ces expressions sont employées ; ces règles sont faites pour écrire des prédicats de façon concise. Il est encore trop tôt pour expliquer exactement ce qu’est un prédicat, mais disons en gros qu’un prédicat est une expression booléenne qui permet de filtrer un node-set pour éliminer les indésirables, à savoir les nœuds qui ne vérifient pas le prédicat. C’est donc à la lumière de la facilité d’écriture de prédicats qu’il faut éclairer les règles de comparaison de node-set, et non à la lumière des mathématiques standard. En cherchant à optimiser au mieux l’écriture de certains types de prédicats qui reviennent souvent dans la pratique, on arrive à des choses qui peuvent donner froid dans le dos au premier abord, mais qui finalement se révèlent très effi- caces à l’usage, quand on écrit des prédicats. Le seul problème est que les comparaisons de node-sets peuvent intervenir ailleurs que dans des prédicats, par exemple dans des tests, avec l’instruction XSLT <xsl:if ...>. C’est là qu’on peut déraper, parce qu’on n’est plus dans le domaine privilégié des prédicats, et que l’on doit être conscient des pièges que constituent ces règles vis-à-vis de la logique habituelle.

Cette définition repose sur la valeur textuelle d’un nœud, qui a été définie à la section

Modèle arborescent d’un document XML vu par XPath, page 30.

On voit tout de suite qu’il faut pouvoir trouver au moins un nœud dans chacun des node- sets pour que l’égalité ait une chance d’être vraie ; il en résulte immédiatement que deux node-sets vides ne sont pas égaux, et même pire, que $p = $p est faux si $p est vide. Un autre point à prendre en compte, est que la valeur textuelle d’un nœud ne reflète peut-

être pas totalement toutes les propriétés visibles de ce nœud.

Par exemple, supposons que $p contienne l’élément <animal hauteur="3m">girafe</ani- mal>, et $q l’élément <animal hauteur="5m">girafe</animal> ; alors l’égalité $p = $q

est vraie. En effet, les attributs ne font pas partie de la valeur textuelle d’un élément : les deux éléments ci-dessus ont donc même valeur textuelle, ce qui suffit à donner l’égalité.

Comparaison de deux node-sets avec l’opérateur !=

Si $p et $q sont deux node-sets, alors $p != $q est une expression booléenne vraie si et seulement si on peut trouver dans $p un nœud N1 et dans $q un nœud N2 qui ont des valeurs textuelles différentes.

D’après les deux définitions que l’on vient de voir, il est immédiat que : not( $p = $q )

et ( $p != $q ) sont deux expressions différentes, qui ne donnent pas en général le même résultat. Il en est de même avec not( $p != $q ) et ( $p = $q ) .

L’expression not( $p = $q ) est vraie quand les deux node-sets ont des valeurs tex- tuelles toutes différentes deux à deux. De même, l’expression not( $p != $q ) est vraie quand les deux node-sets ont des valeurs textuelles toutes identiques deux à deux. Notez bien encore une fois que les comparaisons reposent sur des comparaisons de valeurs textuelles ; il n’est pas question ici d’identité : revoyez ci-dessus l’exemple de la girafe, qui montre bien les limites de ces comparaisons.

Appartenance et test d’inclusion

Tester si deux node-sets sont constitués des mêmes nœuds est beaucoup plus subtil ; c’est le même problème, en gros, que de tester si un nœud donné appartient ou non à un node- set. Pour cela l’idée de base est d’ajouter au node-set le nœud en question ; si cela ne change pas le cardinal du node-set, c’est que le nœud s’y trouvait déjà (puisqu’un node- set est un ensemble, et qu’à ce titre, il ne saurait y avoir des doublons). Il faut donc se débrouiller pour former un node-set (disons $p) ne contenant que le nœud à tester ; pour savoir si ce nœud appartient à un autre node-set $q, il suffit de tester l’expression

count( $p | $q ) = count( $q ).

Note

C’est cette idée qui a mis du temps à voir le jour.

Détail amusant, on peut voir à l’adresse http://dpawson.co.uk/xsl/sect2/muench.html, que Michael Kay en a eu la révélation dans son bain.

Plus généralement, l’expression count( $p | $q ) = count( $q ) est vraie si et seule- ment si le node-set $p est inclus dans $q.

Dans la même veine, on voit immédiatement que les deux node-sets $p et $q sont iden- tiques (égaux au sens mathématique du terme) si et seulement si :

(count( $p | $q ) = count( $q )) and (count( $p | $q ) = count( $p ))

Documents relatifs