Tuteur pour le langage XML (partie 3 / 3)

Valid XHTML 1.0!                  

Texte du Tuteur écrit par Gilles HUNAULT

Liste des autres tuteurs (langages, logiciels, systèmes d'exploitations...)

 


 

Dans ce document :

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    retour à la table des matières principales

 


 

1. 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 haut    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 - invalid

Pour é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 haut    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 haut    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 - invalid

Pour é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 haut    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 validate


Il 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 haut    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 haut    retour en haut de document
   retour    retour à la table des matières principales