Flux RSS d'opikanoba.org

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


Billets de la catégorie ‘notes’

L’élément XInclude

Les différents attributs de l’élément XInclude sont les suivants :

attributs description
href définit la localisation des données à inclure. L’attribut peut être omis, le document sur lequel se fera l’inclusion sera le document dans lequel est définie cette inclusion. Si hrefest présent, il s’agit d’un URI ou d’un IRI (URI internationnalisé sans obligation d’échapper les caractères spéciaux)
parse indique si le fichier doit être analysé (parse="xml") ou non (parse="text")
xpointer permet de limiter l’inclusion à une partie du document. La définition de la zone restreinte utilise le framework XPointer
encoding permet de définir l’encodage attendu de la ressource lorsque parse="text"
accept permet de fixer l’entête HTTP accept pour définir une préférence sur le format de la ressource à obtenir.
accept-language permet de fixer l’entête HTTP accept-language pour définir une préférence quant à la langue de la ressource à inclure

Support de XInclude

De nombreux processeurs mettent déjà en œuvre XInclude mais de façon très inégale. La principale différence réside dans le support plus ou moins poussé de XPointer et de ses schémas (xpointer(), xmlns(), element()…).

XOM et JDom, par le biais de la brique XIncluder, supportent une partie de XInclude (les fragments et les fallbacks ne sont pas implémentés par exemple). Il en est de même pour Xerces, qui fait cependant l’impasse sur XPointer. GnuJax offre un support également très partiel de XInclude. Enfin, les framework de publication dynamique XML comme Cocoon ou Orbéon offre également un support partiel de XInclude. Libxml fournit un support complet de la spécification, tout comme XInclude.NET qui supporte des schémas XPointer complémentaires (element(), xmlns(), xpath1(), xpointer()). Que ce soient les librairies pour Python (4Suite) , pour perl (Petal ou XML::Filter::XInclude) ou php, les supports sont d’ores-et-déjà présents mais avec des niveaux de complétudes très disparates. Sans doute s’agit-il d’une question de temps.

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

Scalable Vector Graphics

Scalable Vector Graphics (SVG) est un langage XML, né en 1998 peu après la recommandation XML 1.0. Il est issu d’un groupe de travail du W3C. Il permet de créer des graphiques vectoriels en deux dimensions dans un format texte portable. Il est composé de trois concepts : des formes vectorielles, des images et du texte. Tous ces objets graphiques peuvent être regroupés, mis en forme, transformés par des fonctions mathématiques (translation, multiplication de matrice, modification d’échelle,…). SVG fournit également tout un ensemble de possibilités pour créer des filtres élaborés, des dégradés de couleurs, ou autres effets d’éclairage. SVG supporte de nombreuses autres recommandations du W3C, en particulier Xlink, CSS, DOM, SMIL… Ainsi, SVG peut être utilisé pour créer des graphiques statiques, mais aussi dynamiques et interactifs. Les événements DOM remontent des informations sur la modification du document ou du contexte de la page Internet (clic de la souris par exemple) et le Javascript permet de réagir en conséquence. Les multiples possibilités du langage ont en fait un concurrent très sérieux à la technologie Flash (d’autant que le format est libre de droit, et engendre un coût de développement nul en termes d’infrastructure logicielle). Le format XML, rend ce format utilisable par toutes les librairies XML disponibles sur le marché et permet de créer un graphique avec un simple traitement de texte. SVG s’intègre très bien avec les pages XHTML et l’utilisation de XSL-FO permet également d’insérer des graphiques à l’intérieur des documents PDF. Pour visualiser des documents SVG, un logiciel est nécessaire. Il s’agit soit d’une application à part entière, comme tous les produits d’Adobe (GoLive, illustrator), la visionneuse SVG de Batik (framework d’Apache en Java), le logiciel Inkscape, le navigateur X-Smiles,…Il peut également se présenter sous la forme d’un plugin pour votre navigateur. Le plugin d’Adobe pour Internet Explorer ou celui de Corel, la version de Mozilla avec SVG intégrée, KSVG pour Konqueror…Voici un exemple de document SVG.


<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="12cm" height="4cm" viewBox="0 0 1200 400"
     xmlns="http://www.w3.org/2000/svg" version="1.1">
  <!-- un cercle rouge avec un contour bleu  -->
  <circle cx="600" cy="200" r="100"
        fill="red" stroke="blue" stroke-width="10"  />
</svg>

Un document SVG est identifié par une balise éponyme. Ici seul un cercle rempli en rouge avec un bord épais bleu est affiché.

Python et les listes

S’il y a bien un concept sur lequel Python est éclatant, c’est bien le support natif des listes. Les listes, les fonctions lambda, filter et la forme associée au concept de liste “[expression for e in list]”. La méthode de collecte de données utilisée dans l’exemple utilise ces concepts, rendant le code plus concis et plus facile à comprendre. Voici un petit rappel pour clarifier les choses. Une fonction lambda est une fonction anonyme, qui associée à map ou filter (fonctions du langage Python) permet d’appliquer un traitement identique sur chaque élément d’une liste, et ce en une seule ligne. Par exemple, multiplier tous les éléments d’une liste d’entiers par 2 ou ne garder que les nombres pairs :

