1 <?xml version="1.0" encoding="utf-8" ?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
5 <html xmlns="http://www.w3.org/1999/xhtml" >
7 <title>XPath (suite)</title>
9 <meta http-equiv="Content-Type"
10 content="text/html; charset=utf-8" />
11 <meta name="copyright"
12 content="Copyright © 2013 Kim Nguyễn" />
15 <script src="../jquery-1.9.1.min.js" type="text/javascript" ></script>
16 <!-- Load the library -->
17 <script src="../simpleWebSlides.js" type="text/javascript" ></script>
19 <link rel="stylesheet" href="../simpleWebSlides.css" type="text/css" media="all" />
20 <!-- Load a custom Theme, the class-element marks this style-sheet
21 a "theme" that can be swtiched dynamicaly -->
22 <link class="sws-theme" rel="stylesheet" title="U-Psud style" href="../themes/uPsud.css" type="text/css" />
24 <!-- Customize some templates and initialize -->
25 <style type="text/css">
26 .xml-tag { color: #00486c; }
28 <script type="text/javascript">
30 SWS.Config['sws-slide-change'] = SWS.Effects.slideChangeFadeOutIn;
31 SWS.Config['sws-object-deactivate'] = SWS.Effects.objectDeactivateFadeOut;
32 SWS.Config['sws-object-activate'] = SWS.Effects.objectActivateFadeIn;
34 //Ensures that we load SWS at the very end, after MathJax has
37 $(window).load(function () {
38 $(".inline-xml").each(function(i, elem)
41 var code = jelem.html();
42 code = code.replace ("<![CDATA" + "[", "").replace ("]" + "]>", "");
43 code = code.replace (/>/g, ">>>");
44 code = code.replace (/</g, "<span class='xml-tag'><");
45 code = code.replace (/>>>/g,"></span>");
51 var checkSVG = function (o, i)
53 if (i >= 10 || SWS.Utils.isUndefined(o) || o == null) return;
54 var svg = o.getSVGDocument();
56 setTimeout(function() { checkSVG(o, i+1); }, 200);
58 var alltext = $(svg).find("text");
59 alltext.css("font-family", "DIN");
60 alltext.css("font-size", "70%");
64 $(window).load(function() {
65 $("embed").ready(function() {
66 setTimeout(function() {
67 $("embed").each(function(i, o) { checkSVG(this,0); });
71 $(window).load(SWS.Presentation.init);
79 <a href="xpi_02.xhtml" class="sws-previous"/>
80 <div class="sws-slide sws-cover sws-option-nofooter">
81 <h1>XML et Programmation Internet</h1>
83 <a href="mailto:kn@lri.fr">kn@lri.fr</a>
85 <h1>Évaluation des prédicats</h1>
86 <div class="sws-slide">
87 <h1>Rappels de syntaxe</h1>
92 | count(…), contains(…), position(), …
94 | e<sub>1</sub> op e<sub>2</sub>
96 <p>On évalue le prédicat et on converti son résultat en valeur de
97 vérité. Si la valeur vaut vrai, on garde le nœud courant, si elle
98 vaut faux, on ne le garde pas
100 <p>XPath connait <a>4 types de données</a> pour les prédicats : </p>
102 <li>Les booléens, valeur de vérité : vrai ou faux</li>
103 <li>Les nombres (flottants), valeur de vérité compliquée… </li>
104 <li>Les chaînes de caractères, chaîne vide = faux, sinon vrai</li>
105 <li>Les ensembles de nœuds, ensemble vide = faux, sinon vrai </li>
108 <div class="sws-slide">
109 <h1>Comparaisons (e<sub>1</sub> op e<sub>2</sub>)</h1>
110 <p> Les opérateurs de comparaisons sont : <tt>=, !=, <, <=,
111 >, >= </tt>.<br/>
112 La manière de calculer de vérité de <tt>e<sub>1</sub> op
113 e<sub>2</sub></tt> dépend du typed de <tt>e<sub>1</sub></tt>
114 et <tt>e<sub>2</sub></tt> :
117 <li>Si <tt>e<sub>1</sub></tt> et <tt>e<sub>2</sub></tt> représente
118 <a>des ensembles de nœuds</a>, alors la comparaison est vraie ssi
119 il existe un élément <tt>x</tt> dans <tt>e<sub>1</sub></tt> et un
120 élément <tt>y</tt> dans <tt>e<sub>2</sub></tt> tels que <tt>x op y</tt>
123 <li>Si <tt>e<sub>1</sub></tt> représente
124 <a>un ensembles de nœuds</a> et <tt>e<sub>2</sub></tt> une valeur
125 scalaire <tt>y</tt>, alors la comparaison est vraie ssi
126 il existe un élément <tt>x</tt> dans <tt>e<sub>1</sub></tt> tel que <tt>x op y</tt>
128 <li>Si <tt>e<sub>1</sub></tt> et <tt>e<sub>2</sub></tt> sont des
129 valeurs scalaires, alors ont les compare en utilisant les règles de
130 comparaison des valeurs scalaires (voir page suivante).
134 <div class="sws-slide">
135 <h1>Comparaisons des valeurs scalaires</h1>
136 <code> v<sub>1</sub> op v<sub>2</sub> </code>
137 <p>Si op est <tt>!=</tt> ou <tt>=</tt>, on applique les règles dans cet ordre:</p>
139 <li> Si <tt>v<sub>1</sub></tt> (resp. <tt>v<sub>2</sub></tt>) est
140 un <a>booléen</a>, alors <tt>v<sub>2</sub></tt>
141 (resp. <tt>v<sub>1</sub></tt>) est converti en booléen et les deux
142 booléens sont comparés </li>
143 <li> Sinon si <tt>v<sub>1</sub></tt> (resp. <tt>v<sub>2</sub></tt>) est
144 un <a>nombre</a>, alors <tt>v<sub>2</sub></tt>
145 (resp. <tt>v<sub>1</sub></tt>) est converti en nombre et les deux
146 nombres sont comparés </li>
147 <li> Sinon, <tt>v<sub>1</sub></tt> et <tt>v<sub>2</sub></tt> sont des
148 <a>chaines de caractères</a>, on les compares</li>
150 <p>Si op est <tt> <</tt>, <tt> <=</tt>, <tt> ></tt> ou <tt>
151 >=</tt>, on convertit <tt>v<sub>1</sub></tt>
152 et <tt>v<sub>2</sub></tt> en <a>nombres</a> et on les compare.
155 <div class="sws-slide">
157 <p>Conversion en booléen</p>
159 <li>0 et NaN sont converti en <tt>false</tt>, le reste
160 en <tt>true</tt> </li>
161 <li>Un ensemble de nœud vaut <tt>true</tt> ssi il est non vide</li>
162 <li>Une chaine vaut <tt>true</tt> ssi elle est non vide</li>
164 <p>Conversion en nombre</p>
166 <li>Une chaine de caractère représentant un flottant au format
167 IEEE-754 est convertie en ce nombre, sinon elle est convertie en NaN
169 <li>Booléen: <tt>true</tt> est converti à 1, <tt>false</tt> est
171 <li>Un ensemble de nœud est d'abord converti en chaine de caractères
172 puis la chaine est convertie en nombre</li>
175 <div class="sws-slide">
176 <h1>Conversions (suite)</h1>
177 <p>Conversion en chaine de caractères</p>
179 <li>Un booléen est traduit en <tt>"true"</tt> ou <tt>"false"</tt>
182 <ul><li>NaN est converti en la chaine <tt>"NaN"</tt></li>
183 <li>Si le nombre n'a pas de partie décimale, sa
184 représentation <i>entière</i> est convertie en chaine (ex:
185 1.000e10 ≡ <tt>"10"</tt>)</li>
186 <li>Sinon une représentation IEE-754 du nombre est utilisé
187 (ex: <tt>"123.10e-34"</tt>)
191 <li>Ensemble de noœud : <ul>
192 <li>L'ensemble vide est converti en la chaine vide
194 <li>Sinon le premier élément dans l'ordre du document est
195 converti en chaine en concatenant tous les nœuds textes dans ces
196 descendants (y compris lui-même)</li>
202 <div class="sws-slide">
203 <h1>Appels de fonction</h1>
204 <p>Il existe des fonctions prédéfinies (voir la spec XPath)</p>
206 <li><tt>contains(str<sub>1</sub>,str<sub>2</sub>)</tt></li>
207 <li><tt>starts-with(str<sub>1</sub>,str<sub>2</sub>)</tt></li>
208 <li><tt>count(node_set<sub>1</sub>)</tt></li>
209 <li><tt>last()</tt></li>
210 <li><tt>position()</tt></li>
213 <p>Si les arguments ne sont pas du bon type, ils sont convertis en
214 utilisant les règles de conversion</p>
216 <div class="sws-slide">
218 <p>Dans la suite, on se donne un document de test ayant une
219 racine <tt><![CDATA[<a> ... </a>]]></tt> et une expression XPath qui
220 sélectionne la racine si et seulement si le prédicat vaut vrai
223 <div class="sws-slide">
229 <ol> <li class="sws-pause">
230 <tt>/child::a[ child::*/child::text() ]</tt>
231 <span class="sws-pause">sélectionne la racine (l'ensemble de nœud
232 renvoyé par <tt>child::*/cild::text()</tt> est non vide, donc il est converti
233 en <tt>true</tt>)</span><br/><br/></li>
234 <li class="sws-pause">
235 <tt>/child::a[ child::*/child::text() = "2" ]</tt>
236 <span class="sws-pause">sélectionne la racine (l'ensemble de nœud texte
237 renvoyé par <tt>child::*/child::text()</tt> est comparé à "2", et
238 il existe un élément dans cet ensemble pour lequel le test réussi
239 )</span><br/><br/></li>
240 <li class="sws-pause"><tt>/child::a[ child::*/child::text() != "2" ]</tt>
241 <span class="sws-pause"><s>sélectionne la racine</s> (l'ensemble de nœud texte
242 renvoyé par <tt>child::*/child::text()</tt> est comparé à "2", et
243 il existe un élément dans cet ensemble pour lequel le test réussi
244 )</span><br/><br/></li>
245 <li class="sws-pause" style="background:white;"><tt>/child::a[ not(child::*/child::text() = "2") ]</tt>
246 <span class="sws-pause"><s>ne sélectionne pas la racine</s> (on
247 prend la négation du deuxième cas ci-dessus)
248 </span><br/><br/></li>
252 <div class="sws-slide">
259 <li class="sws-pause">
260 <tt>/child::a[ child::*/child::text() > 1.5 ]</tt>
261 <span class="sws-pause">sélectionne la racine (l'ensemble de nœud texte
262 renvoyé par <tt>child::*/child::text()</tt> est comparé à 1.5, et
263 il existe un élément dans cet ensemble pour lequel le test réussi
264 )</span><br/><br/></li>
265 <li class="sws-pause"><tt>/child::a[ child::b/child::text() >= child::c/child::text() ]</tt>
266 <span class="sws-pause"><s>sélectionne la racine</s> (les deux
267 ensembles de nœuds sont convertis en ensmbles de nombres, car on
268 utilise <tt>>=</tt> et on a bien que <tt>2 >= 2</tt>
269 )</span><br/><br/></li>
270 <li class="sws-pause"><tt>/child::a[ child::b/child::text() = child::c/child::text() ]</tt>
271 <span class="sws-pause"><s>sélectionne la racine</s> (les deux
272 ensembles de nœuds comportent un élément commun)</span><br/><br/></li>
273 <li class="sws-pause"><tt>/child::a[ child::b/child::text() != child::c/child::text() ]</tt>
274 <span class="sws-pause"><s>sélectionne la racine</s> (les deux
275 comportent des éléments différents)</span><br/><br/></li>
278 <div class="sws-slide">
280 <code> <![CDATA[ <a><b>1</b><b>2</b><c>2</c><c>3</c></a> ]]></code>
282 <li class="sws-pause">
283 <tt>/child::a[ contains(self::*, "22") ]</tt>
284 <span class="sws-pause"><s>sélectionne la racine</s>(l'ensemble de
285 nœud séléctionné par <tt>self::*</tt>, i.e. la racine est converti
286 en chaine. Pour ce faire, on colle toutes éléments textes
287 descendants et on obtient la chaine "1223" qui contient bien "22")
288 </span><br/><br/></li>
289 <li class="sws-pause">
290 <tt>/child::a[ self::* > 442.38 ]</tt>
291 <span class="sws-pause"><s>sélectionne la racine</s>(l'ensemble de
292 nœud séléctionné par <tt>self::*</tt>, est converti en chaine puis
293 en nombre pour comparer 1223 à 442.38)
294 </span><br/><br/></li>
296 <li class="sws-pause">
297 <tt>/child::a[ sum(child::*) >= 7.5 ]</tt>
298 <span class="sws-pause"><s>sélectionne la racine</s>(la fonction
299 <tt>sum</tt> converti la liste de valeurs passée en argument en
300 liste de nombre et fait la somme de ces derniers)
301 </span><br/><br/></li>
305 <div class="sws-slide">
307 <code> <![CDATA[ <a><b>1</b><b>toto</b><c>2</c><c>3</c></a> ]]></code>
310 <li class="sws-pause">
311 <tt>/child::a[ sum(child::*) >= 7.5 ]</tt>
312 <span class="sws-pause"><s>ne sélectionne pas la racine</s>(la fonction
313 <tt>sum</tt> converti la liste de valeurs passée en argument en
314 liste de nombres, toto n'étant pas un nombre valide, il est
315 remplacé par NaN. La somme totale fait donc NaN, et une
316 comparaison avec NaN renvoie toujours faux)
317 </span><br/><br/></li>
320 <div class="sws-slide">
321 <h1>Prédicat imbriqués</h1>
322 <p>On peut imbriquer des prédicats de manière arbitraire:</p>
323 <code> Q<sub>1</sub> ≡ /child::a[ child::b[ count(descendant::c) > 4 ] ] </code>
324 <p>Quelle différence avec :</p>
325 <code> Q<sub>2</sub> ≡ /child::a[ count(child::b/descendant::c) > 4 ] </code>
326 <p class="sws-pause">Il suffit de considérer le document :
328 <b> <c/> <c/> <c/></b>
332 <tt>Q<sub>1</sub></tt> <s>ne séléctionne rien</s> car il n'y a
333 aucun <tt>b</tt> ayant plus de 4
334 descendants <tt>c</tt>.<br/> <tt>Q<sub>2</sub></tt> <s>séléctionne</s>
335 la racine car le nombre de descendants <tt>c</tt> de
336 nœuds <tt>b</tt> est plus grand que 4.
339 <div class="sws-slide">
340 <h1><tt>position()</tt> et <tt>last()</tt> </h1>
341 <p>La fonction <tt>position()</tt> renvoie la position du nœud au
342 sein de <a>l'ensemble de résultats en cours de filtrage</a>. Last
343 renvoie le nombre d'éléments dans cet ensemble (ou l'indice du
344 dernier élément). Les indices commencent à 1 :</p>
351 /child::a/child::b[ position() = 2 ] (renvoie <![CDATA[<b>BB</b>]]>)
352 /child::a/child::b[ position() = last() ] (renvoie <![CDATA[<b>CC</b>]]>)
353 /child::a/child::b[ position() mod 2 = 1 ] (renvoie <![CDATA[<b>AA</b>
357 <h1>Axes complexes</h1>
358 <div class="sws-slide">
359 <h1>L'axe <tt>attribute::</tt></h1>
360 <p>Permet d'accéder aux attributs d'un élément.<s>Attention</s>, les
361 attributs ne font pas partie des fils ni des descendants!</p>
363 <b id="a1" v="x" >AA</b>
364 <b id="b2" v="y" >BB</b>
365 <b id="b3" v="z" >CC</b>
368 /descendant::b[ attribute::* = "y" ] (renvoie <![CDATA[<b …>BB</b>]]>)
369 /descendant::b[ attribute::id = "y" ] (ne renvoie rien)
372 <div class="sws-slide">
373 <h1>Les axes <tt>preceding::</tt> et <tt>following::</tt></h1>
374 <p>L'axe <tt>preceding::</tt> selectionne tous les nœuds arrivant
375 avant le nœud courant et qui ne sont pas des ancetres de ce
377 <p>L'axe <tt>following::</tt> selectionne tous les nœuds arrivant
378 après le nœud courant et qui ne sont pas des descendants de ce dernier.</p>
379 <code style="background:white;"><![CDATA[ <a>
392 /descendant::m/preceding::* (séléctionne l, i, h, b, c, d, e, f, g)
393 /descendant::d/following::* (sélectionne h, i, j, k, l, m)
396 <div class="sws-slide">
397 <h1>Autres opérateurs</h1>
398 <p>On peut donner plusieurs prédicats à un chemin :
400 <s>/descendant::a [ descendant::b ]</s><a>[ position () > 4 ]</a><span style="color:orange;">[ child::c ]</span>
402 Sélectionne l'ensemble des nœuds <s>A<sub>1</sub> ayant un
403 tag <tt>a</tt> et ayant un descendant <tt>b</tt></s>. Filtre
404 A<sub>1</sub> pour ne garder que <a>A<sub>2</sub>, l'ensemble des
405 nœuds de A<sub>1</sub> étant en position supérieure à
406 4</a>. <span style="color:orange;">Filtre A<sub>2</sub> pour ne
407 garder que les nœuds ayant un fils <tt>c</tt></span>.
409 <p>On peut prendre <a>l'union</a> de plusieurs chemins :</p>
411 /descendant::a/parent::b | /descendant::c/following-sibling::d
414 <h1>Syntaxe abrégée</h1>
415 <div class="sws-slide">
416 <h1>Abréviations</h1>
417 <p>XPath étant très <a>verbeux</a> il existe une syntaxe abrégée pour
418 les situations les plus courantes :</p>
420 <li> un nom de tag <tt>foo</tt> est l'abréviation
421 de <tt>child::foo</tt>. Exemple : <code> /a/b/c ≡ /child::a/child::b/child::c</code>
423 <li> un <tt>//</tt> est l'abréviation
424 de <tt>/descendant-or-self::node()/</tt>. Exemple :
425 <code> //a ≡ /descendant-or-self::node()/child::a </code>
426 Prend tous les nœuds du document (y compris le
427 nœud fictif <tt>#document</tt> et exécute <tt>child::a</tt> sur
428 cet ensemble.<br/></li>
429 <li> <tt> .. </tt> est un synonyme
430 pour <tt>parent::node()</tt> </li>
431 <li> <tt> @foo </tt> est un synonyme pour <tt>attribute::foo</tt>
435 <code> //book [ year > 2005 ]/title