Flux RSS d'opikanoba.org

Sur l’interopérabilité, l’architecture et les systèmes d’informations de santé


Java SE 6 met l’accent sur les services Web

Alors que Tiger - Java SE 5 - est disponible depuis peu et que Sun travaille sur GlassFish - Java EE 5 -, la planification des futurs composants de Mustang - Java SE 6 - est déjà disponible. Il s’agit bien sûr que d’une vue prévisionnelle, puisque sa sortie est prévue mi 2006, mais jetons d’ores et déjà un oeil sur les nouveautés, liées à XML, de cette future plate-forme.

Après avoir intégré de nombreuses technologies XML de bases dans les actuelles machines virtuelles Java, Mustang fait le choix de l’intégration des technologies relatives aux services web. Celles-ci, présentes du coté serveur (Java EE), arrivent du côté des applications clientes (Java SE). Ainsi, JAX-WS 2.0 (Java API for XML Web Services) et JAXB 2.0 (Java Architecture for XML Binding) font leur entrée dans Java 6.

Il s’agit là des deux évolutions majeures. Notons cependant que JAXP - Java API for XML Processing - passera en version 1.4, avec l’intégration de l’API d’analyse syntaxique StAX (JSR 173). Celui-ci est déjà inclus dans le WSDP 1.6 - Web Services Developer Pack. La signature numérique des documents XML - JSR 105, XML Digital Signature API - sera également intégré à Mustang.

JAX-WS 2.0 : Java API for XML Web Services
JAX-WS est la nouvelle appellation de JAX-RPC (Java API for XML Based RPC). En effet, JAX-RPC ne convient plus à l’ensemble des concepts couverts. Cet acronyme donne l’impression qu’il s’agit uniquement de technologies synchrones, relatives à l’appel de procédure à distance et non aux services web. De plus l’intégration de JAXB 2.0 pose de nombreux problèmes de compatibilité avec JAX-RPC 1.1. C’est ainsi l’occasion pour Sun de repenser, mettre à jour, améliorer et surtout rationaliser cette brique logicielle en utilisant les dernières nouveautés du langage lui-même, ainsi que les technologies développées en parallèle dans d’autres groupes de travail.

La volonté du groupe de travail est de supprimer les développements spécifiques - indispensables dans les versions antérieures, en raison de contraintes de calendrier - et de s’appuyer sur des composants éprouvés (JAXB) ou des standards (WS-*). Ainsi, si JAX-RPC 1.x utilise sa propre méthode de correspondance entre données XML et objets Java, JAX-WS 2 s’appuie désormais sur JAXB 2.0. JAX-WS 2.0 utilise également les nouvelles facilités du langage Java, introduites dans la version 5. Les annotations (JSR 175) utilisent des concepts, inhérents au langage Java et aux outils associés, qui facilitent le développement de scénarios classiques côté client mais également côté serveur. Elles déchargent le développeur de l’ajout d’informations jusqu’à lors nécessaires pour transformer un service classique en un service web. Certaines méta-données ont d’ailleurs été spécialement définies pour le compte des services web (JSR 181). Elles permettent de remplacer la technique de correspondance Java - WSDL, en annotant directement le code Java. Doug Kohlert - responsable technique de JAX-RPC - estime que ces nouvelles facilités permettent d’économiser une somme importante de code (en taille et en nombre) allant jusqu’à 85% d’économie. Ces facilités sont complétées par la JSR 109 - Implementing Enterprise Web Services - qui permet de déployer, de gérer et d’accéder à un service web par le biais d’un serveur d’application Java. Cette JSR couvre les modèles de programmation côté client - accéder à des services comme des objets distants traditionnels - mais aussi côté serveur - comment les services web peuvent être mis en oeuvre par une servlet ou un EJB.

Elle aborde également la façon de déployer ces services dans un serveur d’application. Pour compléter le tout, la JSR 183 - Web Services Message Security APIs - utilisée par JAX-WS aborde la sécurité des échanges de message SOAP.

La nouvelle mouture de JAX-WS est bien sûr l’occasion d’intégrer les dernières versions des standards utilisés. SOAP 1.2 est désormais supporté étant donné son statut de recommandation. Cependant, le support de SOAP 1.1, largement déployé, est assuré. WSDL 2.0 n’est pas encore une recommandation mais le sera certainement durant la cycle de vie de cette JSR, qui continuera d’offrir le support de WSDL 1.1. WS-I Basic Profile 1.1 supplante la version 1.0, actuellement supportée par JAX-RPC 1.1. Enfin, JAX-WS permet d’utiliser de façon optionnelle les récentes spécifications du W3C liées à l’optimisation de la transmission de données binaires dans des messages SOAP : MTOM/XOP (Message Transmission and Optimization Mechanism/ XML Binary Optimized Packaging).

Par ailleurs, JAX-WS 2.0 ajoute ou améliore certains concepts connexes. Une opération WSDL pourra désormais être asynchrone. Des mécanismes de gestionnaire d’événement (handler) et de consultation asynchrone de la réponse à une invocation (polling) sont mis en place dans cette JSR. JAX-WS 2.0 améliore aussi le développement de gestionnaires - logiques ou SOAP - permettant de suivre les messages échangés - leur contexte, leur sens de circulation - et d’accéder aux informations présentes dans les messages ou en-têtes. Autre point intéressant, la possibilité de gérer des versions d’un service web apparaît. Actuellement, l’évolution d’un service web est coûteux et délicat, cette JSR tente de faciliter l’évolution et le déploiement d’une nouvelle version d’un service web. Enfin, JAX-WS accentue également la séparation entre les données transportées (XML) et la couche transport, permettant ainsi de faire des invocations de services sur un protocole différent de HTTP. De plus, la gestion de session, liée à HTTP dans JAX-RPC 1.1, pourra se faire grâce à des informations présentes dans les messages SOAP.

