Texte du Tuteur écrit par Gilles HUNAULT
Liste des autres tuteurs (langages, logiciels, systèmes d'exploitations...)
1. Quels outils logiciels pour XML ?
une liste de références Web
2. Comment tester qu'un document est bien formé
avec son navigateur favori, rxp, xmllint, perl, java, xmlstarlet
3. Comment tester qu'un document est valide
pour une grammaire DTD avec rxp, xmllint, perl, java, xmlstarlet
pour un schéma XSD avec perl et java seulement
4. Comment transformer un fichier XML à l'aide d'un fichier XSL ?
avec avec son navigateur favori, xlstproc, java, perl, php.
5. Archives de programmes pour Windows
libxml, libxsl, xsltproc, fop...
retour à la table des matières principales
retour à la table des matières principales1. Quels outils logiciels pour XML ?
On pourrait croire qu'il est très simple de manipuler des documents XML car ce ne sont que des fichiers texte avec des balises. Il est vrai que n'importe quel programmeur peut gérer des fichiers XML "à la main" avec n'importe quel éditeur de textes (comme Notepad, vi...) mais la complexité des documents et la structure en arbre des documents XML oblige à recourir à des outils spécifiques.
La plupart des utilisateurs utilisent des éditeurs spécialisés pour saisir les fichiers XML. Par exemple l'excellent xmlspy sous Windows est capable de construire une DTD à partir d'un fichier XML, de la convertir en schéma XSD, de reproposer automatiquement les balises déjà entrées, de fermer automatiquement les balises... De même XSLT editor sait afficher et gérer dans 3 fenêtres les fichiers source, "templates" et résultat d'une transformation XSL.
Suivant les besoins des utilisateurs et des applications (au niveau du poste client, sur le serveur Web, en Intranet etc.) les outils ne sont pas les mêmes et ne s'utilisent pas de la même façon. Ainsi pour les utilisateurs "farouches" de XML en ligne de commande, il existe des outils comme rxp, xmlwf, xmlstarlet et libmxl2 (en particulier xmllint) mais de nombreux outils sont installés en standard par exemple sur les serveurs Web de type Apache et sont donc transparents. Par exemple, charger un fichier XML avec Internet Explorer (version 5 ou supérieure) permet de le voir de façon structurée si le document est "correct".
Pour les programmeurs, de nombreux modules et bibliothèques sont disponibles, principalement pour java, perl et c++ mais aussi pour d'autres langages comme rexx, python, tcl...
Voici quelques adresses Web utiles pour retrouver ces logiciels :
xmlspy http:/www.xmlspy.com/ rxp http://www.cogsci.ed.ac.uk/~richard/rxp.html expat xmlwf http://expat.sourceforge.net/ libxml win http://www.zlatkovic.com/libxml.en.html libxml linux http://xmlsoft.org/ xmlsoft http://xmlsoft.org/ xmlsoftware http://www.xmlsoftware.com/ (on y trouve xmllint) xml parsers http://www.holoweb.net/~liam/xmldb/rg/ch21.html xml utilities http://www.hitsw.com/xml_utilites/ xmlstarlet http://xmlstar.sourceforge.net/ (outils en ligne de commande) ibm tools http://www-106.ibm.com/developerworks/xml/ xsleditor http://www.alphaworks.ibm.com/tech/xsleditor perl XML http://www.cpan.org/modules/by-module/XML/perl-xml-modules.html java XML http://java.sun.com/xml/faq.html java XMLJ http://www.cs.rpi.edu/~puninj/XMLJ/classes/class5/slide4-0.html java Xalan http://xml.apache.org/xalan-j/ java Xerces http://xml.apache.org/xerces-j/ tclxml http://tclxml.sourceforge.net/ rexx xml
http://www.interlog.com/~ptjm/
http://nestroy.wi-inf.uni-essen.de:8080/.../RexxExpat/
Remarque : les programmes présentés ci-dessous en perl, java et php notamment supposent que le lecteur et la lectrice connaissent à peu près ces langages, que les librairies sont installées, que les variables d'environnement correspondantes sont correctement positionnées, que les serveurs ont les "bons" modules etc.
En particulier, saxon ou xerces doivent avoir été installés pour que les bibliothéques standards puissent être utilisées.Il existe de nombreux sites et de nombreuses pages qui présentent des outils logiciels pour XML. En voici une sélection.
retour en haut de document
2. Tester qu'un document est bien formé
Vérifier qu'un fichier est bien formé, c'est tester qu'il suit la syntaxe générale de XML et en particulier tester que les balises sont bien ouvertes, bien fermées et bien imbriquées, qu'il n'y a qu'une balise principale qui engloble toutes les autres... Rappelons qu'ouvrir un fichier XML avec un navigateur récent comme Internet Explorer ou Firefox permet de voir si le document est bien formé mais ne permet pas d'intégrer cette vérification dans une chaine de traitement.
Nous allons donc réaliser cette vérification avec 2 logiciels (rxp et xmllint) et 2 langages (perl et java) pour le fichier dmf.xml qui justement n'est pas bien formé (car la balise nommée un n'est pas fermée) dont le contenu est
<un> essai </deux>
Avec rxp, on écrit
rxp dmf.xml
Avec xmllint, on écrit
xmllint dmf.xml
En perl, si on installe les modules XML dont notamment XML::Parser soit (entre autres) le fichier XML/Parser.pm, un programme minimal pour tester le fichier est
use XML::Parser; $nf = "dmf.xml" ; my $parser= new XML::Parser( Style => 'Stream'); eval {$parser->parsefile( $nf )}; if ($@) { die "\n Document mal formé : \n\t\t $@\n" ; } ; # si on arrive ici, c'est que tout va bien
Et son équivalent en java, si on a installé SAX
import java.io.* ; import org.xml.sax.* ; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; public class tsbf { // tsbf : Teste Si Bien Forme public static void main(String args[]) { String nf ; nf = "dmf.xml" ; DefaultHandler handler = new DefaultHandler(); SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser saxParser = factory.newSAXParser(); saxParser.parse( new File( nf ), handler ); } catch (Throwable t) { System.out.println(" Document mal formé :") ; t.printStackTrace (); } // suite du programme } // fin de la méthode main() } ; // fin de public class
Les messages d'erreurs fournis par les divers analyseurs sont similaires. Ainsi rxp répond
<un> essai Error: Mismatched end tag: expected </un>, got </deux> in unnamed entity at line 3 char 7 of file:///dmf.xml
alors que xmllint affiche
dmf.xml:3: error: Opening and ending tag mismatch: un and deux </deux>
Voici aussi le texte produit par le programme perl précédent pour le même fichier sous Windows
<un> Document mal formé : mismatched tag at line 3, column 2, byte 15 at C:/Perl/site/lib/XML/Parser.pm line 168
puis sous Linux
<un> Document mal formé : mismatched tag at line 3, column 2, byte 15 at /usr/lib/perl5/site_perl/5.6.1/i386-linux/XML/Parser.pm line 185
L'exécution du programme java fournit :
Document mal formé : org.xml.sax.SAXParseException: "</un>" prévu pour terminer l'élément qui commence à la ligne 1. at org.apache.crimson.parser.Parser2.fatal(Parser2.java:3182) at org.apache.crimson.parser.Parser2.fatal(Parser2.java:3176) at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1513) at org.apache.crimson.parser.Parser2.parseInternal(Parser2.java:500) at org.apache.crimson.parser.Parser2.parse(Parser2.java:305) at org.apache.crimson.parser.XMLReaderImpl.parse(XMLReaderImpl.java:442) at javax.xml.parsers.SAXParser.parse(SAXParser.java:345) at javax.xml.parsers.SAXParser.parse(SAXParser.java:281) at tsbf.main(tsbf.java:19)
L'outil en ligne de commandes nommé xmlstarlet permet aussi de tester si un document est bien formé :
$> xmlstarlet val -w dmf.xml dmf.xml - invalid $> xmlstarlet val -w -e dmf.xml dmf.xml:219.49: Opening and ending tag mismatch: NOM line 218 and ROLE <INTITULE>Mary Jensen Matthews</INTITULE></ROLE><ROLE><PRENOM>Mat</PRENOM><NOM>D ^ dmf.xml - invalidPour éviter de taper ces programmes, utilisez l'archive des programmes cités pour tester si un document est bien formé ; l'archive contient aussi des documents xml minimaux pour vérifier ces programmes.
retour en haut de document
3. Tester qu'un document est valide
Voici maintenant comment vérifier qu'un fichier est valide, c'est à dire que les balises sont conformes à la grammaire spécifiée. qu'on utilise uniquement que les balises définies, qu'elles correspondent en type, structure et en nombre à la grammaire fournie. Comme celle-ci est soit une DTD ou un Schéma il y a deux validations possibles : la validation par DTD et la validation par Schéma.
On suppose bien sur qu'au départ que le document est bien formé, grâce à la section précédente. Nous prendrons comme fichier d'exemple le texte suivant contenu dans dnv.xml
<id> <nom> BOND </nom> </id>
Inventons la grammaire suivante : la balise identité d'une personne se fait à l'aide de deux balises exactement : une balise nom et une balise prénom, toutes deux forcément présentes et dans cet ordre. Un fichier correct pour cette grammaire serait par exemple
<id> <nom> BOND </nom> <prenom> James </prenom> </id>
Il est clair que notre fichier exemple n'est pas valide car il est incomplet : il lui manque la balise prenom.
retour en haut de document
Validité pour une grammaire DTD avec rxp, xmllint, perl, java, xmlstarlet
Définissons la grammaire DTD par le fichier id.dtd dont le contenu est
<!ELEMENT id (nom,prenom) > <!ELEMENT nom (#PCDATA) > <!ELEMENT prenom (#PCDATA) >
et modifions le document initial pour qu'il fasse référence à cette DTD, soit le texte
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE id SYSTEM "id.dtd"> <id> <nom> BOND </nom> </id>
Pour tester la validité du document avec rxp, on écrit
rxp -V dnv.xml
et rxp retrouve de lui-même le fichier dtd associé au document. Il affiche alors le message d'erreur :
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE id SYSTEM "id.dtd"> <id> <nom> BOND </nom> Warning: Content model for id does not allow it to end here in unnamed entity at line 5 char 5 of file:///home/info/gh/Tmp/dnv.xml </id>
Avec xmllint pour tester la validité, on écrit
xmllint --valid dnv.xml ## avec externalisation : xmllint --dtdvalid id.dtd dnv.xml
et on récupère le message d'erreur :
dnv.xml:5: validity error: Element id content doesn't follow the Dtd Expecting (nom , prenom), got (nom) </id> ^ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE id SYSTEM "id.dtd"> <id> <nom> BOND </nom> </id>
La validation en perl se fait en rajoutant au programme précédent les instructions
{ # nouveau bloc - début de champ lexical ("scope") local local $XML::Checker::FAIL = &my_fail; my $parser2 = new XML::Checker::Parser(SkipExternalDTD => 1, ParseParamEnt => 1 ) ; $parser2 -> parsefile( $nf ) ; } # fin de bloc - le précédent gestionnaire d'échec ("fail") est rétabli # si on arrive ici, c'est que le document est valide print("\n\nLe document nommé $nf est valide pour sa dtd.\n") ; sub my_fail { my $code = shift; XML::Checker::print_error ($code, @_); print "\nLe document nommé $nf est non valide pour sa dtd.\n" ; exit(-2) ; } ; # fin de sous-programme my_fail
Et le message d'erreur associé est
XML::Checker ERROR-154: bad order of Elements Found=[nom] RE=[((nom)(prenom))] Context: line 5, column 0, byte 98 Le document nommé avecdtd_nonvalide.xml est non valide pour sa dtd.
Tester la validité se fait en java, utilise en gros avec les mêmes classes que précédemment, mais en rajoutant
factory.setValidating(true) ;soit le texte
import java.io.*; import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; public class tsv extends DefaultHandler { // teste si valide public static void main (String tab_args[]) throws IOException { String nf ; // test des paramètres if (tab_args.length != 1) { System.out.println(" syntaxe : testvj fichier") ; System.exit (-1); } ; // fin de test sur nombre de paramètres nf = tab_args[0] ; DefaultHandler handler = new tsv(); SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(true); try { SAXParser saxParser = factory.newSAXParser(); saxParser.parse( new File( nf ), handler ); } catch (SAXParseException e) { System.out.println("\n Le document nommé "+nf+" est invalide.") ; System.out.println(" Erreur détectée en ligne "+ e.getLineNumber() + ", uri " + e.getSystemId()); System.out.println(" " + e.getMessage() ); e.printStackTrace() ; if (e.getException() != null) e.getException().printStackTrace(); System.exit(-2); } catch (SAXException e) { if (e.getException() != null) e.getException().printStackTrace(); System.exit(-3); } catch (ParserConfigurationException e) { e.printStackTrace(); System.exit(-4); } catch (IOException e) { e.printStackTrace(); System.exit(-5); } System.out.println ("Le document nommé "+nf+" est bien formé et sa dtd est visible.") ; System.exit (0); } // fin de la méthode main() public void error(SAXParseException e) throws SAXParseException { throw e; } ; // fin de error } ; // fin de public class
et à l'exécution on obtient le message d'erreur
Le document nommé avecdtd_nonvalide.xml est invalide. Erreur détectée en ligne 5, uri file:/home/info/gh/Tmp/avecdtd_nonvalide.xml L'élément "{0}" nécessite des éléments additionnels. org.xml.sax.SAXParseException: L'élément "{0}" nécessite des éléments additionnels. at org.apache.crimson.parser.Parser2.error(Parser2.java:3354) at org.apache.crimson.parser.ValidatingParser$ChildrenValidator.done(ValidatingParser.java:361) at org.apache.crimson.parser.Parser2.maybeElement(Parser2.java:1703) at org.apache.crimson.parser.Parser2.parseInternal(Parser2.java:667) at org.apache.crimson.parser.Parser2.parse(Parser2.java:337) at org.apache.crimson.parser.XMLReaderImpl.parse(XMLReaderImpl.java:448) at javax.xml.parsers.SAXParser.parse(SAXParser.java:345) at javax.xml.parsers.SAXParser.parse(SAXParser.java:281) at tsv.main(tsv.java:34)
ou le message d'erreur
Le document nommé avecdtd_nonvalide.xml est invalide. Erreur détectée en ligne 5, uri file:/home/info/gh/Tmp/avecdtd_nonvalide.xml The content of element type "id" is incomplete, it must match "(nom,prenom)". org.xml.sax.SAXParseException: The content of element type "id" is incomplete, it must match "(nom,prenom)". at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source) at javax.xml.parsers.SAXParser.parse(SAXParser.java:345) at javax.xml.parsers.SAXParser.parse(SAXParser.java:281) at tsv.main(tsv.java:34)
suivant le parseur installé.
L'outil en ligne de commandes nommé xmlstarlet permet aussi de tester si un document est valide pour une DTD :
$> xmlstarlet val -d id.dtd -e dmf.xml dnv.xml:3.0: Element id content does not follow the DTD, expecting (nom , prenom), got (nom ) dnv.xml - invalidPour éviter de taper ces programmes, utilisez l'archive des programmes cités pour tester si un document est bien formé ; l'archive contient aussi des documents xml minimaux et une dtd pour vérifier ces programmes.
retour en haut de document
Validité pour un schéma XSD avec xmllint, perl, java et xmlstarlet seulement
Passons maintenant au schéma XSD : on écrit celui-ci dans le fichier id.xsd dont voici le texte
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="id"> <xsd:complexType> <xsd:sequence> <xsd:element name="nom" type="xs:string"/> <xsd:element name="prenom" type="xs:string"/> </xsd:sequence> </xsd:complexType> </xsd:element>
et on modifie le document de départ pour qu'il fasse référence à ce XSD, soit le contenu
<?xml version="1.0" encoding="UTF-8" ?> <id xsi:noNamespaceSchemaLocation="id.xsd"> <nom> BOND </nom> </id>
rxp ne connait pas les schémas, car à la suite de la commande
rxp -V dnv.xml
il répond
<?xml version="1.0" encoding="UTF-8"?> Warning: Document has no DTD, validating abandoned (detected at end of prolog of document file://dnv.xml) <id xsi:noNamespaceSchemaLocation="id.xsd"> <nom> BOND </nom> </id>
Pas de chance non plus avec xmllint car à la suite de la commande
xmllint --valid dnv.xml
on obtient le message d'erreur
dnv.xml:2: validity error: Validation failed: no DTD found ! <id xsi:noNamespaceSchemaLocation="id.xsd"> ^ dnv.xml:6: error: Premature end of data in tag <id xsi:noNamespaceSchemaLocation ^
Heureusement, la validation de schéma est définie par l'option --schema
$>xmllint --noout --schema id.xsd adv.xml adv.xml validates $>> xmllint --schema id.xsd dnv.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE id SYSTEM "id.dtd"> <id> <nom> BOND </nom> </id> dnv.xml:3: element id: Schemas validity error : Element 'id': Missing child element(s). Expected is ( prenom ). dnv.xml fails to validateIl ne nous reste donc que perl et java pour tester la validité d'un document XML connaissant son schéma.
La validation en java peut se faire avec le programme suivant
// se compile par // javac -classpath ~/Bin/Java_lib/xerces-2_6_2/xercesImpl.jar // :~/Bin/Java_lib/xerces-2_6_2/xml-apis.jar testevs.java // ou par (deneb) // javac -classpath /var/tomcat4/shared/lib/xercesImpl.jar ~/Bin/testevs.java import org.apache.xerces.parsers.SAXParser; import java.io.IOException; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; public class testevs { public void validateSchema(String SchemaUrl, String XmlDocumentUrl) { SAXParser parser = new SAXParser(); try { parser.setFeature("http://xml.org/sax/features/validation",true); parser.setFeature("http://apache.org/xml/features/validation/schema",true); parser.setFeature( "http://apache.org/xml/features/validation/schema-full-checking", true); parser.setProperty( "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", SchemaUrl ); Validator handler=new Validator(); parser.setErrorHandler(handler); parser.parse(XmlDocumentUrl); if (handler.validationError==true) System.out.println("Le document n'est pas valide pour le schéma fourni : " + handler.validationError + " " + handler.saxParseException.getMessage() ); else System.out.println("Le document est valide pour le schéma fourni."); } catch(java.io.IOException ioe) { System.out.println("Erreur de type IOException : "+ioe.getMessage()); } catch (SAXException e) { System.out.println("Erreur de type SAXException : "+e.getMessage()); } ; // fin de try } ; // fin de validateSchema private class Validator extends DefaultHandler { public boolean validationError = false; public SAXParseException saxParseException = null; public void error(SAXParseException exception) throws SAXException { validationError=true; saxParseException=exception; } ; // fin de error public void fatalError(SAXParseException exception) throws SAXException { validationError = true; saxParseException=exception; } ; // fin de fatalError public void warning(SAXParseException exception) throws SAXException {} } ; // fin de class Validator public static void main(String[] tab_args) { // test des paramètres if (tab_args.length != 2) { System.out.println(" syntaxe : testvsj fichier[.xml] schema[.xsd]") ; System.exit (-1); } ; // fin de test sur nombre de paramètres String XmlDocumentUrl = tab_args[0]; String SchemaUrl = tab_args[1]; testevs validator=new testevs(); validator.validateSchema(SchemaUrl, XmlDocumentUrl); } ; // fin de programme principal } ; // fin de public class testevs
Et le message d'erreur associé est
Le document n'est pas valide pour le schéma fourni : The content of element 'id' is not complete. It must match '(("":nom),("":prenom))'.
Ensuite, passons à perl. Le programme suivant est suffisant
# une copie locale de XML/Checker etc. est dans ~/Bin/Perl_lib use lib "/home/info/gh/Bin/Perl_Lib" ; use XML::Parser; use XML::SAX::ParserFactory; use XML::Validator::Schema; if (not($#ARGV==1)) { print "\n syntaxe : testevsp fichier[.xml] schema[.xsd] \n\n" ; exit(-1) ; } ; # fin de si $nf = $ARGV[0] ; $ns = $ARGV[1] ; # on vérifie que le fichier est bien formé my $parser = new XML::Parser( Style => 'Stream'); eval {$parser->parsefile( $nf )}; die " Le document $nf est mal formé : $@" if $@; # validation proprement dite $validator = XML::Validator::Schema->new(file => $ns ); $parser = XML::SAX::ParserFactory->parser(Handler => $validator); eval { $parser->parse_uri($nf) }; die "le document nommé $nf n'est pas valide pour sa dtd : $@" if $@; print "Le document $nf est valide pour sa dtd." ;
et son exécution aboutit à
Le document nommé avecxsd_nonvalide.xml n'est pas valide pour sa dtd : Contents of element 'id' do not match content model '(nom,prenom)'.
Enfin, terminons par xmlstarlet :
$> xmlstarlet val -s id.xsd -e adv.xml adv.xml - valid $> xmlstarlet val -s id.xsd -e dnv.xml dnv.xml:5.6: Element 'id': Missing child element(s). Expected is ( prenom ). dnv.xml - invalid
Pour éviter de taper ces programmes, utilisez l'archive des programmes cités pour tester si un document est valide ; l'archive contient aussi des documents xml et xsd minimaux pour vérifier ces programmes.
retour en haut de document
4. Comment transformer un fichier XML à l'aide d'un fichier XSL ?
Rappelons que si un document XML contient une indication de style généralisé, un navigateur récent comme Internet Explorer ou Firefox effectue la transformation à la volée en local après avoir reçu la "source" XML du document [ce qui n'est pas toujours souhaitable] et après avoir chargé la feuille de style qui joue donc le role d'un programme de traitement des données.
Un "processeur" nommé xsltproc permet aussi, sous Linux comme sous Windows, d'effectuer en ligne de commande ou en "batch" ces transformations.
Voici un programme Java qui répond au problème d'effectuer la transformation au niveau du serveur ou pour une application Web :
// exsl.java "exécute xsl" c'est à dire applique des transformations XSLT import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.w3c.dom.Document; import org.w3c.dom.DOMException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.*; public class exsl { // Exécute XSL public static void main (String tab_args []) { if (tab_args.length != 2){ System.err.println (); System.err.println (" syntaxe : exsl fichier_XML fichier_XSLT"); System.err.println (); System.exit (1); } ; // fin de test sur le nombre de paramètres String nFxml = tab_args[0] ; // nom du fichier XML à traiter String nFxsl = tab_args[1] ; // nom du fichier XSL à traiter DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new File( nFxml) ); TransformerFactory transformFactory = TransformerFactory.newInstance(); StreamSource styleSource = new StreamSource(new File( nFxsl) ); Transformer transform = transformFactory.newTransformer(styleSource); DOMSource doc_in = new DOMSource(doc); StreamResult doc_out = new StreamResult(System.out); transform.transform(doc_in, doc_out); } catch (TransformerConfigurationException e) { System.out.println (" Erreur en usinage de transformation (!) : "); System.out.println(" " + e.getMessage() ); Throwable x = e; if (e.getException() != null) x = e.getException(); x.printStackTrace(); } catch (TransformerException e) { System.out.println ("Erreur de transformation : "); System.out.println(" " + e.getMessage() ); Throwable x = e; if (e.getException() != null) x = e.getException(); x.printStackTrace(); } catch (SAXException e) { Exception x = e; if (e.getException() != null) x = e.getException(); x.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } ; // fin de main } ; // fin de classe exsl
Voici comment l'utiliser : on l'exécute en ligne de commande en lui passant dans cet ordre le nom du fichier XML à traiter et le nom du fichier de transformation XSL à utiliser. Un troisième paramètre facultatif permet d'enregistrer dans un fichier les sorties du programme.
Par exemple, si on exécute
java -classpath ... exsl elf_data.xml xml2dat.xsl
où le fichier de données elf_data.xml contient
<?xml version='1.0' ?> <!-- # elfdix.xml issu de dar2xml.rex ; le 01/12/04 vers 12:30:03 --> <!DOCTYPE DOSSIER SYSTEM "statdata.dtd"> <DOSSIER> <DSC> <NOM> elfdix </NOM> <LDSC> Enquete noms de metier </LDSC> <NATURE> PERSONNEL </NATURE> <DATE> 1989 </DATE> </DSC> <NOMSCOL> IDEN SEXE AGE PROF ETUD REGI USAL </NOMSCOL> <LIGNEDATA> M001 1 62 1 2 2 3 </LIGNEDATA> <LIGNEDATA> M002 0 60 9 3 4 1 </LIGNEDATA> <LIGNEDATA> M003 1 31 9 4 4 1 </LIGNEDATA> <LIGNEDATA> M004 1 27 8 4 1 1 </LIGNEDATA> <LIGNEDATA> M005 0 22 8 4 1 2 </LIGNEDATA> <LIGNEDATA> M006 1 70 4 1 1 1 </LIGNEDATA> <LIGNEDATA> M007 1 19 8 4 4 2 </LIGNEDATA> <LIGNEDATA> M008 1 53 6 2 2 3 </LIGNEDATA> <LIGNEDATA> M009 0 62 16 4 2 2 </LIGNEDATA> </DOSSIER>
et où le fichier de transformation xml2dat.xsl contient
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- xml2dat.xsl n'affiche que les données --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="ISO-8859-1" /> <xsl:variable name="sautdeLigne"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:apply-templates select="//LIGNEDATA" /> </xsl:template> <xsl:template match="LIGNEDATA"> <xsl:value-of select="concat( substring-after(substring-after(.,' '),' '), $sautdeLigne)" /> </xsl:template> </xsl:stylesheet>
alors on ne voit à l'écran le texte sans balise ni autre information que les lignes de données :
M001 1 62 1 2 2 3 M002 0 60 9 3 4 1 M003 1 31 9 4 4 1 M004 1 27 8 4 1 1 M005 0 22 8 4 1 2 M006 1 70 4 1 1 1 M007 1 19 8 4 4 2 M008 1 53 6 2 2 3 M009 0 62 16 4 2 2
Remarque : notre programme permet d'écrire directement dans un fichier de sortie grace au troisième paramètre. Ainsi la commande
java -classpath ... exsl elf_data.xml xml2dat.xsl elf.dat
met dans le fichier elf.dat ce qui était auparavant vu à l'écran.
L'équivalent Perl pour mener à bien la transformation au niveau serveur se résume à :
use XML::XSLT; # il faut le bon nombre de fichiers if ($#ARGV <1) { print "\n\n syntaxe : perl_xsl fichier.xml fichier.xsl\n\n" ; exit(-1) ; } ; # fin de si # préparation des noms de variable my $xmlf = $ARGV[0] ; my $xslf = $ARGV[1] ; # préparation du traitement my $xslt = XML::XSLT->new ($xslf); # exécution de la transformation (en mémoire) $xlst->transform($xmlf); # affichage du résultat de la transformation print $xlst->toString(); # libération éventuelle de la mémoire avec : $xslt->dispose() ;
Php étant très similaire à Perl, pour mener à bien la transformation au niveau serveur on peut écrire en Php 4.1 avec sablotron :
# ouverture du fichier Xml # et transfert dans une variable $nomXml = "test3.xml"; $ficXml = fopen($nomXml,"r"); $lngXml = filesize($ficXml); $strXml = fread($ficXml, $lngXml); # ouverture du fichier Xsl # et transfert dans une variable $nomXsl = "test3.xsl"; $ficXsl = fopen($ficXsl,"r"); $lngXsl = filesize($ficXsl); $strXsl = fread($ficXsl, $lngXsl); # on essaie de transformer if( xslt_process ( $strXsl, $strXml, $xsltRes)) { # et si tout va bien, on affiche print $xsltRest; } else { print "Il y a une erreur au cours de la transformation " ; } ; # fin de si
Avec PHP5 et la classe XSLTProcessor on écrira plutot :
// Nouvelle instance du processeur $xslt = new XSLTProcessor(); // Chargement du fichier XML $xml = new domDocument(); $xml -> load('test3.xml'); // Chargement du fichier XSL $xsl = new domDocument(); $xsl -> load('test3.xsl'); // Import de la feuille XSL $xslt -> importStylesheet($xsl); // Transformation et affichage du résultat echo $xslt -> transformToXml($xml);
A moins que vous préfériez la version plus courte orientée objets :
$nomXml = "test3.xml"; $nomXsl = "test3.xsl"; $xsl = new XSLTProcessor(); $xsl->importStyleSheet(DOMDocument::load($nomXsl)); echo $xsl->transformToXML(DOMDocument::load($nomXml));
En ligne de commandes, xmlstarlet est capable d'effectuer une transformation XSL, comme xsltproc. Voici des exemples de telles commandes :
$> xsltproc test3.xsl test3.xml $> xmlstarlet tr test3.xsl test3.xml
Si vous vous intéressez aux langages Python et Ruby, vous trouverez dans notre tuteur Python et dans notre tuteur Ruby comment lire des fichiers XML et réaliser des transformations XSL avec ces langages. Pour PHP, des exemples de traitement de fichiers XML sont ici.
Pour éviter de taper ces programmes, utilisez l'archive ; elle contient aussi des documents xml, dtd et xsl minimaux pour l'utiliser.
5. Archives de programmes pour Windows
outilsXml.zip : utilitaires pour Windows (rxp,xmllint...)
XML_lib_Perl.zip : librairie Perl Minimale pour XML Checker et Parser
testevj.zip : fichiers java avec commandes locales de compilation et .jar
xlstproc_win.zip exe et dll pour effectuer des transformations XSL
fop_jars.zip fop, pour passer de XML à PDF, PS etc.
retour en haut de document