.
[hacks/simpleWebSlides.git] / xpi / xpi_07.xhtml
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"
4 >
5 <html xmlns="http://www.w3.org/1999/xhtml" >
6   <head>
7     <title>XPath et XSLT en Java</title>
8
9     <meta http-equiv="Content-Type"
10           content="text/html; charset=utf-8" />
11     <meta name="copyright"
12           content="Copyright &#169; 2013 Kim Nguyễn" />
13
14     <!-- Load jQuery -->
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>
18
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" />
23
24     <!-- Customize some templates and initialize -->
25     <style type="text/css">
26       .xml-tag { color: #00486c; }
27     </style>
28     <script type="text/javascript">
29       <![CDATA[
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;
33
34       //Ensures that we load SWS at the very end, after MathJax has
35       //been initialized
36
37       $(window).load(function () {
38        $(".inline-xml").each(function(i, elem)
39       {
40       var jelem = $(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'>&lt;");
45       code = code.replace (/>>>/g,"&gt;</span>");
46
47       jelem.html(code);
48       });
49   });
50
51       var checkSVG = function (o, i)
52       {
53             if (i >= 10 || SWS.Utils.isUndefined(o) || o == null) return;
54             var svg = o.getSVGDocument();
55             if (svg == null) {
56               setTimeout(function() { checkSVG(o, i+1); }, 200);
57             } else {
58          var alltext = $(svg).find("text");
59          alltext.css("font-family", "DIN");
60          alltext.css("font-size", "70%");
61
62             };
63       };
64       $(window).load(function() {
65       $("embed").ready(function() {
66          setTimeout(function() {
67          $("embed").each(function(i, o) { checkSVG(this,0);   });
68 }, 1000);
69         });
70      });
71       $(window).load(SWS.Presentation.init);
72
73         ]]>
74
75     </script>
76
77   </head>
78   <body>
79     <a href="xpi_06.xhtml" class="sws-previous"/>
80     <div class="sws-slide sws-cover sws-option-nofooter">
81       <h1>XML et Programmation Internet</h1>
82       <h1>Cours 7</h1>
83       <a href="mailto:kn@lri.fr">kn@lri.fr</a>
84     </div>
85     <h1>Requêtes XPath en Java</h1>
86     <div class="sws-slide">
87       <h1>Moteur XPath en java</h1>
88       <p>L'API JAXP contient un moteur XPath 1.0 complet. Outre les
89       classes nécessaires au chargement de fichier et à la
90       manipulation du DOM (voir cours 6), il faut charger les éléments
91       du package <a><tt>javax.xml.xpath</tt></a>. Comme pour le reste
92       de JAXP, on passe par un <tt>XPathFactory</tt> pour créer une
93       nouvelle instance du moteur XPath.
94     </p>
95   </div>
96   <div class="sws-slide">
97     <h1>Exemple : packages</h1>
98     <code style="background:white;">  //Pour les documents et DOM
99   <kbd>import org.w3c.dom.*;
100   import javax.xml.namespace.QName;
101   import javax.xml.parsers.DocumentBuilder;
102   import javax.xml.parsers.DocumentBuilderFactory;</kbd>
103
104   //Pour le moteur XPath
105   <u>import javax.xml.xpath.XPathFactory;
106   import javax.xml.xpath.XPath;
107   import javax.xml.xpath.XPathConstants;</u>
108
109   <kbd>public class TestXPath {</kbd>
110   //Deux attributs pour contenir le moteur XPath et le document builder
111     <kbd>XPath xp_ = null;
112     DocumentBuilder db_ = null;</kbd>
113
114     </code>
115   </div>
116   <div class="sws-slide">
117     <h1>Exemple : constructeur</h1>
118     <code style="background:white;">  <kbd>public TestXPath () {
119     try {
120      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
121      factory.setNamespaceAware(true);
122      db_ = factory.newDocumentBuilder();
123
124      <u>XPathFactory xf = XPathFactory.newInstance();
125      xp_ = xf.newXPath();</u>
126
127    } catch (Exception e) {</kbd>
128     //Peuvent être levées en cas d'erreur de création d'objet XPath
129     //DocumentBuilder, par exemple si des options passées sont
130     //non-supportées.
131 <kbd>    }
132   }</kbd>
133
134     </code>
135   </div>
136 <div class="sws-slide">
137     <h1>Exemple : méthode d'évaluation</h1>
138     <code style="background:white;">
139    <kbd>NodeList eval(String fichier, String chemin) throws Exception {
140
141    </kbd>//Création d'un DOM pour le fichier source<kbd>
142    Document doc = db_.parse(fichier);
143
144    <u>NodeList nl = (NodeList) xp_.evaluate(chemin,
145                                          doc,
146                                          XPathConstants.NODESET);</u>
147
148
149    }</kbd>
150
151 </code>
152 </div>
153 <div class="sws-slide">
154     <h1>Méthode <tt>XPath.evaluate()</tt></h1>
155 <p>La méthode <tt>XPath.evaluate(xpath, n, type)</tt> permet d'évaluer une
156   l'expression <a>xpath</a> (donnée sous-forme de chaîne de
157   caractères), à partir du nœud contexte <tt>n</tt> (qui doit
158   implémenter l'interface <a>Node</a>). Le résultat est de
159   type <a>typ</a>. La fonction renvoie un résultat de
160   type <s>Object</s>. L'argument <tt>typ</tt> peut avoir 5 valeurs
161   possibles, définies dans la class <tt>XPathConstants</tt> :
162 </p>
163 <ul>
164   <li><tt><u>XPathConstants.BOOLEAN</u></tt>: le résultat est de type java <tt>Boolean</tt></li>
165   <li><tt><u>XPathConstants.NUMBER</u></tt>: le résultat est de type java <tt>Double</tt></li>
166   <li><tt><u>XPathConstants.STRING</u></tt>: le résultat est de type java <tt>String</tt></li>
167   <li><tt><u>XPathConstants.NODE</u></tt>: le résultat est de type java <tt>Node</tt></li>
168   <li><tt><u>XPathConstants.NODESET</u></tt>: le résultat est de type java <tt>NodeList</tt></li>
169 </ul>
170 <p>En effet, une expression XPath peut avoir comme valeur un booléen,
171   un ensemble de noeuds ou une chaîne dépendant du <s>contexte</s> où
172   elle est utilisée. On peut demander à Jaxp d'évaluer la requête
173   XPath pour un certain contexte.
174 </p>
175 </div>
176   <div class="sws-slide">
177     <h1>Exemple </h1>
178     <code><kbd>  Document doc = ...
179   String chemin = <u>"//descendant::year[position () = 1]";</u>
180
181
182   </kbd>//Crée une NodeList à un élément<kbd>
183   <u>NodeList nl = (NodeList) xp_.evaluate(chemin, doc, XPathConstants.NODESET);</u>
184
185   </kbd>//Renvoie le nœud correspondant ou null<kbd>
186   <u>Node n = (Node) xp_.evaluate(chemin, doc, XPathConstants.NODE);</u>
187
188   </kbd>//Renvoie le double java correspondant à la valeur<kbd>
189   <u>Double d = (Double) xp_.evaluate(chemin, doc, XPathConstants.NUMBER);</u>
190
191   </kbd>//Renvoie la chaine java correspondant au texte<kbd>
192   <u>String s = (String) xp_.evaluate(chemin, doc, XPathConstants.STRING);</u>
193
194   </kbd>//Renvoie la valeur de vérité corresondant au chemin<kbd>
195   <u>Boolean b = (Boolean) xp_.evaluate(chemin, doc, XPathConstants.BOOLEAN);</u>
196 </kbd></code>
197 </div>
198 <div class="sws-slide">
199 <h1>La classe <tt>XPathExpression</tt></h1>
200 <p>Cette classe est similaire à l'utilisation
201   de <a>PreparedStatements</a> en JDBC.<br/>
202 <span class="sws-pause">Utilité ?</span>
203 <span class="sws-pause">compiler la requête XPath une fois pour toute
204   et donc éviter de re-parser la chaîne de caractère à chaque
205   appel. <br/>Exemple : </span>
206 </p>
207 <code>
208 <kbd>   <u>XPathExpression ex = xp_.compile("//movie/title");</u>
209
210    NodeList nl1 = (NodeList) ex.evaluate(doc1, XPathConstants.NODESET);
211    NodeList nl2 = (NodeList) ex.evaluate(doc2, XPathConstants.NODESET);
212    NodeList nl3 = (NodeList) ex.evaluate(doc3, XPathConstants.NODESET);
213    …
214 </kbd></code>
215
216 </div>
217 <h1>XSLT</h1>
218 <div class="sws-slide">
219 <h1> Applications de transformations XSLT </h1>
220 <p>Appliquer une transformation XSLT est une opération complexe à
221   cause des différentes combinaisons possibles :
222 </p>
223 <ul>
224 <li>Le fichier source (ex: <tt>movie.xml</tt>) peut être soit déjà
225   chargé comme un <tt>DOM</tt>, soit sous forme de fichier, soit sous
226   forme de chaîne de caractères,…</li>
227 <li>Le fichier destination (ex: <tt>resultat.xhtml</tt>) est
228   représenté par une <tt>DOM</tt> qui doit être
229   éventuellement <i>sérialisé</i> (i.e. retransformé en fichier XML).
230 </li>
231 <li>La transformation elle même (ex: <tt>style.xsl</tt>) peut être
232   sous forme diverse (fichier, URL, DOM, …)
233 </li>
234 <p>On a donc une série de classes d'encapsulation (<tt>Source</tt>,
235   …), de factory, …</p>
236 </ul>
237
238
239 </div>
240 <div class="sws-slide">
241 <h1>Création d'une transformation</h1>
242 <p>Pour créer une transformation XSLT, il faut les classes suivantes,
243   du package: <tt>javax.xml.transform</tt></p>
244 <code>
245   //La classe permettant d'appliquer une transformation XSLT
246   //ainsi que sa factory
247   <u>import javax.xml.transform.Transformer;
248   import javax.xml.transform.TransformerFactory;</u>
249
250   //La classe permettant de charger des transformations ou des
251   //arguments de transformation sous forme de fichiers
252   <u>import javax.xml.transform.stream.StreamSource;</u>
253
254   //La classe permettant de charger des documents ou transformations
255   //sous forme de nœuds DOM
256   <u>import javax.xml.transform.dom.DOMSource;</u>
257
258 </code>
259 </div>
260
261 <div class="sws-slide">
262   <h1>Exemple</h1>
263
264 <code>
265   <u>TransformerFactory tf = TransformerFactory.newInstance();</u>
266   //On crée un StreamSource à partir d'un nom de fichier contenant
267   //la feuille de style XSLT
268   <u>Transformer tr = tf.newTransformer(new StreamSource("style.xsl"));</u>
269 </code>
270
271 <p>Le code ci-dessus crée un objet de type <tt>Transformer</tt>
272   représentant la transformation XSLT se trouvant dans le fichier
273   <tt>style.xsl</tt>. <br/>
274   Si on avait chargé le fichier sous forme d'un
275   arbre DOM:
276 </p>
277 <code>  <kbd>Document style_xsl = … ;</kbd>//chargement de style.xsl
278
279   <u>TransformerFactory tf = TransformerFactory.newInstance();</u>
280   <u>Transformer tr = tf.newTransformer(new DOMSource(style_xsl));</u>
281
282 </code>
283
284 </div>
285 <div class="sws-slide">
286 <h1>La méthode <tt>Transformer.transform()</tt></h1>
287 <code>            transform(<u>Source</u> xmlSource, <u>Result</u> outputTarget)
288 </code>
289 <p>Les interfaces <tt>Source</tt> et <tt>Result</tt> permettent
290   d'abstraire le type de l'entrée et de la sortie. Ces dernières
291   peuvent être :</p>
292 <ul>
293   <li>Des objets DOM : <u>DOMSource</u> et <u>DOMResult</u> </li>
294   <li>Des objets d'entrée sortie de la bibliothèque java standard
295   (<tt>File</tt>, <tt>Input/OutputStream</tt>, <tt>Reader/Writer</tt>,
296   chaîne de caractère représentant un nom de fichier
297   : <u>StreamSource</u> et <u>StreamResult</u></li>
298 </ul>
299
300 </div>
301 <div class="sws-slide">
302 <h1>Exemple</h1>
303 <code>
304  //On applique le transformer associé à style.xsl
305  //sur le fichier movie et on écrit le résultat sur
306  //la sortie standard :
307
308  <u>tr.transform(new StreamSource("movies.xml"), new StreamResult(System.out));</u>
309 </code>
310 </div>
311 <div class="sws-slide">
312   <h1>Sérialisation</h1>
313   <p>La manière la plus simple de <i>sérialiser un document</i> est de
314   créer une transformation XSLT vide (i.e qui fait l'identité) et de
315   demander à ce que le résultat soit un fichier (ou la sortie
316   standard)</p>
317   <code>
318   <kbd>Document doc = …; </kbd>//l'objet DOM que l'on veut sauver dans un fichier
319   <u>Transformer tr = tf.newTransformer();</u>
320   <u>tr.transform(doc, new StreamSource(new FileOutputStream("fichier.xml")));</u>
321   </code>
322 </div>
323 <h1><i>Streaming</i> avec SAX</h1>
324 <div class="sws-slide">
325   <h1><i>Streaming</i> ?</h1>
326   <p>Charger un document avec DOM permet d'accéder à l'arbre « en
327     entier » mais peut être couteux en mémoire (chaque nœud possède au
328     moins 4 pointeurs, 2 chaines de caractères, …). On veut pouvoir
329     effectuer certains types d'opération à la volée :
330   </p>
331   <ul class="sws-pause">
332     <li  class="sws-pause">Faire des statistiques sur les documents (compter le nombre
333     d'éléments, d'attributs, …)</li>
334     <li  class="sws-pause">Faire des transformations simples qui
335     préservent la structure (par exemple mettre les balises en
336     majuscules)</li>
337     <li  class="sws-pause">Valider vis à vis d'une DTD</li>
338     </ul>
339 </div>
340 <div class="sws-slide">
341 <h1>Programmation évènementielle</h1>
342 <p>Les parseurs SAX (Simple API for XML) reposent sur la programmation
343   évènementielle. Ils lisent le fichier d'entrée et génèrent un
344   certain nombre d'évènements, auxquels on peut réagir avec du code.
345   Les évènements sont :
346 </p>
347 <ul>
348   <li>Début de document</li>
349   <li>Fin de document </li>
350   <li>Ouverture de balise (avec le nom et la liste des attributs)</li>
351   <li>Fermeture de balise (avec le nom)</li>
352   <li>Élément texte</li>
353   <li>Commentaire </li>
354   <li>…</li>
355 </ul>
356 </div>
357 <div class="sws-slide">
358   <h1>L'API SAX</h1>
359 <code>
360 import javax.xml.parsers.*;
361 import org.xml.sax.*;
362 import org.xml.sax.helpers.*;
363 </code>
364 <p>On doit étendre la classe par <tt>DefaultHandler</tt></p>
365 </div>
366 <div class="sws-slide">
367 <h1><tt>DefaultHandler</tt></h1>
368 <code>
369  //le parseur a lu length caractères qui se trouvent dans
370  //ch à partir de la position start
371  void  <u>characters</u>(char[] ch, int start, int length)
372
373  //le parseur a détécté la fin de document
374  void  <u>endDocument</u>()
375
376  //le parseur a détecté la fin d'un élément
377  void  <u>endElement</u>(String uri, String localName, String qName)
378
379  //le parseur a détecté du texte « ignorable »
380  void  <u>ignorableWhitespace</u>(char[] ch, int start, int length)
381
382  //le parseur a détecté le début du document
383  void  <u>startDocument</u>()
384  //le parseur a detecté le début d'un élément
385  void  <u>startElement</u>(String uri,String localName, String qName,
386                            Attributes attributes)
387 </code>
388 <p><tt><u>Attributes</u></tt> est une classe auxiliaire qui permet de
389   connaître le nom, le nombre et les valeurs des attributs pour cette
390   balise.</p>
391 </div>
392
393 <div class="sws-slide">
394 <h1><tt>Handler</tt> personnalisé</h1>
395 <p>On étend la classe <tt>DefaultHandler</tt> : </p>
396 <code>
397 <u>class MyHandler extends DefaultHandler</u> {
398    private int nb_elems;
399    MyHandler() {
400      nb_elems = 0;
401    }
402     void  <u>startElement</u>(String uri,String localName, String qName,
403                            Attributes attributes)
404     throws SAXException {
405     nb_elems++;
406
407     }
408    int getNbElems() { return nb_elems; };
409 }
410
411 </code>
412
413 </div>
414 <div class="sws-slide">
415 <h1>Invocation du parseur</h1>
416 <p>On utilise (encore) une factory : </p>
417 <code>
418  public static void main(String[] args) {
419     …
420     SAXParserFactory spf = <u>SAXParserFactory.newInstance</u>();
421     spf.setNamespaceAware(true);
422     SAXParser saxParser = <u>spf.newSAXParser</u>();
423
424     MyHandler my = <kbd>new MyHandler()</kbd>;
425     XMLReader xmlReader = <u>saxParser.getXMLReader</u>();
426     xmlReader.<u>setContentHandler(my)</u>;
427     xmlReader.parse(filename);
428 }
429 </code>
430
431 </div>
432   </body>
433 </html>