Tant de changements impliquent des choix. Et JAX-WS en fait de nombreux. La correspondance données-XML est déléguée à JAXB. Il n’est pas prévu de fournir une possibilité évoluée de changer la technologie sous-jacente de “binding”. Cependant JAXB pourra être désactivé ponctuellement pour faire place à une technologie alternative. Contrairement à JAX-RPC 1.x, cette nouvelle version ne prendra pas en charge l’encodage SOAP 1.2. Cet usage est déprécié par WS-I Basic profile. Même si JAX-WS 2.0 offre un certain niveau de compatibilité ascendante, le fonctionnement du code issu de la génération de JAX-RPC 1.x n’est pas assuré. Il est donc nécessaire de modifier le code afin de s’insérer dans ce nouveau cadre. Enfin JAX-WS s’appuie sur de nombreuses fonctionnalités de Java 5 - annotation (JSR 175), génériques (JSR 14), types énumérés (JSR 201) … - le support des machines virtuelles antérieures ne sera donc pas pris en compte.

JAXB 2.0 : Java Architecture for XML Binding
JAXB 2.0 est l’évolution logique de la version 1.0, définie par la JSR 31. JAXB 2.0 supporte désormais l’ensemble des fonctionnalités définies dans XML Schema, ce qui n’avait pas été possible pour des raisons de calendrier dans la version 1 de JAXB. Là où JAXB 1.0 offrait une façon de partir du schéma pour arriver aux classes Java, JAXB 2.0 ajoute la possibilité d’avoir une correspondance bidirectionnelle. Par ailleurs, il est maintenant possible d’avoir une correspondance limitée à un fragment de document XML.

Alors que JAXB 1 n’assurait pas un processus invariable d’aller-retour entre XML et Java - un bean Java transformé en XML qui est de nouveau transformé en bean Java. JAXB 2.0 impose que ces transformations assurent l’invariabilité des données (Java et XML). La prise en compte d’un XML incorrect, aspect non-traité dans JAXB 1, sera définie. Un effort sur la portabilité des classes annotées permettra de conserver des classes issues d’une mise en oeuvre même si celle-ci est amenée à changer. Les classes JAXB 1 issues du schéma XML devaient être compatibles au niveau du code avec les implémentations JAXB 1, celles de JAXB 2 devront également être compatibles au niveau du bytecode. Enfin, l’utilisation des annotations des javabeans existants devrait permettre aux bibliothèques JAXB de générer automatiquement les objets responsables du chargement et de la sauvegarde de ces beans en XML.

A l’instar de JAX-WS 2.0, JAXB 2.0 fait également des choix. La JSR 222 utilise ainsi pleinement les facilités du langage Java 5, avec les conséquences de compatibilité avec les JDK antérieurs que cela engendre. Du côté des grammaires, seuls les schémas XML sont supportés. JAXB 2.0 part du principe qu’il est simple de convertir une DTD en Schéma - par l’intermédiaire de nombreux outils. La validation à la volée des classes java par rapport à des contraintes exprimées dans un schéma, supportée dans JAXB 1, n’est plus d’actualité dans JAXB 2.0. Enfin, à l’image de JAX-WS, JAXB n’utilise plus l’encodage SOAP, qui est remplacé par WS-I Basic Profile.

Cependant, à l’heure actuelle, il reste des points à préciser. JAXB se propose d’explorer les possibilités d’évolution de schémas, tant dans le domaine des applications centrées sur les données (services web) que dans le domaine des applications centrées sur les documents. JAXB 2.0 doit, par ailleurs, clarifier l’intégration et les relations avec StAX (JSR 173).

Sun a affiché très clairement, lors de la présentation des orientations futures de la plate-forme Java à JavaOne, sa volonté de renforcer la pile des technologies XML présentes dans la machine virtuelle et de faciliter le développement des services web. Graham Hamilton évoque que la version suivante (java 7 ou dolphin) poussera plus loin encore l’utilisation des services web en les mariant avec JMX pour offrir de l’administration à distance par le biais de services web. Il évoque également une possible intégration de XML au niveau même du langage Java. Cependant, cela reste à l’état de projet et ne verra pas le jour avant 2008.

Autres articles :

Voir aussi :

Liste des JSR relatives à XML et aux services web :

Hibernate 3.0 ajoute la persistance des documents XML

La nouvelle version d’Hibernate, passé sous le giron de JBoss, permet de prendre en compte, grâce à DOM4j, le traitement et la transformation des documents XML pour rendre leurs données facilement persistantes.

Hibernate est un framework Java de persistance qui permet de faire correspondre des tables de base de données relationnelle avec des objets java simples (POJO ou «Plain Old Java Object»). Une fois la correspondance entre les deux mondes définie, le programme Java peut manipuler toutes les données en utilisant que des JavaBean, masquant alors totalement la base de données sous-jacente et ses spécificités. Le framework assure le remplissage de ces objets et la mise à jour de la base en se basant sur leur contenu. Avant la sortie de la version 3 de ce framework, XML constituait déjà le format de description de la correspondance entre les tables relationnelles et les classes Java.

