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 et XSLT en Java</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_06.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>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.
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>
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>
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>
116 <div class="sws-slide">
117 <h1>Exemple : constructeur</h1>
118 <code style="background:white;"> <kbd>public TestXPath () {
120 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
121 factory.setNamespaceAware(true);
122 db_ = factory.newDocumentBuilder();
124 <u>XPathFactory xf = XPathFactory.newInstance();
125 xp_ = xf.newXPath();</u>
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
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 {
141 </kbd>//Création d'un DOM pour le fichier source<kbd>
142 Document doc = db_.parse(fichier);
144 <u>NodeList nl = (NodeList) xp_.evaluate(chemin,
146 XPathConstants.NODESET);</u>
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> :
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>
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.
176 <div class="sws-slide">
178 <code><kbd> Document doc = ...
179 String chemin = <u>"//descendant::year[position () = 1]";</u>
182 </kbd>//Crée une NodeList à un élément<kbd>
183 <u>NodeList nl = (NodeList) xp_.evaluate(chemin, doc, XPathConstants.NODESET);</u>
185 </kbd>//Renvoie le nœud correspondant ou null<kbd>
186 <u>Node n = (Node) xp_.evaluate(chemin, doc, XPathConstants.NODE);</u>
188 </kbd>//Renvoie le double java correspondant à la valeur<kbd>
189 <u>Double d = (Double) xp_.evaluate(chemin, doc, XPathConstants.NUMBER);</u>
191 </kbd>//Renvoie la chaine java correspondant au texte<kbd>
192 <u>String s = (String) xp_.evaluate(chemin, doc, XPathConstants.STRING);</u>
194 </kbd>//Renvoie la valeur de vérité corresondant au chemin<kbd>
195 <u>Boolean b = (Boolean) xp_.evaluate(chemin, doc, XPathConstants.BOOLEAN);</u>
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>
208 <kbd> <u>XPathExpression ex = xp_.compile("//movie/title");</u>
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);
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 :
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).
231 <li>La transformation elle même (ex: <tt>style.xsl</tt>) peut être
232 sous forme diverse (fichier, URL, DOM, …)
234 <p>On a donc une série de classes d'encapsulation (<tt>Source</tt>,
235 …), de factory, …</p>
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>
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>
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>
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>
261 <div class="sws-slide">
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>
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
277 <code> <kbd>Document style_xsl = … ;</kbd>//chargement de style.xsl
279 <u>TransformerFactory tf = TransformerFactory.newInstance();</u>
280 <u>Transformer tr = tf.newTransformer(new DOMSource(style_xsl));</u>
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)
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
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>
301 <div class="sws-slide">
304 //On applique le transformer associé à style.xsl
305 //sur le fichier movie et on écrit le résultat sur
306 //la sortie standard :
308 <u>tr.transform(new StreamSource("movies.xml"), new StreamResult(System.out));</u>
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
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(new DOMSource(doc),</u>
321 <u>new StreamResult(new FileOutputStream("fichier.xml")));</u>
324 <h1><i>Streaming</i> avec SAX</h1>
325 <div class="sws-slide">
326 <h1><i>Streaming</i> ?</h1>
327 <p>Charger un document avec DOM permet d'accéder à l'arbre « en
328 entier » mais peut être couteux en mémoire (chaque nœud possède au
329 moins 4 pointeurs, 2 chaines de caractères, …). On veut pouvoir
330 effectuer certains types d'opération à la volée :
332 <ul class="sws-pause">
333 <li class="sws-pause">Faire des statistiques sur les documents (compter le nombre
334 d'éléments, d'attributs, …)</li>
335 <li class="sws-pause">Faire des transformations simples qui
336 préservent la structure (par exemple mettre les balises en
338 <li class="sws-pause">Valider vis à vis d'une DTD</li>
341 <div class="sws-slide">
342 <h1>Programmation évènementielle</h1>
343 <p>Les parseurs SAX (Simple API for XML) reposent sur la programmation
344 évènementielle. Ils lisent le fichier d'entrée et génèrent un
345 certain nombre d'évènements, auxquels on peut réagir avec du code.
346 Les évènements sont :
349 <li>Début de document</li>
350 <li>Fin de document </li>
351 <li>Ouverture de balise (avec le nom et la liste des attributs)</li>
352 <li>Fermeture de balise (avec le nom)</li>
353 <li>Élément texte</li>
354 <li>Commentaire </li>
358 <div class="sws-slide">
361 import javax.xml.parsers.*;
362 import org.xml.sax.*;
363 import org.xml.sax.helpers.*;
365 <p>On doit étendre la classe par <tt>DefaultHandler</tt></p>
367 <div class="sws-slide">
368 <h1><tt>DefaultHandler</tt></h1>
370 //le parseur a lu length caractères qui se trouvent dans
371 //ch à partir de la position start
372 void <u>characters</u>(char[] ch, int start, int length)
374 //le parseur a détécté la fin de document
375 void <u>endDocument</u>()
377 //le parseur a détecté la fin d'un élément
378 void <u>endElement</u>(String uri, String localName, String qName)
380 //le parseur a détecté du texte « ignorable »
381 void <u>ignorableWhitespace</u>(char[] ch, int start, int length)
383 //le parseur a détecté le début du document
384 void <u>startDocument</u>()
385 //le parseur a detecté le début d'un élément
386 void <u>startElement</u>(String uri,String localName, String qName,
387 Attributes attributes)
389 <p><tt><u>Attributes</u></tt> est une classe auxiliaire qui permet de
390 connaître le nom, le nombre et les valeurs des attributs pour cette
394 <div class="sws-slide">
395 <h1><tt>Handler</tt> personnalisé</h1>
396 <p>On étend la classe <tt>DefaultHandler</tt> : </p>
398 <u>class MyHandler extends DefaultHandler</u> {
399 private int nb_elems;
403 void <u>startElement</u>(String uri,String localName, String qName,
404 Attributes attributes)
405 throws SAXException {
409 int getNbElems() { return nb_elems; };
415 <div class="sws-slide">
416 <h1>Invocation du parseur</h1>
417 <p>On utilise (encore) une factory : </p>
419 public static void main(String[] args) {
421 SAXParserFactory spf = <u>SAXParserFactory.newInstance</u>();
422 spf.setNamespaceAware(true);
423 SAXParser saxParser = <u>spf.newSAXParser</u>();
425 MyHandler my = <kbd>new MyHandler()</kbd>;
426 XMLReader xmlReader = <u>saxParser.getXMLReader</u>();
427 xmlReader.<u>setContentHandler(my)</u>;
428 xmlReader.parse(filename);