>>> liste=[1,2,3,4,5,6]
>>> map(lambda e: e*2, liste)
[2, 4, 6, 8, 10, 12]
>>> filter(lambda e: e % 2 ==0, liste)
[2, 4, 6]

L’inconvénient des fonctions lambda reste son écriture, qui rappelle les langages fonctionnels comme prolog ou caml. Cette écriture qui contraste fortement avec la programmation classique déroute souvent les programmeurs. Une autre forme peut alors être utilisée “[expression for e in liste]”. D’aucuns prétendent qu’elle est plus claire… Chacun se forgera une opinion.

>>> [e*2 for e in liste]
[2, 4, 6, 8, 10, 12]

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 un (ou une combinaison de) chemin de localisation. Un chemin est une représentation d’un parcours de l’arbre XML jusqu’à l’information désirée. Le parcours peut être absolu, c’est à dire qu’il part de la racine du document, ou relatif (un noeud sert de point de départ). Le chemin de localisation est composé d’une ou plusieurs étapes de localisation.

Chaque étape est découpée en trois parties : un axe, un test de noeud, et un ou plusieurs prédicats (que l’on peut schématiser par la syntaxe "axe::test[predicat]“). L’axe indique la direction dans laquelle démarrer le parcours : les axes fils, descendant, parent, ancêtre, voisin, espace de noms, attribut permettent de sélectionner un premier sous-ensemble de noeuds. Le test de noeud diminue le précédent résultat en ne sélectionnant que les noeuds qui répondent positivement au test. Par exemple /descendant::personne est un chemin de localisation qui ne contient qu’une seule étape de localisation. Elle part de la racine (chemin absolu commençant par un /), utilise l’axe descendant pour ne sélectionner que les noeuds situés sous la racine, et applique une nouvelle restriction à cet ensemble, en ne gardant que les éléments dont le nom de balise est "personne". La troisième et dernière partie de l’étape de localisation permet de raffiner une nouvelle fois en appliquant des prédicats, par exemple : le premier noeud de l’ensemble, celui qui contient un attribut nom valant "dupond" (/descendant::personne[@nom="dupond"]), etc… Le caractère / permet d’enchaîner plusieurs étapes de localisation.

Cette technologie gigogne peut devenir rapidement verbeuse. C’est la raison pour laquelle, XPath définit une notation abrégée pour certains noms d’axe et pour certains tests (.. pour l’axe parent, @ pour l’axe attribut, personne[1] pour personne[position()=1], etc…). Ainsi, l’expression

/descendant::personne[position()=1]/descendant-or-self::
node()/child::voiture[attribute::couleur="rouge"]

peut s’écrire de façon plus concise

//personne[2]//voiture[@couleur="rouge"]

Enfin, une panoplie de fonctions manipulant les ensembles de noeuds, les chaînes de caractères, les nombres ou encore les booléens complète les concepts évoqués précédemment. XPath offre donc un moyen de concentrer dans une seule expression un parcours simple ou extrêmement complexe de l’arbre XML, permettant de localiser les données recherchées. Cependant, certaines requêtes restent impossibles à formuler. XPath 2 (document de travail du W3C proche du statut de recommandation) apportera alors une solution à ce problème marginal.

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é. Cela ne pose pas réellement de problème lorsque le préfixe est défini dans le document original (par exemple, xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" définit l’espace de noms RDF et lui associe le préfixe rdf), car classiquement, c’est ce même préfixe qui est utilisé dans une expression XPath (ce n’est pas obligatoire, puisqu’en termes d’espaces de noms, seule l’URI importe, le préfixe n’est qu’un alias).

Par contre, pour les espaces de noms par défaut (qui ne possèdent pas de préfixe), il faut leur en attribuer un. Ainsi, dans les programmes de cet article, tous les espaces de noms par défaut commenceront par "dns" suivi d’un entier incrémenté automatiquement. Le préfixe dns1 correspond alors à l’URI http://purl.org/rss/1.0/, qui figure dans le document XML original en tant qu’espace de noms par défaut. les éléments présents dans cet espace de noms par défaut dans le fichier original, tels que <title> ou <description> seront accessibles dans l’expression XPath via <dns1:title> ou <dns1:description>.

DOM 3 : 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. Définie au niveau de l’interface Node, la méthode isSupported() répond true ou false selon la fonctionnalité demandée (en fait un couple (fonctionnalité, version)). La construction de l’évaluateur XPath se fera soit par retypage de l’objet Document (si la réponse à isSupported("XPath", "3.0") est vraie), soit par obtention d’un objet via un appel à getFeature("XPath", "3.0") puis retypage (si la réponse à isSupported("+XPath", "3.0") est vraie. Attention le signe + devant la chaîne “XPath” est très significatif). Toutes ces opérations se déroulent au niveau de l’interface, il n’y a donc aucun lien avec l’implémentation.

Groovy et BouncyCastle

L’installation de BouncyCastle permet de rajouter une implémentation tierce, Open Source, des algorithmes liés à la crypographie. La simplicité des tests avec Groovy permet de vérifier que tout fonctionne dans l’environnement Java.

Avant d’installer BouncyCastle, un petit test des fournisseurs existants (ceux par défaut)

import java.security.*
p = Security.getProviders()
count=1
p.each { println("[${count++}] ${it.getName()} -> version : ${it.getVersion()}”)}

[1] SUN -> version : 1.42
[2] SunJSSE -> version : 1.42
[3] SunRsaSign -> version : 1.42
[4] SunJCE -> version : 1.42
[5] SunJGSS -> version : 1.0

Après téléchargement de la dernière version, on obtient un fichier zip qui contient un répertoire jars. Celui-ci contient les archives adaptées à chaque JVM. Il faut copier le bon (par exemple bcprov-jdk14-124.jar pour le jdk 1.4) dans le répertoire javahome/jre/lib/ext. (Une autre solution consiste à le fournir à la JVM par le biais de l’argument XBootclasspath)

Ensuite pour indiquer à la JVM de prendre en compte les nouveaux paquetages, il faut éditer le fichier jre/lib/security/java.security et ajouter la ligne suivante :

security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider

Le nombre 6 vient du fait que le dernier index, celui de SunJGSS, était 5. En exécutant de nouveau le script, on note que le fournisseur est bien disponible

[1] SUN -> version : 1.42
[2] SunJSSE -> version : 1.42
[3] SunRsaSign -> version : 1.42
[4] SunJCE -> version : 1.42
[5] SunJGSS -> version : 1.0
[6] BC -> version : 1.24

Pour permettre l’usage d’une librairie tierce concernant la sécurité, il faut télécharger sur le site de Sun deux nouveaux jar qui lèvent des contrôles de sécurité quant aux fournisseurs. Cette archive zip est disponible sur la même page de téléchargement que le JSDK lui-même et se nomme «Unlimited Strength Jurisdiction Policy Files 1.4.2» Une fois téléchargés, les fichiers local_policy.jar et US_export_policy.jar remplacent ceux situés dans le répertoire jre/lib/security.

Il faut également spécifier dans le programme Java le fournisseur, par

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())

BounceCastle possède «BC» comme nom de fournisseur, il faut donc l’utiliser lors de la récupération de l’instance du KeyGenerator

import javax.crypto.*
import java.security.*

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())
kg = KeyGenerator.getInstance("DES","BC")
kg.init(new SecureRandom())
key = kg.generateKey()
println(key)
println("format : " + key.getFormat())
println("Key algorithm: " + key.getAlgorithm())

produit le résultat suivant :

javax.crypto.spec.SecretKeySpec@fffe7ab9
format : RAW
Key algorithm: DES

Enfin, un petit test d’encodage avec l’algorithme symétrique DES

import javax.crypto.*
import java.security.*
import java.io.*
import org.apache.commons.codec.binary.Hex

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())
kg = KeyGenerator.getInstance("DES","BC")
kg.init(new SecureRandom())
key = kg.generateKey()
encrypt = Cipher.getInstance("DES/CBC/PKCS5Padding", "BC")
encrypt.init(Cipher.ENCRYPT_MODE, key)

texteclair = "abracadabrantesque"

println("format : ${key.getFormat()}, algorithme : ${key.getAlgorithm()}")

// affichage du texte en clair
println("texte en clair ${texteclair} [len=${texteclair.length()}]“)
hexRepr = new String(Hex.encodeHex(texteclair.getBytes()))
println(”texte en clair (hex) : ${hexRepr.toUpperCase()} [len=${hexRepr.length()}]“)

// encodage
cryptext = encrypt.doFinal(texteclair.getBytes())

// affichage du texte crypté
hexRepr = new String(Hex.encodeHex(cryptext))
println(”texte encrypte (hex) : ${hexRepr.toUpperCase()} [len=${hexRepr.length()}]“)

produit le résultat suivant :

format : RAW, algorithme : DES
texte en clair abracadabrantesque [len=18]
texte en clair (hex) : 61627261636164616272616E746573717565 [len=36]
texte encrypte (hex) : 7CF8D889EB271236793A4C7002AF3D2BEA6816B3AF36D225 [len=48]

La librairie common.codec d’Apache est bien pratique ici pour afficher sous forme hexadécimale, un tableau d’octets. Si c’est très simple en Python :

>>> for c in texteclair:
...     print hex(ord(c)),
...
0x61 0x62 0x72 0x61 0x63 0x61 0x64 0x61 0x62 0x72 0x61 0x6e 0x74 0x65 0x73 0x71 0x75 0x65

c’est un peu pénible à faire en Java ! :( Merci Apache…

Canaux atom des groupes de discussions (merci google)

Google propose des canaux Atom pour suivre les groupes de discussions (Usenet). Disponibles dans leur nouvelle version Google Groups 2 bêta

Ils ne sont pas facile à trouver pour l’instant. Deux solutions :