Hibernate 3 franchit un pas supplémentaire. De la même façon que les POJO permettent de manipuler des objets dont les données sont stockées dans une base de données, cette nouvelle fonctionnalité permet de s’affranchir des solutions XML propriétaires. En effet, chaque fournisseur, se devant de se préoccuper de l’importation/exportation des données XML, fournit une solution qui lui est propre à défaut de se baser sur un standard.

Le framework Hibernate permet d’obtenir une représentation XML du résultat d’une requête. Il permet aussi de rendre persistant, c’est-à-dire d’insérer ou de mettre à jour des données dans la base de données depuis des fragments de document XML de façon très simple et similaire à la manipulation de POJO.

Pour illustrer ces ajouts, prenons l’exemple (extrêmement simple) d’une table contenant une liste de tâches à faire, les fameux TODO. Voici une définition SQL possible de la table TODO_TASK:

CREATE TABLE TODO_TASK (
  TODOID INTEGER NOT NULL PRIMARY KEY,
  SUMMARY VARCHAR(45) NOT NULL ,
  DESCRIPTION VARCHAR(45),
  PRIORITY INTEGER,
  DONE TIMESTAMP);

Hibernate permet non seulement de définir une correspondance entre cette table et un bean Java, mais également entre la table et un document XML. Dans cet exemple, le structure des données XML sera la suivante :

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="bean">
  <class name="TodoTask"
         table="todo_task" node="todo">
    <id name="todoid" node="@id"/>
    <property name="summary" not-null="true" node="sum"/>
    <property name="description" node="descr"/>    <property name="priority" node="@priority"/>
<property name="doneDate" column="done"/>
  </class>
</hibernate-mapping>

Ainsi, Hibernate fera une correspondance automatique entre, par exemple, le contenu du noeud sum, fils du noeud todo et la colonne summary. Par ailleurs, la colonne done sera disponible dans les beans Java (via la propriété doneDate), mais ne le sera pas dans les fragments XML.

La gestion du XML est assurée par DOM4j. Cette librairie très complète offre le support de DOM, SAX et JAXP mais également des requêtes XPath et de XSLT. Ainsi un document provenant au programme sous une forme SOAP par exemple, peut être transformé dans le format XML pivot par le biais d’une transformation XSLT avant d’être pris en compte par Hibernate. Il peut alors être délivré sous une autre forme, comme un format de sortie SVG, par une autre transformation XSLT. L’association DOM4j/Hibernate permet donc de définir le format XML qui sera utilisé par le métier et délivre un environnement complet de transformation et de traitement de l’information.

Le bout de code Java suivant montre comment, à partir d’un fichier XML, contenant une liste de tâches, hibernate met à jour la base de données relationnelle :

SAXReader sr=new SAXReader(false);
Document doc=null;

try {
  doc = sr.read(ClassLoader.getSystemClassLoader().
                getResourceAsStream("todo-ex.xml"));
} catch (DocumentException e} { ...} 

List todo=doc.selectNodes("//todo");

Session session = sessionFactory.openSession();

Session xmlSession = session.getSession(EntityMode.DOM4J);
Transaction tx=session.beginTransaction();

for (Iterator it=todo.iterator(); it.hasNext(); ) {
xmlSession.saveOrUpdate(”bean.TodoTask”,it.next());
}

tx.commit();

session.close();

Le document est lu grâce à un analyseur syntaxique SAX. La requète XPath permet d’obtenir une liste de tâches Todo. Puis, une session est ouverte. Elle est de type «EntityMode.DOM4J», ce qui indique au framework qu’il doit utiliser la librairie XML et que les données se trouvent dans des fragments XML et non dans des POJO. La boucle les parcourt et les fournit à la session XML qui se charge de mettre la base de données à jour. Le fait de spécifier bean.TodoTask lors de l’action sur la base, permet au framework de connaître à quelle correspondance les noeuds «todo» font référence.

De façon similaire, la consultation de la base peut se faire ainsi :

Element root=docFactory.createElement("todolist");
Document doc=docFactory.createDocument(root) ; Session session = sessionFactory.openSession();

Session xmlSession = session.getSession(EntityMode.DOM4J);
List res=(List) xmlSession.createQuery(”from TodoTask”).list();

for (int i=0; i<res.size(); i++){
  Element elt = (Element) res.get(i);
  root.add(elt);
}

session.close();

Un document hôte est créé de façon classique. La racine accueillera les différents éléments issus du résultat de la requête. Pour afficher le document XML, DOM4j fournit une classe XMLWriter :

XMLWriter xw;

try {
  xw = new XMLWriter(System.out, new OutputFormat("  ",true));
  xw.write(doc);
} catch (Exception e) {...}

Avec cette nouvelle version, Hibernate facilite non seulement la persistance en offrant une couche d’abstraction par rapport à la base de données, mais il permet désormais d’intégrer des données provenant de documents XML, de messages SOAP, de messages JMS, etc… Même si Hibernate n’a pas vocation à devenir un framework spécialiste du XML, cette extension au monde XML renforce les possibilités offertes par le framework pour assurer un découplage des objets métier avec les détails de mise en oeuvre du stockage en base de données relationnelle.

