--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
+>
+<html xmlns="http://www.w3.org/1999/xhtml" >
+ <head>
+ <title>XPath (suite)</title>
+
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=utf-8" />
+ <meta name="copyright"
+ content="Copyright © 2013 Kim Nguyễn" />
+
+ <!-- Load jQuery -->
+ <script src="../jquery-1.9.1.min.js" type="text/javascript" ></script>
+ <!-- Load the library -->
+ <script src="../simpleWebSlides.js" type="text/javascript" ></script>
+
+ <link rel="stylesheet" href="../simpleWebSlides.css" type="text/css" media="all" />
+ <!-- Load a custom Theme, the class-element marks this style-sheet
+ a "theme" that can be swtiched dynamicaly -->
+ <link class="sws-theme" rel="stylesheet" title="U-Psud style" href="../themes/uPsud.css" type="text/css" />
+
+ <!-- Customize some templates and initialize -->
+ <style type="text/css">
+ .xml-tag { color: #00486c; }
+ </style>
+ <script type="text/javascript">
+ <![CDATA[
+ SWS.Config['sws-slide-change'] = SWS.Effects.slideChangeFadeOutIn;
+ SWS.Config['sws-object-deactivate'] = SWS.Effects.objectDeactivateFadeOut;
+ SWS.Config['sws-object-activate'] = SWS.Effects.objectActivateFadeIn;
+
+ //Ensures that we load SWS at the very end, after MathJax has
+ //been initialized
+
+ $(window).load(function () {
+ $(".inline-xml").each(function(i, elem)
+ {
+ var jelem = $(elem);
+ var code = jelem.html();
+ code = code.replace ("<![CDATA" + "[", "").replace ("]" + "]>", "");
+ code = code.replace (/>/g, ">>>");
+ code = code.replace (/</g, "<span class='xml-tag'><");
+ code = code.replace (/>>>/g,"></span>");
+
+ jelem.html(code);
+ });
+ });
+
+ var checkSVG = function (o, i)
+ {
+ if (i >= 10 || SWS.Utils.isUndefined(o) || o == null) return;
+ var svg = o.getSVGDocument();
+ if (svg == null) {
+ setTimeout(function() { checkSVG(o, i+1); }, 200);
+ } else {
+ var alltext = $(svg).find("text");
+ alltext.css("font-family", "DIN");
+ alltext.css("font-size", "70%");
+
+ };
+ };
+ $(window).load(function() {
+ $("embed").ready(function() {
+ setTimeout(function() {
+ $("embed").each(function(i, o) { checkSVG(this,0); });
+}, 1000);
+ });
+ });
+ $(window).load(SWS.Presentation.init);
+
+ ]]>
+
+ </script>
+
+ </head>
+ <body>
+ <a href="xpi_02.xhtml" class="sws-previous"/>
+ <div class="sws-slide sws-cover sws-option-nofooter">
+ <h1>XML et Programmation Internet</h1>
+ <h1>Cours 3</h1>
+ <a href="mailto:kn@lri.fr">kn@lri.fr</a>
+ </div>
+ <h1>Évaluation des prédicats</h1>
+ <div class="sws-slide">
+ <h1>Rappels de syntaxe</h1>
+<code>
+ p ::= p or p
+ | p and p
+ | not (p)
+ | count(…), contains(…), position(), …
+ | chemin XPath
+ | e<sub>1</sub> op e<sub>2</sub>
+</code>
+<p>On évalue le prédicat et on converti son résultat en valeur de
+ vérité. Si la valeur vaut vrai, on garde le nœud courant, si elle
+ vaut faux, on ne le garde pas
+</p>
+<p>XPath connait <a>4 types de données</a> pour les prédicats : </p>
+<ul>
+<li>Les booléens, valeur de vérité : vrai ou faux</li>
+<li>Les nombres (flottants), valeur de vérité compliquée… </li>
+<li>Les chaînes de caractères, chaîne vide = faux, sinon vrai</li>
+<li>Les ensembles de nœuds, ensemble vide = faux, sinon vrai </li>
+</ul>
+ </div>
+<div class="sws-slide">
+<h1>Comparaisons (e<sub>1</sub> op e<sub>2</sub>)</h1>
+<p> Les opérateurs de comparaisons sont : <tt>=, !=, <, <=,
+ >, >= </tt>.<br/>
+ La manière de calculer de vérité de <tt>e<sub>1</sub> op
+ e<sub>2</sub></tt> dépend du typed de <tt>e<sub>1</sub></tt>
+ et <tt>e<sub>2</sub></tt> :
+</p>
+<ul>
+ <li>Si <tt>e<sub>1</sub></tt> et <tt>e<sub>2</sub></tt> représente
+ <a>des ensembles de nœuds</a>, alors la comparaison est vraie ssi
+ il existe un élément <tt>x</tt> dans <tt>e<sub>1</sub></tt> et un
+ élément <tt>y</tt> dans <tt>e<sub>2</sub></tt> tels que <tt>x op y</tt>
+ </li>
+
+ <li>Si <tt>e<sub>1</sub></tt> représente
+ <a>un ensembles de nœuds</a> et <tt>e<sub>2</sub></tt> une valeur
+ scalaire <tt>y</tt>, alors la comparaison est vraie ssi
+ il existe un élément <tt>x</tt> dans <tt>e<sub>1</sub></tt> tel que <tt>x op y</tt>
+ </li>
+ <li>Si <tt>e<sub>1</sub></tt> et <tt>e<sub>2</sub></tt> sont des
+ valeurs scalaires, alors ont les compare en utilisant les règles de
+ comparaison des valeurs scalaires (voir page suivante).
+ </li>
+</ul>
+</div>
+<div class="sws-slide">
+<h1>Comparaisons des valeurs scalaires</h1>
+<code> v<sub>1</sub> op v<sub>2</sub> </code>
+<p>Si op est <tt>!=</tt> ou <tt>=</tt>, on applique les règles dans cet ordre:</p>
+<ol>
+<li> Si <tt>v<sub>1</sub></tt> (resp. <tt>v<sub>2</sub></tt>) est
+ un <a>booléen</a>, alors <tt>v<sub>2</sub></tt>
+ (resp. <tt>v<sub>1</sub></tt>) est converti en booléen et les deux
+ booléens sont comparés </li>
+<li> Sinon si <tt>v<sub>1</sub></tt> (resp. <tt>v<sub>2</sub></tt>) est
+ un <a>nombre</a>, alors <tt>v<sub>2</sub></tt>
+ (resp. <tt>v<sub>1</sub></tt>) est converti en nombre et les deux
+ nombres sont comparés </li>
+<li> Sinon, <tt>v<sub>1</sub></tt> et <tt>v<sub>2</sub></tt> sont des
+ <a>chaines de caractères</a>, on les compares</li>
+</ol>
+<p>Si op est <tt> <</tt>, <tt> <=</tt>, <tt> ></tt> ou <tt>
+ >=</tt>, on convertit <tt>v<sub>1</sub></tt>
+ et <tt>v<sub>2</sub></tt> en <a>nombres</a> et on les compare.
+</p>
+</div>
+<div class="sws-slide">
+<h1>Conversions</h1>
+<p>Conversion en booléen</p>
+<ul>
+ <li>0 et NaN sont converti en <tt>false</tt>, le reste
+ en <tt>true</tt> </li>
+ <li>Un ensemble de nœud vaut <tt>true</tt> ssi il est non vide</li>
+ <li>Une chaine vaut <tt>true</tt> ssi elle est non vide</li>
+</ul>
+<p>Conversion en nombre</p>
+<ul>
+ <li>Une chaine de caractère représentant un flottant au format
+ IEEE-754 est convertie en ce nombre, sinon elle est convertie en NaN
+ </li>
+ <li>Booléen: <tt>true</tt> est converti à 1, <tt>false</tt> est
+ converti à 0</li>
+ <li>Un ensemble de nœud est d'abord converti en chaine de caractères
+ puis la chaine est convertie en nombre</li>
+</ul>
+</div>
+<div class="sws-slide">
+<h1>Conversions (suite)</h1>
+<p>Conversion en chaine de caractères</p>
+<ul>
+ <li>Un booléen est traduit en <tt>"true"</tt> ou <tt>"false"</tt>
+ selon sa valeur</li>
+ <li>Nombres:
+ <ul><li>NaN est converti en la chaine <tt>"NaN"</tt></li>
+ <li>Si le nombre n'a pas de partie décimale, sa
+ représentation <i>entière</i> est convertie en chaine (ex:
+ 1.000e10 ≡ <tt>"10"</tt>)</li>
+ <li>Sinon une représentation IEE-754 du nombre est utilisé
+ (ex: <tt>"123.10e-34"</tt>)
+ </li>
+ </ul>
+ </li>
+ <li>Ensemble de noœud : <ul>
+ <li>L'ensemble vide est converti en la chaine vide
+ </li>
+ <li>Sinon le premier élément dans l'ordre du document est
+ converti en chaine en concatenant tous les nœuds textes dans ces
+ descendants (y compris lui-même)</li>
+ </ul>
+ </li>
+</ul>
+</div>
+
+<div class="sws-slide">
+<h1>Appels de fonction</h1>
+<p>Il existe des fonctions prédéfinies (voir la spec XPath)</p>
+<ul>
+ <li><tt>contains(str<sub>1</sub>,str<sub>2</sub>)</tt></li>
+ <li><tt>starts-with(str<sub>1</sub>,str<sub>2</sub>)</tt></li>
+ <li><tt>count(node_set<sub>1</sub>)</tt></li>
+ <li><tt>last()</tt></li>
+ <li><tt>position()</tt></li>
+ <li>…</li>
+</ul>
+<p>Si les arguments ne sont pas du bon type, ils sont convertis en
+ utilisant les règles de conversion</p>
+</div>
+<div class="sws-slide">
+<h1>Exemples</h1>
+<p>Dans la suite, on se donne un document de test ayant une
+ racine <tt><![CDATA[<a> ... </a>]]></tt> et une expression XPath qui
+ sélectionne la racine si et seulement si le prédicat vaut vrai
+</p>
+</div>
+<div class="sws-slide">
+ <h1>Exemples</h1>
+ <code> <![CDATA[ <a>
+ <b>1</b>
+ <c>2</c>
+ </a> ]]></code>
+<ol> <li class="sws-pause">
+ <tt>/child::a[ child::*/child::text() ]</tt>
+ <span class="sws-pause">sélectionne la racine (l'ensemble de nœud
+ renvoyé par <tt>child::*/cild::text()</tt> est non vide, donc il est converti
+ en <tt>true</tt>)</span><br/><br/></li>
+ <li class="sws-pause">
+ <tt>/child::a[ child::*/child::text() = "2" ]</tt>
+ <span class="sws-pause">sélectionne la racine (l'ensemble de nœud texte
+ renvoyé par <tt>child::*/child::text()</tt> est comparé à "2", et
+ il existe un élément dans cet ensemble pour lequel le test réussi
+ )</span><br/><br/></li>
+ <li class="sws-pause"><tt>/child::a[ child::*/child::text() != "2" ]</tt>
+ <span class="sws-pause"><s>sélectionne la racine</s> (l'ensemble de nœud texte
+ renvoyé par <tt>child::*/child::text()</tt> est comparé à "2", et
+ il existe un élément dans cet ensemble pour lequel le test réussi
+ )</span><br/><br/></li>
+ <li class="sws-pause" style="background:white;"><tt>/child::a[ not(child::*/child::text() = "2") ]</tt>
+ <span class="sws-pause"><s>ne sélectionne pas la racine</s> (on
+ prend la négation du deuxième cas ci-dessus)
+ </span><br/><br/></li>
+
+</ol>
+</div>
+<div class="sws-slide">
+ <h1>Exemples</h1>
+ <code> <![CDATA[ <a>
+ <b>1</b><b>2</b>
+ <c>2</c><c>3</c>
+ </a> ]]></code>
+<ol>
+ <li class="sws-pause">
+ <tt>/child::a[ child::*/child::text() > 1.5 ]</tt>
+ <span class="sws-pause">sélectionne la racine (l'ensemble de nœud texte
+ renvoyé par <tt>child::*/child::text()</tt> est comparé à 1.5, et
+ il existe un élément dans cet ensemble pour lequel le test réussi
+ )</span><br/><br/></li>
+ <li class="sws-pause"><tt>/child::a[ child::b/child::text() >= child::c/child::text() ]</tt>
+ <span class="sws-pause"><s>sélectionne la racine</s> (les deux
+ ensembles de nœuds sont convertis en ensmbles de nombres, car on
+ utilise <tt>>=</tt> et on a bien que <tt>2 >= 2</tt>
+ )</span><br/><br/></li>
+ <li class="sws-pause"><tt>/child::a[ child::b/child::text() = child::c/child::text() ]</tt>
+ <span class="sws-pause"><s>sélectionne la racine</s> (les deux
+ ensembles de nœuds comportent un élément commun)</span><br/><br/></li>
+ <li class="sws-pause"><tt>/child::a[ child::b/child::text() != child::c/child::text() ]</tt>
+ <span class="sws-pause"><s>sélectionne la racine</s> (les deux
+ comportent des éléments différents)</span><br/><br/></li>
+</ol>
+</div>
+<div class="sws-slide">
+ <h1>Exemples</h1>
+ <code> <![CDATA[ <a><b>1</b><b>2</b><c>2</c><c>3</c></a> ]]></code>
+<ol>
+ <li class="sws-pause">
+ <tt>/child::a[ contains(self::*, "22") ]</tt>
+ <span class="sws-pause"><s>sélectionne la racine</s>(l'ensemble de
+ nœud séléctionné par <tt>self::*</tt>, i.e. la racine est converti
+ en chaine. Pour ce faire, on colle toutes éléments textes
+ descendants et on obtient la chaine "1223" qui contient bien "22")
+ </span><br/><br/></li>
+ <li class="sws-pause">
+ <tt>/child::a[ self::* > 442.38 ]</tt>
+ <span class="sws-pause"><s>sélectionne la racine</s>(l'ensemble de
+ nœud séléctionné par <tt>self::*</tt>, est converti en chaine puis
+ en nombre pour comparer 1223 à 442.38)
+ </span><br/><br/></li>
+
+ <li class="sws-pause">
+ <tt>/child::a[ sum(child::*) >= 7.5 ]</tt>
+ <span class="sws-pause"><s>sélectionne la racine</s>(la fonction
+ <tt>sum</tt> converti la liste de valeurs passée en argument en
+ liste de nombre et fait la somme de ces derniers)
+ </span><br/><br/></li>
+</ol>
+</div>
+
+<div class="sws-slide">
+ <h1>Exemples</h1>
+ <code> <![CDATA[ <a><b>1</b><b>toto</b><c>2</c><c>3</c></a> ]]></code>
+<ol>
+
+ <li class="sws-pause">
+ <tt>/child::a[ sum(child::*) >= 7.5 ]</tt>
+ <span class="sws-pause"><s>ne sélectionne pas la racine</s>(la fonction
+ <tt>sum</tt> converti la liste de valeurs passée en argument en
+ liste de nombres, toto n'étant pas un nombre valide, il est
+ remplacé par NaN. La somme totale fait donc NaN, et une
+ comparaison avec NaN renvoie toujours faux)
+ </span><br/><br/></li>
+</ol>
+</div>
+<div class="sws-slide">
+ <h1>Prédicat imbriqués</h1>
+ <p>On peut imbriquer des prédicats de manière arbitraire:</p>
+ <code> Q<sub>1</sub> ≡ /child::a[ child::b[ count(descendant::c) > 4 ] ] </code>
+ <p>Quelle différence avec :</p>
+ <code> Q<sub>2</sub> ≡ /child::a[ count(child::b/descendant::c) > 4 ] </code>
+ <p class="sws-pause">Il suffit de considérer le document :
+ <code> <![CDATA[ <a>
+ <b> <c/> <c/> <c/></b>
+ <b> <c/> <c/> </b>
+ </a>
+ ]]></code>
+ <tt>Q<sub>1</sub></tt> <s>ne séléctionne rien</s> car il n'y a
+ aucun <tt>b</tt> ayant plus de 4
+ descendants <tt>c</tt>.<br/> <tt>Q<sub>2</sub></tt> <s>séléctionne</s>
+ la racine car le nombre de descendants <tt>c</tt> de
+ nœuds <tt>b</tt> est plus grand que 4.
+</p>
+</div>
+<div class="sws-slide">
+ <h1><tt>position()</tt> et <tt>last()</tt> </h1>
+ <p>La fonction <tt>position()</tt> renvoie la position du nœud au
+ sein de <a>l'ensemble de résultats en cours de filtrage</a>. Last
+ renvoie le nombre d'éléments dans cet ensemble (ou l'indice du
+ dernier élément). Les indices commencent à 1 :</p>
+ <code><![CDATA[ <a>
+ <b>AA</b>
+ <b>BB</b>
+ <b>CC</b>
+ </a>]]>
+
+ /child::a/child::b[ position() = 2 ] (renvoie <![CDATA[<b>BB</b>]]>)
+ /child::a/child::b[ position() = last() ] (renvoie <![CDATA[<b>CC</b>]]>)
+ /child::a/child::b[ position() mod 2 = 1 ] (renvoie <![CDATA[<b>AA</b>
+ <b>CC</b>]]>)
+</code>
+</div>
+<h1>Axes complexes</h1>
+<div class="sws-slide">
+ <h1>L'axe <tt>attribute::</tt></h1>
+ <p>Permet d'accéder aux attributs d'un élément.<s>Attention</s>, les
+ attributs ne font pas partie des fils ni des descendants!</p>
+ <code><![CDATA[ <a>
+ <b id="a1" v="x" >AA</b>
+ <b id="b2" v="y" >BB</b>
+ <b id="b3" v="z" >CC</b>
+ </a>]]>
+
+ /descendant::b[ attribute::* = "y" ] (renvoie <![CDATA[<b …>BB</b>]]>)
+ /descendant::b[ attribute::id = "y" ] (ne renvoie rien)
+</code>
+</div>
+<div class="sws-slide">
+ <h1>Les axes <tt>preceding::</tt> et <tt>following::</tt></h1>
+ <p>L'axe <tt>preceding::</tt> selectionne tous les nœuds arrivant
+ avant le nœud courant et qui ne sont pas des ancetres de ce
+ dernier.</p>
+ <p>L'axe <tt>following::</tt> selectionne tous les nœuds arrivant
+ après le nœud courant et qui ne sont pas des descendants de ce dernier.</p>
+ <code style="background:white;"><![CDATA[ <a>
+ <b > <c/>
+ <d> <e/> </d>
+ <f ><g/></f>
+ </b>
+ <h/>
+ <i/>
+ <j> <k>
+ <l/> <m/> <n/>
+ </k>
+ </j>
+ </a>]]>
+
+ /descendant::m/preceding::* (séléctionne l, i, h, b, c, d, e, f, g)
+ /descendant::d/following::* (sélectionne h, i, j, k, l, m)
+</code>
+</div>
+<div class="sws-slide">
+<h1>Autres opérateurs</h1>
+<p>On peut donner plusieurs prédicats à un chemin :
+<code>
+ <s>/descendant::a [ descendant::b ]</s><a>[ position () > 4 ]</a><span style="color:orange;">[ child::c ]</span>
+</code>
+Sélectionne l'ensemble des nœuds <s>A<sub>1</sub> ayant un
+ tag <tt>a</tt> et ayant un descendant <tt>b</tt></s>. Filtre
+ A<sub>1</sub> pour ne garder que <a>A<sub>2</sub>, l'ensemble des
+ nœuds de A<sub>1</sub> étant en position supérieure à
+ 4</a>. <span style="color:orange;">Filtre A<sub>2</sub> pour ne
+ garder que les nœuds ayant un fils <tt>c</tt></span>.
+</p>
+<p>On peut prendre <a>l'union</a> de plusieurs chemins :</p>
+<code>
+ /descendant::a/parent::b | /descendant::c/following-sibling::d
+</code>
+</div>
+<h1>Syntaxe abrégée</h1>
+<div class="sws-slide">
+<h1>Abréviations</h1>
+<p>XPath étant très <a>verbeux</a> il existe une syntaxe abrégée pour
+ les situations les plus courantes :</p>
+<ul>
+ <li> un nom de tag <tt>foo</tt> est l'abréviation
+ de <tt>child::foo</tt>. Exemple : <code> /a/b/c ≡ /child::a/child::b/child::c</code>
+ <br/></li>
+ <li> un <tt>//</tt> est l'abréviation
+ de <tt>/descendant-or-self::node()/</tt>. Exemple :
+ <code> //a ≡ /descendant-or-self::node()/child::a </code>
+ Prend tous les nœuds du document (y compris le
+ nœud fictif <tt>#document</tt> et exécute <tt>child::a</tt> sur
+ cet ensemble.<br/></li>
+ <li> <tt> .. </tt> est un synonyme
+ pour <tt>parent::node()</tt> </li>
+ <li> <tt> @foo </tt> est un synonyme pour <tt>attribute::foo</tt>
+ </li>
+</ul>
+ <p>Exemple :</p>
+ <code> //book [ year > 2005 ]/title
+ </code>
+
+</div>
+ </body>
+</html>