voir aussi :

Hibernate 3.0 ajoute la persistance des documents XML - fichiers d’exemple

Le test suivant se propose de tester la nouvelle fonctionnalité de mapping XML d’Hibernate. Voir l’article associé, pour plus d’informations.

Le projet se compose de plusieurs répertoires :

  • cfg : fichiers de configuration d’Hibernate, de propriétés (hibernate et log) et script pour la création de la table de la base de données
  • res : fichier XML de données, qui seront insérées dans la base
  • src : sources Java du test
  • build.xml: fichier Ant de compilation, exécution du test

Initialisation de la base

La base de données utilisée pour ce test, HSQLdb, est 100% Java et très simple à installer. Après l’avoir téléchargé et décrompressée dans un répertoire, il suffit de lancer le serveur et de provisionner la table. Pour plus d’informations, consulter la note à ce sujet.

java -cp lib/hsqldb.jar org.hsqldb.Server

Une fois le serveur démarré, l’insertion se fait à l’aide du DatabaseManager, par lecture et exécution du script SQL (create_todo.sql) suivant :

DROP TABLE TODO_TASK if EXISTS;

CREATE TABLE TODO_TASK (
  TODOID INTEGER NOT NULL PRIMARY KEY,
  SUMMARY VARCHAR(45) NOT NULL ,
  DESCRIPTION VARCHAR(45),
  PRIORITY INTEGER,
  DONE TIMESTAMP);

INSERT INTO TODO_TASK VALUES(001,'faire le cafe',
  'Prendre 7 volumes deau et 7 volumes de cafe', 1, CURRENT_DATE);

Ce script se situe dans le répertoire cfg du projet.

Lancement du test

Le test se lance grâce au script Ant. Il compile les classes et lance le programme Java MappingXML qui réalise 3 opérations :

  • modification de données via la manipulation d’un POJO (scénario classique)
  • lecture d’un fichier XML et insertion de ses données dans la base en utilisant les facilités d’Hibernate
  • consultation de la base, et génération d’un fichier de résultat au format XML
> ant

...
     [java] <?xml version=”1.0″ encoding=”UTF-8″?>

     [java] <todolist>
     [java]   <todo id=”1″ priority=”1″>
     [java]     <sum>faire le cafe</sum>

     [java]     <descr>Prendre 7 volumes deau et 7 volumes de cafe</descr>
     [java]     <doneDate>2005-05-02 00:00:00</doneDate>
     [java]   </todo>
     [java]   <todo id=”2″ priority=”2″>

     [java]     <sum>Faire une pause</sum>
     [java]     <descr>Allez a la cafet, prendre un cafe avec Bob</descr>
     [java]   </todo>
     [java]   <todo id=”4″ priority=”2″>

     [java]     <sum>installer eclipse</sum>
     [java]     <descr>une nouvelle version est disponible</descr>
     [java]   </todo>
     [java]   <todo id=”5″ priority=”1″>

     [java]     <sum>redemarrer le serveur</sum>
     [java]     <descr>une mise a jour du serveur tartenpion necessite un redemarrage</descr>
     [java]   </todo>
     [java]   <todo id=”6″ priority=”3″>

     [java]     <sum>documentation du product</sum>
     [java]     <descr>faire une documentation complete de notre super produit</descr>
     [java]   </todo>
     [java] </todolist>

all:

BUILD SUCCESSFUL

Le bean Java utilisé est bean.TodoTask et son fichier de correspondance Hibernate, Todo.hbm.xml, se trouve dans le répertoire cfg.

Fichiers

En résumé, voici les fichiers utilisés pour ce test :

 |   build.xml
 |
 +—- cfg
 |       create_todo.sql
 |       hibernate.properties
 |       log.properties
 |       Todo.hbm.xml
 |
 +—- res
 |       todo-ex.xml
 |
 \—- src
       |   MappingXML.java
       |
       \—- bean
                TodoTask.java

Utilisation de HSQLdb

Quelques notes sur l’utilisation de hsqldb. Cette base de données écrite en java s’utilise simplement, ne nécessite pas d’installation lourde et est très pratique pour faire des tests.

Voici un exemple d’utilisation très simple.

Démarrage de la base de données
La présente note utilise hsqldb en version serveur. Le serveur se sert d’un fichier de propriétés, s’il est présent pour se configurer. Ce fichier se nomme server.properties. En voici un exemple :

server.port=9001
server.database.0=file:/home/fred/mydb/tododb
server.dbname.0=todo
server.silent=false

Le démarrage du serveur se fait ensuite par l’exécution de la commande

java -cp lib/hsqldb.jar org.hsqldb.Server

Dans cet exemple, la base (0 car c’est la première) s’appelle todo (grâce à la définition de l’alias, server.dbname.0). Elle est localisée dans le répertoire /home/fred/mydb/tododb.

Console d’administration
La console d’administration permet de créer des tables, de faire des requêtes, bref d’exploiter la base. On peut la lancer ainsi :

java -cp lib/hsqldb.jar org.hsqldb.util.DatabaseManager
-url jdbc:hsqldb:hsql://localhost/todo -driver org.hsqldb.jdbcDriver -user sa

XOM : XML Object Model 1.0

XML est définitivement une affaire de personnalités ! Après Michael Kay et son processeur Saxon, Tim Bray et genX, Daniel Veillard et libxml, Elliotte Rusty Harold annonce un nouveau parseur Java XML : XOM 1.0.

Elliotte Rusty Harold est un expert des technologies XML. Auteur de plusieurs ouvrages sur le sujet, il s’est penché de près sur les avantages et les inconvénients des différentes API permettant de manipuler des documents XML. Sa conclusion est assez sévère : les API XML (comme SAX ou DOM) ont été écrites par des programmeurs experts qui découvraient XML. Ainsi le produit de leurs travaux n’était pas, toujours selon Elliotte Rusty Harold, d’une grande qualité. Cette arrogance, l’auteur la justifie par le fait qu’elle est construite sur une forte expérience du domaine et sur son expertise démontrée au fil des ans.

Ainsi, il a passé en revue les quatre types d’API : événementielles type push (comme SAX), événementielles type pull (comme XMLPull ou StAX), celles à base de représentation arborescente (comme DOM, JDOM, etc) et enfin celles dites de «Data Binding» (comme Castor ou JAXB). De toutes ces observations, Elliotte Rusty Harold en a tiré une conclusion. Toutes présentent suffisamment d’inconvénients pour laisser la place à une nouvelle qui tenterait d’être plus pertinente. Les objectifs qu’il fixe pour XOM sont prometteurs !

  • produire du XML correct. XOM est une implémentation de XML 1.0 focalisée sur l’impossibilité de produire du XML mal formé,
  • facile à utiliser grâce à une API intuitive évitant de consulter fréquemment la documentation,
  • facile à apprendre : un seul paquetage nu.xom pour toutes les fonctionnalités principales. Tout ce qui se trouve en dehors est optionnel et peut-être ignoré par un utilisateur débutant. XOM ne doit pas surprendre, les méthodes ont des noms explicites. Si XOM surprend, la surprise doit venir de XML lui-même et non de cette mise en oeuvre Java,
  • rapidité d’exécution et taille en mémoire acceptable : ces aspects ne sont clairement pas des priorités pour l’auteur qui préfère se concentrer sur les points précédents, pour offrir un ensemble stable qu’il pourra optimiser par la suite.

Pour construire cette API, Elliotte Rusty Harold a conjugué principes de conception objet, principes liés à Java et à la nature intrinsèque de XML. Ainsi les classes (il n’y a pas d’interfaces, l’auteur les jugeant inadaptées pour une librairie efficace) possèdent des pré-conditions et des invariants sur lesquels l’utilisateur ne peut passer outre. Seules les méthodes ne mettant pas en péril la conformité vis-à-vis de XML peuvent être surchargées. Et à l’instar des réflexions sur DOM Traversal, XOM n’implémente pas non plus le design pattern Visiteur (des données d’une classe pouvant être manipulées de l’extérieur sans contrôle). Car l’obsession de l’auteur est bien d’assurer l’impossibilité pour un utilisateur de produire un document XML mal formé.

Contrairement aux idées reçues, XOM n’a rien à voir avec JDOM. L’auteur a participé au développement de ce dernier et reconnaît avoir beaucoup appris techniquement. Cependant, en désaccord avec de nombreux principes de conception dans JDOM, il hésita à s’en servir de base pour en créer une nouvelle version. Finalement, il abandonna l’idée et repartit d’une feuille blanche. Si XOM est écrit en Java, l’API se distingue donc de JDOM ou de DOM4j en laissant certaines fonctionnalités inhérentes au langage Java volontairement de côté. Ainsi les classes sont pas «serializable» car XML est lui-même un format offrant cette fonctionnalité et est nettement plus inter-opérable que celui de la «serialisation» java. La notion de classe «Cloneable» est également laissée de côté au profit du copie constructeur classique. Les listes de noeuds utilisent une représentation interne à XOM et ne se basent pas sur les «List» Java, jugées pas assez performantes (notamment vis-à-vis des threads). Enfin, les principes de programmation objet sont respectés puisque les accesseurs en écriture ne retourne pas l’objet lui-même mais le type «void». Ce qui contraste avec les facilités de JDOM, qui permet notamment d’écrire, en une seule ligne

new Element(”html”).appendChild(new Element(”head”))

Les fonctionnalités de XOM 1.0 sont les suivantes :

  • libre, pure Java
  • un nouveau modèle de document XML 1.0. XOM ne supporte pas XML 1.1 (délibérément), qualifié d’abomination par l’auteur
  • support de XInclude
  • support de XML canonique (traduction française)
  • des ponts vers SAX et DOM
  • support de TrAX pour les transformations XSLT

Elliote Rusty Harold prévoit les améliorations suivantes :

Pour faciliter son utilisation, l’auteur fournit un tutorial. Par ailleurs, l’absence du support de XPath et le besoin de faire des requêtes sur les documents ont poussé Wolfgang Hoschek à développer Nux, une extension permettant d’utiliser XQuery (et donc XPath 2.0) avec XOM. Cette mise en oeuvre utilise Saxon-B comme moteur de requêtes.

Si XOM est un logiciel libre, il n’en reste pas moins qu’il est l’oeuvre d’un développeur déterminé à garder le contrôle de son oeuvre. Elliotte Rusty Harold insiste beaucoup sur ce point. Même s’il est ouvert aux critiques et suggestions, il proclame XOM comme une république bananière : «XOM is a more-or-less benevolent dictatorship, not a democracy. I am the only committer. This is my API, and it reflects my thoughts and desires». Cela a au moins le mérite d’être très clair ! XOM est disponible depuis le site xom.nu sous licence LGPL.

Autres articles :

Recherche rapide d’informations grâce à XPath

Avec l’avènement de XML, de nombreuses informations se retrouvent dans des fichiers au format texte structuré de façon arborescente, qu’il s’agisse de fichiers de configuration, de données à proprement parler ou de résultats de requête. Si la structure XML apporte lisibilité et robustesse, le problème d’accès à l’information demeure. Nous allons voir comment XPath y apporte une réponse vraiment puissante.

Magazine Login: n°120, septembre 2004 - Frédéric Laurent

De nombreuses techniques permettent de retrouver une valeur noyée au plus profond d’un arbre XML, mais elles ne sont pas toutes aisées à mettre en oeuvre. XPath, langage non XML, spécifié par le W3C, permet de déclarer de façon concise l’information recherchée. Le travail du programmeur est allégé en terme de code mais aussi de maintenance. Il peut en effet se concentrer uniquement sur la formulation de sa requête (le quoi) et non sur la façon d’y accéder (le comment).

Pour illustrer l’article, nous définissons deux types d’information à retrouver dans deux fichiers XML différents. Tout d’abord, nous souhaitons connaître la liste des servlets déclarées dans un fichier de configuration d’une application web J2EE (le fichier web.xml). Les noms de servlet sont définis par la balise <servlet-name>. Le fichier ne contient pas d’espace de noms. L’expression sera donc très simple. Le second exemple, en revanche, est plus complexe. A partir du fichier d’actualités du W3C (au format RSS 1.0, c’est à dire avec le support des espaces de noms), nous souhaitons connaître les annonces des nouveaux documents de travail. Ce qui revient à localiser le texte des balises <description> dont les balises adjacentes <title> contiennent le mot “Draft”. Cet exemple utilise donc les concepts d’axe XPath, d’espace de noms et de fonction XPath.

Différents types d’accès

Plusieurs techniques sont envisageables pour accéder à une information contenue dans un fichier XML. On peut citer la recherche de texte à l’aide des expressions régulières, l’API SAX, le modèle DOM, les librairies de correspondance (désigné par le terme anglais “binding”) XML vers des objets de n’importe quel langage de programmation, et bien sûr XPath.

Utilisation des expressions régulières

Un fichier XML est un fichier texte. Pendant longtemps, l’utilisation des expressions régulières a fait le bonheur des développeurs devant trouver des données dans ces fichiers texte. Cette technique est donc parfaitement applicable pour retrouver notre liste de servlets. En python, une première version naïve serait la suivante :

servletname="<servlet-name>(.*?)</servlet-name>"
webxml = open("WEB-INF\\web.xml").read()
print re.findall(servletname, webxml)
['invoker', 'CompressionFilterTestServlet', 'HelloWorldExample',
 'RequestInfoExample', 'RequestHeaderExample', 'RequestParamExample',
 'CookieExample', 'SessionExample', 'CompressionFilterTestServlet',
 'HelloWorldExample', 'RequestInfoExample', 'RequestHeaderExample',
 'RequestParamExample', 'CookieExample', 'SessionExample']

Pour ce cas simple, la solution semble parfaite. Cependant, il faudra penser à traiter les retours à la ligne entre la balise ouvrante et le texte à proprement dit. Le code se complexifie alors. Mais surtout comment repérer que <servlet-name>invoker</servlet-name> est déclaré ou ne l’est pas car compris entre un début et une fin de commentaire (resp. <!-- et -->) ? Complexifier encore l’expression régulière ? Ajouter du code pour contrôler cet aspect ? Faire une première lecture pour supprimer toutes les parties XML contenues dans des commentaires et travailler sur cette version épurée ? Les solutions sont multiples, mais elles présentent toutes de nombreux inconvénients. En occultant la sémantique du langage XML, le travail devient complexe et difficilement maintenable. Et que dire de notre second exemple…

Utilisation de SAX

SAX permet de répondre de façon plus intéressante que les expressions régulières car le format XML est traité de façon adaptée : les problèmes d’espaces entre balise et texte, ou de balises entre commentaires se résolvent d’eux-mêmes. Si SAX fournit un moyen rapide d’accéder à l’information puisqu’il est possible de ne prendre en compte que les données qui nous intéressent, il n’en demeure pas moins qu’il faut construire un programme pour trouver les différents noms de servlet. La classe dédiée peut être relativement simple, elle a cependant le principal inconvénient de fixer dans le programme la façon d’accéder à l’information. Si le format évolue, le programme doit être changé, recompilé, redéployé (selon le cas, et le langage).

Utilisation de DOM

L’API DOM, spécifiée par le W3C, permet également d’accéder aux informations des fichiers XML. Une fois le document lu en mémoire dans une structure de données standard, l’accès se fait par l’appel aux méthodes définies sur les classes Document, Element, Attribute… A l’image de SAX, cette solution exploite pleinement la spécificité du format XML et règle nombre de problèmes. Cependant, elle ne résout pas la dépendance entre le code du programme et le format du fichier XML.

S’il existe des alternatives à DOM, comme JDOM ou DOM4J par exemple, qui rendent le code plus concis et plus lisible, les inconvénients exposés ci-dessus persistent.

Utilisation du binding

Il s’agit d’obtenir une représentation du fichier XML sous forme de classe. L’accès est simple, cependant encore une fois, la consultation d’une information impose la génération de code (Java, Python ou autre), sa compilation éventuelle, son déploiement… Tout cela étant sujet à modification, et donc difficilement maintenable. De plus, pour accéder à la liste des noms de servlet, il faut coder explicitement l’accès par des appels à des accesseurs de la classe générée.

Utilisation de XPath

XPath : un langage pour intérroger les fichiers XML

La spécification XPath est assez simple. Peu de notions permettent de composer une expression qui localisera, dans le document XML, une simple valeur, ou un ensemble de noeuds. Une expression XPath définit …(lire la suite)

Face à tous ces problèmes de couplage fort entre le format XML et le code du programme, XPath apporte une réponse vraiment satisfaisante. La requête d’accès à l’information est la seule chose à définir. Le codage de l’affichage du résultat reste indépendant (des informations recherchées). Si la structure du fichier source XML change, seule l’expression XPath doit évoluer. Qui plus est, les instructions qui exploitent le résultat de l’évaluation sont vraiment simples. Il s’agit d’un parcours d’un ensemble de noeuds pour les résultats multiples (ensembles de noeuds, ou "node-set") ou la consultation d’une valeur. Enfin, l’utilisation de cette technologie permet également d’obtenir le résultat en tant que noeud DOM d’un document. Lui ajouter un nouveau noeud fils, un attribut ou du texte est donc une formalité. XPath ne se cantonne donc pas à la seule consultation d’information, mais fournit un véritable moyen d’accès à une partie du document XML. Libre au programmeur d’utiliser le résultat comme bon lui semble.

XPath et la gestion des espaces de noms

Lors de la formulation d’une requête XPath, chaque espace de noms doit être explicitement nommé. Chaque élément doit pouvoir être préfixé… (lire la suite)

L’apparition d’une spécification claire pour l’utilisation d’API XPath s’est faite attendre. La conséquence immédiate est le développement par chaque librairie XML de sa propre API. Ainsi pour Java, Saxon, JDOM, Xalan, DOM4j,… fournissent ce service de façon propriétaire. Le W3C progresse sur une recommandation (qui n’est encore qu’un document de travail), et les différents projets comblent peu à peu ce manque de cohérence. Nous allons voir comment accéder aux informations désirées en utilisant d’une part Saxon et d’autre part l’API standard XPath (uniquement implémentée par Xalan, à ce jour).

Le premier exemple permet de manipuler une expression XPath triviale, puisqu’il s’agit d’obtenir la valeur textuelle de tous les noeuds <servlet-name>. L’expression //servlet-name/text() convient parfaitement. Le second exemple est plus ardu. Une des expressions XPath utilisable (il est possible de fournir de nombreuses autres solutions pour accéder à la même information) est :

//dns1:description[contains(preceding-sibling::dns1:title,'Draft')]/text()

ce qui peut se traduire en français par : prendre le texte de toutes les balises <description> (dans l’espace de noms dns1) qui contiennent un noeud frère nommé <title> (dans l’espace de noms dns1) et dont le contenu contient le mot ‘Draft’.

XPath avec Saxon

Le listing 1 présente comment utiliser Saxon pour obtenir notre liste de servlets. Le programme se contente de lire un fichier XML et d’évaluer l’expression XPath. Une fois le fichier lu (depuis le système de fichiers ou depuis une URL), l’objet XPathEvaluator de l’API Saxon est créé avec la référence sur le flux XML. Il servira à évaluer les requètes. Ce service est rendu par la méthode evaluate(). Elle renvoie un objet du type Java classique [List][23] qu’il suffit de parcourir pour afficher l’ensemble des résultats. Saxon fournit pour la représentation des noeuds, une classe [NodeInfo][24], qui offre contrairement à la classe [Node][25] du W3C, une méthode getStringValue() permettant d’en avoir une représentation textuelle. L’affichage est donc grandement simplifié.

Le listing 2 correspond au second exemple. Il est plus complexe puisqu’il faut gérer les espaces de noms. Chaque couple (préfixe, URI de l’espace de noms) doit être déclaré au niveau de l’évaluateur XPath. Enfin, les espaces de noms par défaut spécifiés dans le document XML (par une déclaration xmlns="http://...") doivent également posséder un préfixe au niveau XPath. Ainsi, la constante DEFAULT_NS_PREFIX définit la valeur textuelle du préfixe à laquelle un entier, incrémenté automatiquement, est accolé. Il n’existe pas de moyen prédéfini pour collecter les espaces de noms d’un document XML. Deux solutions relativement simples sont envisageables. La première consiste à utiliser la récursivité de la structure XML et les méthodes d’accès aux informations fournies par DOM. Le parcours récursif teste tous les attributs de tous les noeuds Element afin de trouver ceux qui commencent par "xmlns". La seconde solution est basée sur l’analyse syntaxique SAX en se concentrant uniquement sur les espaces de noms. C’est cette solution qui est retenue dans notre exemple. Ainsi, avant de fournir le flux XML à l’objet [XPathEvalutor][26], il est analysé une première fois par une classe dérivant du [DefaultHandler][27] de SAX 2. Seul le signal startPrefixMapping(prefix,uri) est utilisé. Cette méthode voit passer chaque déclaration d’espace de noms, elle se charge de l’enregistrer dans un objet [StandaloneContext][28] prévu, entre autres, à cet effet dans l’API Saxon.

Utilisation de l’API XPath DOM niveau 3

Les exemples suivants se basent sur des abstractions d’API. Le but recherché est bien sûr d’être indépendant de toute implémentation, afin d’offrir une pérennité et une maintenabilité plus grandes. La première abstraction concerne la lecture du document. Les documents XML sont lus en utilisant l’API JAXP. Définie par Sun, elle permet de ne pas se préoccuper de l’analyseur syntaxique sous-jacent. L’évaluation XPath se fait en utilisant l’ensemble des classes spécifiées par le groupe de travail DOM du W3C. Ainsi, même si actuellement seule Xalan implémente ce document de travail, l’utilisation de l’évaluateur XPath est indépendante. Dès qu’une autre librairie supportera XPath DOM niveau 3, il sera trivial de remplacer Xalan. Le code de l’exemple n’aura pas besoin d’évoluer (on notera d’ailleurs que les imports utilisés ne dépendent pas de Xalan). Il reste cependant un bémol à cette indépendance. Le document est très jeune, et l’implémentation de Xalan n’est pas finalisée. Ainsi, la création de l’évaluateur XPath est un peu différente de ce qu’elle devrait être (et de ce qu’elle sera dans les mois à venir). En effet, elle est effective en faisant appel explicitement à une classe de la librairie Xalan.

XPathEvaluator evaluator = new org.apache.xpath.domapi.XPathEvaluatorImpl(this.doc);

Dans la version finale, il faudra utiliser le mécanisme d’interrogation (les méthodes isSupported() et getFeature() de l’interface Node) de l’implémentation afin de choisir la bonne façon de créer l’objet XPathEvaluator.

Interroger une implémentation indirectement…

La recommandation DOM Niveau 3 introduit un mécanisme permettant d’agir selon les réponses d’une implémentation… (lire la suite)

Enfin, l’écriture sur la sortie standard du résultat de l’évaluation est également indépendante de toute librairie, puisque c’est une transformation XSLT identité qui l’effectue (la transformation identité prend en entrée un document XML et produit en sortie le même document XML).

Le listing 3 permet d’illustrer l’évaluation d’expressions simples, sans espaces de noms. La méthode evaluate() de l’XPathEvaluator produit un résultat qui est parcouru élément par élément. Chaque élément est affiché sur la sortie standard, par un simple println dans le cas d’un noeud Texte, ou par la transformation identité s’il s’agit d’un fragment de document.

Le listing 4 se charge de traiter les espaces de noms. L’analyse des déclarations d’espace de noms se fait de façon similaire à celle présente dans le listing 2. Par contre, la résolution des préfixes se fait de façon différente. Lors de la lecture du document source, un nouveau document DOM est créé. Son seul but est de porter l’ensemble des déclarations d’espace de noms. On peut se demander pourquoi créer un nouveau document, alors que le document RSS du W3C porte déjà toutes les déclarations sur son noeud racine (<rdf:RDF>). Pourquoi alors ne pas l’utiliser directement ? La raison est simple et double: le fichier RSS n’est qu’un exemple et il s’agit donc d’un cas particulier qui ne fonctionne que dans la mesure ou toutes les déclarations sont faites au niveau le plus haut. Si un nouvel espace de noms (par défaut ou préfixé) est déclaré dans les profondeurs de l’arbre, il ne sera pas pris en compte. De plus, cette méthode permet d’associer, de façon claire, un préfixe pour chaque espace de noms par défaut.

Un évaluateur XPathNSResolver est créé par la méthode createNSResolver(). Il sera consulté à chaque fois que le moteur d’évaluation rencontrera un préfixe et sera chargé de fournir l’URI correspondante. Cet objet est construit à partir du document portant toutes les déclarations, mais une autre méthode pourrait être employée. Elle est sans doute plus simple, mais la jeunesse de l’implémentation la rend indisponible pour l’instant. Le programmeur pourra fournir lui-même une classe implémentant XPathNSResolver. Elle ne rendra qu’un seul service (lookupNamespaceURI(String prefix)): donner l’URI exacte correspondant au préfixe qu’elle reçoit en paramètre. Pour autant, la phase de collecte des espaces de noms ne sera pas supprimée, mais la création du document transitoire pourra être évitée puisque cette classe fournira le renseignement.

Pour conclure…

L’utilisation de XPath n’est certes pas encore complètement standard, mais l’arrivée de la recommandation du W3C risque d’accélérer encore le processus. Cela dit, il ne s’agit là que de questions d’abstraction. Si l’indépendance vis-à-vis d’une librairie particulière n’est pas rédhibitoire, vous avez un large panel d’outils déjà disponibles vous permettant d’exploiter pleinement XPath dans vos programmes. L’intégrer sera d’autant plus intéressant que le nombre de requêtes sera important. Avec une classe utilitaire (helper class), l’accès aux informations de vos fichiers XML gagne en efficacité, maintenance, compréhension. Plus de code à maintenir mais simplement des chaînes de caractères décrivant les requêtes. Voila tout l’intérêt d’utiliser XPath dans vos programmes.

Les sources de l’article