• S'inscrire
  • Affichage des résultats 1 à 3 sur 3

    Discussion: Cours Java - Lecture d'un flux XML via SAX

    1. #1
      x_octet
      Guest

      Par défaut Cours Java - Lecture d'un flux XML via SAX

      Introduction

      Je vous présente dans cet article un rapide cours d'introduction à SAX et un exemple d'implémentation d'une lecture d'un flux XML dans cette API SAX en java.Si le prérequis XML ne fait pas encore partie de votre bagage, n'hésitez pas à rendre visite à la section XML de developpez.com. Il n'y aura pas de découverte fantastique cette fois, ce tutoriel ayant pour but de présenter l'API SAX qui sert en particulier pour l'article sur le design pattern du GOF : le monteur. Cet article est donc la partie technique et pure java de la série du cours débutée avec le monteur :

      Présentation de SAX
      Simple API for XML ou SAX est une API générale pour la lecture d'un flux XML. Il existe des implémentations de cette API dans tous les langages que vous connaissez probablement (en tout cas l'implémentation existe pour C++, C#, Java, Pascal, perl, PHP, ...) car XML s'est largement imposé aujourd'hui dans le monde du logiciel pour l'échange d'informations. Il existe deux grandes API pour relire les flux XML : DOM et SAX. SAX est événementielle (nous allons la découvrir en détails) alors que DOM transforme l'arborescence XML en arborescence du langage cible. L'intérêt majeur de DOM est donc la possibilité qu'il offre d'aller et venir à votre gré dans l'arborescence, son inconvénient majeur reste la lourdeur du traitement. En effet, SAX étant événementiel, son traitement se fait au fil du flux entrant.

      Je disais donc que SAX est événementiel, ce qui signifie qu'il existerait des événements dans un fichier XML !? Et bien, si l'on considère le flux XML entrant, il devient plus facile de découvrir les événements : une balise ouvrante est un événement, une balise fermante un autre événement... Voilà pour tout dire l'essentiel de cette API, d'où son nom Simple API for XML, une fois que vous savez répondre à ces deux événements, vous pouvez déjà traiter un flux XML donc utiliser un fichier de configuration XML. C'est étonnamment simple, et finalement extrêmement puissant comme nous allons le découvrir.Quand vous aurez découvert cette API, il est probable que vous choisissiez de remplacer tous vos fichiers de propriétés de type paire clef/valeur par un fichier XML et une relecture SAX. L'avantage d'une configuration XML est son aptitude contextuelle, laquelle est difficile à représenter dans un fichier de propriétés. En effet sous la forme de paires nom/valeur , la notion contextuelle est généralement mal représentée par des clefs ayant une forme de chemin (mon.chemin.vers.ma.propriété).

      Nous étudierons, un peu plus en détails, cette API qui est un peu plus compliquée que je ne l'ai présentée pour le moment, en particulier parce qu'elle réagit à beaucoup plus que les simples événements d'ouverture et de fermeture de balises. Nous trouverons en particulier des événements pour l'ouverture et la fermeture du document xml, des événements pour l'ouverture et la fermeture de meta informations.
      Découverte de l'API
      ContentHandler

      Voyons pour commencer comment nous allons pouvoir réagir à ces fameux événements SAX générés par le parser. Pour ce faire, il nous suffira en fait d'implémenter l'interface ContentHandler qui se trouve dans le package org.xml.sax, puis d'instancier le parser en lui indiquant quel gestionnaire de contenu il devra utiliser (c'est à dire le notre) et le tour sera quasiment joué. Voici donc présenté un aperçu de l'interface centrale de vos développements SAX : le ContentHandler ou gestionnaire de Contenu. Ce gestionnaire est en effet celui qui fait le véritable travail d'analyse tandis que les autres interfaces de l'API font des travaux satellites comme gérer les erreurs, repérer le "curseur" dans le flux pendant l'analyse. Ces interfaces satellites ne sont pas à négliger mais ont un rôle moins central dans votre développement.
      setDocumentLocator

      Un locator vous permet de localiser "le curseur" pendant le traitement du flux vous permettant par exemple de connaître le numéro de ligne et de colonne en cours d'analyse. Ceci est une fonctionnalité certes très intéressante au moment du débugage mais qu'il faut à tout prix éviter, que dis-je, vous interdire d'utiliser pour le traitement proprement dit. Dans les Helper de l'API sax, il vous est fournit une implémentation par défaut de toutes les interfaces. Si l'implémentation par défaut du ContentHandler est proprement inutile, celle du Locator devrait amplement suffire à 99% des développements, je ne m'étendrai donc pas sur ce point.
      startDocument

      Cette méthode est appelée par le parser une et une seule fois au démarrage de l'analyse de votre flux xml. Elle est appelée avant toutes les autres méthodes de l'interface, à l'exception unique, évidemment, de la méthode setDocumentLocator. Cet événement devrait vous permettre d'initialiser tout ce qui doit l'être avant le début du parcours du document.
      endDocument

      Et son contraire, cette méthode est donc appelée à la fin du parcours du flux après toutes les autres méthodes. Il peut alors être utile à ce moment de notifier d'autres objets du fait que le travail est terminé.
      processingInstruction

      Cet événement est levé pour chaque instruction de fonctionnement rencontrée. Ces instructions sont celles que vous trouvez hors de l'arbre xml lui-même comme par exemple les instructions concernant les dtd ou plus simplement la déclaration :

      Code:
      <?xml version="1.0" encoding="ISO-8859-1" ?>
      startPrefixMapping

      Cet événement est lancé à chaque fois qu'un mapping préfixé, c'est à dire une balise située dans un espace de nommage (name space) , est rencontré.
      endPrefixMapping

      Son événement contraire évidemment, c'est à dire la fin du traitement dans un espace de nommage.
      startElement

      Démarrage d'un élément XML... Enfin ! Et oui, on peut en effet pour démarrer avec SAX se contenter de comprendre cet événement et son traitement ainsi que son contraire pour analyser un flux xml de manière très puissante et efficace. Nous allons donc nous pencher un peu plus sur cet événement.

      startElement (String namespaceUri, String localName, String rawName, Attributs atts);

      * où nameSpaceUri est la chaîne de caractères contenant l'URI complète de l'espace de nommage du tag ou une chaîne vide si le tag n'est pas compris dans un espace de nommage,
      * localName est le nom du tag sans le préfixe s'il y en avait un,
      * rawName est le nom du tag version xml 1.0 c'est à dire $prefix:$localname,
      * Enfin attributs est la liste des attributs du tag que l'on étudiera un peu plus loin.

      endElement

      Evénement inverse de signature beaucoup plus simple puisque seul le nom complet du tag a besoin d'être connu. En effet, à la fermeture de la balise XML, aucun attribut n'est requis.
      characters

      Tout ce qui est dans l'arborescence mais n'est pas partie intégrante d'un tag, déclenche la levée de cet événement. En général, cet événement est donc levé tout simplement par la présence de texte entre la balise d'ouverture et la balise de fermeture comme dans l'exemple suivant:

      Code:
      <maBalise>un peu de texte</maBalise>
      La présence de "un peu de texte" provoque la levée de l'événement characters. Attention : il est à noter que l'API SAX n'impose rien quant à pas l'implémentation de cet événement. Dans le cas d'un texte épars autour de balises filles de la balise en cours, les réactions peuvent être diverses. Ainsi le flux xml suivant :
      Code:
      <maBalise>un peu
          <baliseImbriquee nom="coucou"/> de texte<baliseImbriquee nom="toto"/>éparpillé
      </maBalise>
      Il peut soit donner lieu à trois événements contenant respectivement le texte "un peu", " de texte", "éparpillé" soit donner un seul événement contenant l'intégralité du texte à savoir "un peu de texte éparpillé". Comme l'API ne fixe rien, ce sera à vous de penser au fait que le parser que vous avez sous la main ne sera peut être pas celui de vos clients et d'agir en conséquence, c'est à dire en gérant les deux types de réactions possibles de telle sorte qu'elles fournissent le même comportement final dans les deux cas.
      ignorableWhiteSpace

      Permet de traiter les espaces et tabulations multiples, sachant qu'ils n'ont normalement aucune valeur en xml. Un ou deux ou 10 espaces, 1 espace et une tabulation et 3 retours chariot, etc sont autant d'espaces normalement ignorés en XML. Cet événement est donc levé à chaque fois que des espaces normalement ignorés sont rencontrés. En fait les paramètres de la méthode contiennent la chaîne complète de characters et les index de début et de fin de la série d'espaces ignorables. A vous de voir si vous voulez outrepasser la préconisation qui considère ces espaces comme étant inutiles.
      skippedEntity

      Evitez d'y toucher, cette méthode est levée à chaque fois qu'une entité (une balise et toute l'arborescence descendante) est ignorée. Elle le sera si vous avez demandé au parser de ne pas valider le document et que la balise en question est mal formée. Bref, vous faites face à une situation dangeureuse pour votre application, soit vous décidez alors de partir sur des valeurs par défaut, soit, et c'est en général le mieux, vous interrompez le traitement pour défaut dans l'environnement.
      Implémentation du ContentHandler

      Voyons à présent une petite implémentation rapide du ContentHandler qui reste l'interface centrale à implémenter pour analyser un flux XML à l'aide de SAX. Comme toujours, je vous donne une implémentation en java qui normalement est facilement adaptable aux divers langages que vous utilisez. Notre classe d'implémentation du ContentHandler se contentera donc d'analyser un document et de prouver qu'il le fait bien en exprimant sur la sortie standard (System.out.println() pour les non javayeurs) ce qu'il est en train de faire. Je focalise votre attention sur le démarrage de la lecture du flux, la lecture d'entités simples ou d'entités faisant partie d'un espace de nommage. En effet, le reste devient trivial une fois que les bases ont été comprises.
      Code:
      /*
       * Created on 2 nov. 03
       *
       * To change the template for this generated file go to
       * Window>Preferences>Java>Code Generation>Code and Comments
       */
      package com.developpez.smeric.xml.sax;
      
      import org.xml.sax.*;
      import org.xml.sax.helpers.LocatorImpl;
      
      /**
       * @author smeric
       *
       * Exemple d'implementation extremement simplifiee d'un SAX XML ContentHandler. Le but de cet exemple
       * est purement pedagogique.
       * Very simple implementation sample for XML SAX ContentHandler.
       */
      public class SimpleContentHandler implements ContentHandler &#123;
      
              /**
               * Constructeur par defaut. 
               */
              public SimpleContentHandler&#40;&#41; &#123;
                      super&#40;&#41;;
                      // On definit le locator par defaut.
                      locator = new LocatorImpl&#40;&#41;;
              &#125;
      
              /**
               * Definition du locator qui permet a tout moment pendant l'analyse, de localiser
               * le traitement dans le flux. Le locator par defaut indique, par exemple, le numero
               * de ligne et le numero de caractere sur la ligne.
               * @author smeric
               * @param value le locator a utiliser.
               * @see org.xml.sax.ContentHandler#setDocumentLocator&#40;org.xml.sax.Locator&#41;
               */
              public void setDocumentLocator&#40;Locator value&#41; &#123;
                      locator =  value;
              &#125;
      
              /**
               * Evenement envoye au demarrage du parse du flux xml.
               * @throws SAXException en cas de probleme quelquonque ne permettant pas de
               * se lancer dans l'analyse du document.
               * @see org.xml.sax.ContentHandler#startDocument&#40;&#41;
               */
              public void startDocument&#40;&#41; throws SAXException &#123;
                      System.out.println&#40;"Debut de l'analyse du document"&#41;;
              &#125;
      
              /**
               * Evenement envoye a la fin de l'analyse du flux xml.
               * @throws SAXException en cas de probleme quelquonque ne permettant pas de
               * considerer l'analyse du document comme etant complete.
               * @see org.xml.sax.ContentHandler#endDocument&#40;&#41;
               */
              public void endDocument&#40;&#41; throws SAXException &#123;
                      System.out.println&#40;"Fin de l'analyse du document" &#41;;
              &#125;
      
              /**
               * Debut de traitement dans un espace de nommage.
               * @param prefixe utilise pour cet espace de nommage dans cette partie de l'arborescence.
               * @param URI de l'espace de nommage.
               * @see org.xml.sax.ContentHandler#startPrefixMapping&#40;java.lang.String, java.lang.String&#41;
               */
              public void startPrefixMapping&#40;String prefix, String URI&#41; throws SAXException &#123;
                      System.out.println&#40;"Traitement de l'espace de nommage &#58; " + URI + ", prefixe choisi &#58; " + prefix&#41;;
              &#125;
      
              /**
               * Fin de traitement de l'espace de nommage.
               * @param prefixe le prefixe choisi a l'ouverture du traitement de l'espace nommage.
               * @see org.xml.sax.ContentHandler#endPrefixMapping&#40;java.lang.String&#41;
               */
              public void endPrefixMapping&#40;String prefix&#41; throws SAXException &#123;
                      System.out.println&#40;"Fin de traitement de l'espace de nommage &#58; " + prefix&#41;;
              &#125;
      
              /**
               * Evenement recu a chaque fois que l'analyseur rencontre une balise xml ouvrante.
               * @param nameSpaceURI l'url de l'espace de nommage.
               * @param localName le nom local de la balise.
               * @param rawName nom de la balise en version 1.0 <code>nameSpaceURI + "&#58;" + localName</code>
               * @throws SAXException si la balise ne correspond pas a ce qui est attendu,
               * comme par exemple non respect d'une dtd.
               * @see org.xml.sax.ContentHandler#startElement&#40;java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes&#41;
               */
              public void startElement&#40;String nameSpaceURI, String localName, String rawName, Attributes attributs&#41; throws SAXException &#123;
                      System.out.println&#40;"Ouverture de la balise &#58; " + localName&#41;;
      
                      if &#40; ! "".equals&#40;nameSpaceURI&#41;&#41; &#123; // espace de nommage particulier
                              System.out.println&#40;"  appartenant a l'espace de nom &#58; "  + nameSpaceURI&#41;;
                      &#125;
      
                      System.out.println&#40;"  Attributs de la balise &#58; "&#41;;
      
                      for &#40;int index = 0; index < attributs.getLength&#40;&#41;; index++&#41; &#123; // on parcourt la liste des attributs
                              System.out.println&#40;"     - " +  attributs.getLocalName&#40;index&#41; + " = " + attributs.getValue&#40;index&#41;&#41;;
                      &#125;
              &#125;
      
              /**
               * Evenement recu a chaque fermeture de balise.
               * @see org.xml.sax.ContentHandler#endElement&#40;java.lang.String, java.lang.String, java.lang.String&#41;
               */
              public void endElement&#40;String nameSpaceURI, String localName, String rawName&#41; throws SAXException &#123;
                      System.out.print&#40;"Fermeture de la balise &#58; " + localName&#41;;
      
                      if &#40; ! "".equals&#40;nameSpaceURI&#41;&#41; &#123; // name space non null
                              System.out.print&#40;"appartenant a l'espace de nommage &#58; " + localName&#41;;
                      &#125;
      
                      System.out.println&#40;&#41;;
              &#125;
      
              /**
               * Evenement recu a chaque fois que l'analyseur rencontre des caracteres &#40;entre
               * deux balises&#41;.
               * @param ch les caracteres proprement dits.
               * @param start le rang du premier caractere a traiter effectivement.
               * @param end le rang du dernier caractere a traiter effectivement
               * @see org.xml.sax.ContentHandler#characters&#40;char&#91;&#93;, int, int&#41;
               */
              public void characters&#40;char&#91;&#93; ch, int start, int end&#41; throws SAXException &#123;
                      System.out.println&#40;"#PCDATA &#58; " + new String&#40;ch, start, end&#41;&#41;;
              &#125;
      
              /**
               * Recu chaque fois que des caracteres d'espacement peuvent etre ignores au sens de
               * XML. C'est a dire que cet evenement est envoye pour plusieurs espaces se succedant,
               * les tabulations, et les retours chariot se succedants ainsi que toute combinaison de ces
               * trois types d'occurrence.
               * @param ch les caracteres proprement dits.
               * @param start le rang du premier caractere a traiter effectivement.
               * @param end le rang du dernier caractere a traiter effectivement
               * @see org.xml.sax.ContentHandler#ignorableWhitespace&#40;char&#91;&#93;, int, int&#41;
               */
              public void ignorableWhitespace&#40;char&#91;&#93; ch, int start, int end&#41; throws SAXException &#123;
                      System.out.println&#40;"espaces inutiles rencontres &#58; ..." + new String&#40;ch, start, end&#41; +  "..."&#41;;
              &#125;
      
              /**
               * Rencontre une instruction de fonctionnement.
               * @param target la cible de l'instruction de fonctionnement.
               * @param data les valeurs associees a cette cible. En general, elle se presente sous la forme 
               * d'une serie de paires nom/valeur.
               * @see org.xml.sax.ContentHandler#processingInstruction&#40;java.lang.String, java.lang.String&#41;
               */
              public void processingInstruction&#40;String target, String data&#41; throws SAXException &#123;
                      System.out.println&#40;"Instruction de fonctionnement &#58; " + target&#41;;
                      System.out.println&#40;"  dont les arguments sont &#58; " + data&#41;;
              &#125;
      
              /**
               * Recu a chaque fois qu'une balise est evitee dans le traitement a cause d'un
               * probleme non bloque par le parser. Pour ma part je ne pense pas que vous
               * en ayez besoin dans vos traitements.
               * @see org.xml.sax.ContentHandler#skippedEntity&#40;java.lang.String&#41;
               */
              public void skippedEntity&#40;String arg0&#41; throws SAXException &#123;
                      // Je ne fais rien, ce qui se passe n'est pas franchement normal.
                      // Pour eviter cet evenement, le mieux est quand meme de specifier une dtd pour vos
                      // documents xml et de les faire valider par votre parser.              
              &#125;
      
              private Locator locator;
      
      &#125;

      Cours Java - Lecture d'un flux XML via SAX


      Introduction

      Je vous présente dans cet article un rapide cours d'introduction à SAX et un exemple d'implémentation d'une lecture d'un flux XML dans cette API SAX en java.Si le prérequis XML ne fait pas encore partie de votre bagage, n'hésitez pas à rendre visite à la section XML de developpez.com. Il n'y aura pas de découverte fantastique cette fois, ce tutoriel ayant pour but de présenter l'API SAX qui sert en particulier pour l'article sur le design pattern du GOF : le monteur. Cet article est donc la partie technique et pure java de la série du cours débutée avec le monteur :
      Cet article fait partie de la série :
      monteur construction d'une structure complexe indépendamment de son implémentation
      ioc Inversion of control laissez votre environnement objet interagir avec vos objets
      sax Relire un fichier xml avec l'API SAX
      implémentation Implémentation, exemples
      Présentation de SAX

      Simple API for XML ou SAX est une API générale pour la lecture d'un flux XML. Il existe des implémentations de cette API dans tous les langages que vous connaissez probablement (en tout cas l'implémentation existe pour C++, C#, Java, Pascal, perl, PHP, ...) car XML s'est largement imposé aujourd'hui dans le monde du logiciel pour l'échange d'informations. Il existe deux grandes API pour relire les flux XML : DOM et SAX. SAX est événementielle (nous allons la découvrir en détails) alors que DOM transforme l'arborescence XML en arborescence du langage cible. L'intérêt majeur de DOM est donc la possibilité qu'il offre d'aller et venir à votre gré dans l'arborescence, son inconvénient majeur reste la lourdeur du traitement. En effet, SAX étant événementiel, son traitement se fait au fil du flux entrant.

      Je disais donc que SAX est événementiel, ce qui signifie qu'il existerait des événements dans un fichier XML !? Et bien, si l'on considère le flux XML entrant, il devient plus facile de découvrir les événements : une balise ouvrante est un événement, une balise fermante un autre événement... Voilà pour tout dire l'essentiel de cette API, d'où son nom Simple API for XML, une fois que vous savez répondre à ces deux événements, vous pouvez déjà traiter un flux XML donc utiliser un fichier de configuration XML. C'est étonnamment simple, et finalement extrêmement puissant comme nous allons le découvrir.Quand vous aurez découvert cette API, il est probable que vous choisissiez de remplacer tous vos fichiers de propriétés de type paire clef/valeur par un fichier XML et une relecture SAX. L'avantage d'une configuration XML est son aptitude contextuelle, laquelle est difficile à représenter dans un fichier de propriétés. En effet sous la forme de paires nom/valeur , la notion contextuelle est généralement mal représentée par des clefs ayant une forme de chemin (mon.chemin.vers.ma.propriété).

      Nous étudierons, un peu plus en détails, cette API qui est un peu plus compliquée que je ne l'ai présentée pour le moment, en particulier parce qu'elle réagit à beaucoup plus que les simples événements d'ouverture et de fermeture de balises. Nous trouverons en particulier des événements pour l'ouverture et la fermeture du document xml, des événements pour l'ouverture et la fermeture de meta informations.
      Découverte de l'API
      ContentHandler

      Voyons pour commencer comment nous allons pouvoir réagir à ces fameux événements SAX générés par le parser. Pour ce faire, il nous suffira en fait d'implémenter l'interface ContentHandler qui se trouve dans le package org.xml.sax, puis d'instancier le parser en lui indiquant quel gestionnaire de contenu il devra utiliser (c'est à dire le notre) et le tour sera quasiment joué. Voici donc présenté un aperçu de l'interface centrale de vos développements SAX : le ContentHandler ou gestionnaire de Contenu. Ce gestionnaire est en effet celui qui fait le véritable travail d'analyse tandis que les autres interfaces de l'API font des travaux satellites comme gérer les erreurs, repérer le "curseur" dans le flux pendant l'analyse. Ces interfaces satellites ne sont pas à négliger mais ont un rôle moins central dans votre développement.
      setDocumentLocator

      Un locator vous permet de localiser "le curseur" pendant le traitement du flux vous permettant par exemple de connaître le numéro de ligne et de colonne en cours d'analyse. Ceci est une fonctionnalité certes très intéressante au moment du débugage mais qu'il faut à tout prix éviter, que dis-je, vous interdire d'utiliser pour le traitement proprement dit. Dans les Helper de l'API sax, il vous est fournit une implémentation par défaut de toutes les interfaces. Si l'implémentation par défaut du ContentHandler est proprement inutile, celle du Locator devrait amplement suffire à 99% des développements, je ne m'étendrai donc pas sur ce point.
      startDocument

      Cette méthode est appelée par le parser une et une seule fois au démarrage de l'analyse de votre flux xml. Elle est appelée avant toutes les autres méthodes de l'interface, à l'exception unique, évidemment, de la méthode setDocumentLocator. Cet événement devrait vous permettre d'initialiser tout ce qui doit l'être avant le début du parcours du document.
      endDocument

      Et son contraire, cette méthode est donc appelée à la fin du parcours du flux après toutes les autres méthodes. Il peut alors être utile à ce moment de notifier d'autres objets du fait que le travail est terminé.
      processingInstruction

      Cet événement est levé pour chaque instruction de fonctionnement rencontrée. Ces instructions sont celles que vous trouvez hors de l'arbre xml lui-même comme par exemple les instructions concernant les dtd ou plus simplement la déclaration :

      Code:
      <?xml version="1.0" encoding="ISO-8859-1" ?>
      startPrefixMapping

      Cet événement est lancé à chaque fois qu'un mapping préfixé, c'est à dire une balise située dans un espace de nommage (name space) , est rencontré.
      endPrefixMapping

      Son événement contraire évidemment, c'est à dire la fin du traitement dans un espace de nommage.
      startElement

      Démarrage d'un élément XML... Enfin ! Et oui, on peut en effet pour démarrer avec SAX se contenter de comprendre cet événement et son traitement ainsi que son contraire pour analyser un flux xml de manière très puissante et efficace. Nous allons donc nous pencher un peu plus sur cet événement.

      startElement (String namespaceUri, String localName, String rawName, Attributs atts);

      * où nameSpaceUri est la chaîne de caractères contenant l'URI complète de l'espace de nommage du tag ou une chaîne vide si le tag n'est pas compris dans un espace de nommage,
      * localName est le nom du tag sans le préfixe s'il y en avait un,
      * rawName est le nom du tag version xml 1.0 c'est à dire $prefix:$localname,
      * Enfin attributs est la liste des attributs du tag que l'on étudiera un peu plus loin.

      endElement

      Evénement inverse de signature beaucoup plus simple puisque seul le nom complet du tag a besoin d'être connu. En effet, à la fermeture de la balise XML, aucun attribut n'est requis.
      characters

      Tout ce qui est dans l'arborescence mais n'est pas partie intégrante d'un tag, déclenche la levée de cet événement. En général, cet événement est donc levé tout simplement par la présence de texte entre la balise d'ouverture et la balise de fermeture comme dans l'exemple suivant:

      <maBalise>un peu de texte</maBalise>

      La présence de "un peu de texte" provoque la levée de l'événement characters. Attention : il est à noter que l'API SAX n'impose rien quant à pas l'implémentation de cet événement. Dans le cas d'un texte épars autour de balises filles de la balise en cours, les réactions peuvent être diverses. Ainsi le flux xml suivant :

      Code:
      <maBalise>un peu
          <baliseImbriquee nom="coucou"/> de texte<baliseImbriquee nom="toto"/>éparpillé
      </maBalise>
      Il peut soit donner lieu à trois événements contenant respectivement le texte "un peu", " de texte", "éparpillé" soit donner un seul événement contenant l'intégralité du texte à savoir "un peu de texte éparpillé". Comme l'API ne fixe rien, ce sera à vous de penser au fait que le parser que vous avez sous la main ne sera peut être pas celui de vos clients et d'agir en conséquence, c'est à dire en gérant les deux types de réactions possibles de telle sorte qu'elles fournissent le même comportement final dans les deux cas.
      ignorableWhiteSpace

      Permet de traiter les espaces et tabulations multiples, sachant qu'ils n'ont normalement aucune valeur en xml. Un ou deux ou 10 espaces, 1 espace et une tabulation et 3 retours chariot, etc sont autant d'espaces normalement ignorés en XML. Cet événement est donc levé à chaque fois que des espaces normalement ignorés sont rencontrés. En fait les paramètres de la méthode contiennent la chaîne complète de characters et les index de début et de fin de la série d'espaces ignorables. A vous de voir si vous voulez outrepasser la préconisation qui considère ces espaces comme étant inutiles.
      skippedEntity

      Evitez d'y toucher, cette méthode est levée à chaque fois qu'une entité (une balise et toute l'arborescence descendante) est ignorée. Elle le sera si vous avez demandé au parser de ne pas valider le document et que la balise en question est mal formée. Bref, vous faites face à une situation dangeureuse pour votre application, soit vous décidez alors de partir sur des valeurs par défaut, soit, et c'est en général le mieux, vous interrompez le traitement pour défaut dans l'environnement.
      Implémentation du ContentHandler

      Voyons à présent une petite implémentation rapide du ContentHandler qui reste l'interface centrale à implémenter pour analyser un flux XML à l'aide de SAX. Comme toujours, je vous donne une implémentation en java qui normalement est facilement adaptable aux divers langages que vous utilisez. Notre classe d'implémentation du ContentHandler se contentera donc d'analyser un document et de prouver qu'il le fait bien en exprimant sur la sortie standard (System.out.println() pour les non javayeurs) ce qu'il est en train de faire. Je focalise votre attention sur le démarrage de la lecture du flux, la lecture d'entités simples ou d'entités faisant partie d'un espace de nommage. En effet, le reste devient trivial une fois que les bases ont été comprises.
      Code:
      /*
       * Created on 2 nov. 03
       *
       * To change the template for this generated file go to
       * Window>Preferences>Java>Code Generation>Code and Comments
       */
      package com.developpez.smeric.xml.sax;
      
      import org.xml.sax.*;
      import org.xml.sax.helpers.LocatorImpl;
      
      /**
       * @author smeric
       *
       * Exemple d'implementation extremement simplifiee d'un SAX XML ContentHandler. Le but de cet exemple
       * est purement pedagogique.
       * Very simple implementation sample for XML SAX ContentHandler.
       */
      public class SimpleContentHandler implements ContentHandler &#123;
      
              /**
               * Constructeur par defaut. 
               */
              public SimpleContentHandler&#40;&#41; &#123;
                      super&#40;&#41;;
                      // On definit le locator par defaut.
                      locator = new LocatorImpl&#40;&#41;;
              &#125;
      
              /**
               * Definition du locator qui permet a tout moment pendant l'analyse, de localiser
               * le traitement dans le flux. Le locator par defaut indique, par exemple, le numero
               * de ligne et le numero de caractere sur la ligne.
               * @author smeric
               * @param value le locator a utiliser.
               * @see org.xml.sax.ContentHandler#setDocumentLocator&#40;org.xml.sax.Locator&#41;
               */
              public void setDocumentLocator&#40;Locator value&#41; &#123;
                      locator =  value;
              &#125;
      
              /**
               * Evenement envoye au demarrage du parse du flux xml.
               * @throws SAXException en cas de probleme quelquonque ne permettant pas de
               * se lancer dans l'analyse du document.
               * @see org.xml.sax.ContentHandler#startDocument&#40;&#41;
               */
              public void startDocument&#40;&#41; throws SAXException &#123;
                      System.out.println&#40;"Debut de l'analyse du document"&#41;;
              &#125;
      
              /**
               * Evenement envoye a la fin de l'analyse du flux xml.
               * @throws SAXException en cas de probleme quelquonque ne permettant pas de
               * considerer l'analyse du document comme etant complete.
               * @see org.xml.sax.ContentHandler#endDocument&#40;&#41;
               */
              public void endDocument&#40;&#41; throws SAXException &#123;
                      System.out.println&#40;"Fin de l'analyse du document" &#41;;
              &#125;
      
              /**
               * Debut de traitement dans un espace de nommage.
               * @param prefixe utilise pour cet espace de nommage dans cette partie de l'arborescence.
               * @param URI de l'espace de nommage.
               * @see org.xml.sax.ContentHandler#startPrefixMapping&#40;java.lang.String, java.lang.String&#41;
               */
              public void startPrefixMapping&#40;String prefix, String URI&#41; throws SAXException &#123;
                      System.out.println&#40;"Traitement de l'espace de nommage &#58; " + URI + ", prefixe choisi &#58; " + prefix&#41;;
              &#125;
      
              /**
               * Fin de traitement de l'espace de nommage.
               * @param prefixe le prefixe choisi a l'ouverture du traitement de l'espace nommage.
               * @see org.xml.sax.ContentHandler#endPrefixMapping&#40;java.lang.String&#41;
               */
              public void endPrefixMapping&#40;String prefix&#41; throws SAXException &#123;
                      System.out.println&#40;"Fin de traitement de l'espace de nommage &#58; " + prefix&#41;;
              &#125;
      
              /**
               * Evenement recu a chaque fois que l'analyseur rencontre une balise xml ouvrante.
               * @param nameSpaceURI l'url de l'espace de nommage.
               * @param localName le nom local de la balise.
               * @param rawName nom de la balise en version 1.0 <code>nameSpaceURI + "&#58;" + localName</code>
               * @throws SAXException si la balise ne correspond pas a ce qui est attendu,
               * comme par exemple non respect d'une dtd.
               * @see org.xml.sax.ContentHandler#startElement&#40;java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes&#41;
               */
              public void startElement&#40;String nameSpaceURI, String localName, String rawName, Attributes attributs&#41; throws SAXException &#123;
                      System.out.println&#40;"Ouverture de la balise &#58; " + localName&#41;;
      
                      if &#40; ! "".equals&#40;nameSpaceURI&#41;&#41; &#123; // espace de nommage particulier
                              System.out.println&#40;"  appartenant a l'espace de nom &#58; "  + nameSpaceURI&#41;;
                      &#125;
      
                      System.out.println&#40;"  Attributs de la balise &#58; "&#41;;
      
                      for &#40;int index = 0; index < attributs.getLength&#40;&#41;; index++&#41; &#123; // on parcourt la liste des attributs
                              System.out.println&#40;"     - " +  attributs.getLocalName&#40;index&#41; + " = " + attributs.getValue&#40;index&#41;&#41;;
                      &#125;
              &#125;
      
              /**
               * Evenement recu a chaque fermeture de balise.
               * @see org.xml.sax.ContentHandler#endElement&#40;java.lang.String, java.lang.String, java.lang.String&#41;
               */
              public void endElement&#40;String nameSpaceURI, String localName, String rawName&#41; throws SAXException &#123;
                      System.out.print&#40;"Fermeture de la balise &#58; " + localName&#41;;
      
                      if &#40; ! "".equals&#40;nameSpaceURI&#41;&#41; &#123; // name space non null
                              System.out.print&#40;"appartenant a l'espace de nommage &#58; " + localName&#41;;
                      &#125;
      
                      System.out.println&#40;&#41;;
              &#125;
      
              /**
               * Evenement recu a chaque fois que l'analyseur rencontre des caracteres &#40;entre
               * deux balises&#41;.
               * @param ch les caracteres proprement dits.
               * @param start le rang du premier caractere a traiter effectivement.
               * @param end le rang du dernier caractere a traiter effectivement
               * @see org.xml.sax.ContentHandler#characters&#40;char&#91;&#93;, int, int&#41;
               */
              public void characters&#40;char&#91;&#93; ch, int start, int end&#41; throws SAXException &#123;
                      System.out.println&#40;"#PCDATA &#58; " + new String&#40;ch, start, end&#41;&#41;;
              &#125;
      
              /**
               * Recu chaque fois que des caracteres d'espacement peuvent etre ignores au sens de
               * XML. C'est a dire que cet evenement est envoye pour plusieurs espaces se succedant,
               * les tabulations, et les retours chariot se succedants ainsi que toute combinaison de ces
               * trois types d'occurrence.
               * @param ch les caracteres proprement dits.
               * @param start le rang du premier caractere a traiter effectivement.
               * @param end le rang du dernier caractere a traiter effectivement
               * @see org.xml.sax.ContentHandler#ignorableWhitespace&#40;char&#91;&#93;, int, int&#41;
               */
              public void ignorableWhitespace&#40;char&#91;&#93; ch, int start, int end&#41; throws SAXException &#123;
                      System.out.println&#40;"espaces inutiles rencontres &#58; ..." + new String&#40;ch, start, end&#41; +  "..."&#41;;
              &#125;
      
              /**
               * Rencontre une instruction de fonctionnement.
               * @param target la cible de l'instruction de fonctionnement.
               * @param data les valeurs associees a cette cible. En general, elle se presente sous la forme 
               * d'une serie de paires nom/valeur.
               * @see org.xml.sax.ContentHandler#processingInstruction&#40;java.lang.String, java.lang.String&#41;
               */
              public void processingInstruction&#40;String target, String data&#41; throws SAXException &#123;
                      System.out.println&#40;"Instruction de fonctionnement &#58; " + target&#41;;
                      System.out.println&#40;"  dont les arguments sont &#58; " + data&#41;;
              &#125;
      
              /**
               * Recu a chaque fois qu'une balise est evitee dans le traitement a cause d'un
               * probleme non bloque par le parser. Pour ma part je ne pense pas que vous
               * en ayez besoin dans vos traitements.
               * @see org.xml.sax.ContentHandler#skippedEntity&#40;java.lang.String&#41;
               */
              public void skippedEntity&#40;String arg0&#41; throws SAXException &#123;
                      // Je ne fais rien, ce qui se passe n'est pas franchement normal.
                      // Pour eviter cet evenement, le mieux est quand meme de specifier une dtd pour vos
                      // documents xml et de les faire valider par votre parser.              
              &#125;
      
              private Locator locator;
      
      &#125;
      Lancer l'analyse d'un flux XML à l'aide de notre parser SAX

      Nous avons maintenant réagi aux impulsions fournies par le parseur sax mais nous ne savons toujours pas instancier un parser pour qu'il pointe vers notre gestionnaire de contenu, puis lui demander de démarrer la lecture du flux. Voyons donc comment nous allons pouvoir nous y prendre. La manipulation est très simple, il faut obtenir une instance de XMLReader, lui fournir une URI à analyser, lui fournir notre gestionnaire bien entendu et lancer la lecture. Nous avons deux moyens d'arriver à initialiser notre parser : une très simple mais aussi peu évolutive et en particulier très liée à un éditeur ; par exemple :

      XMLReader monAnalyseur = new org.apache.xerces.parsers.SAXParser();

      L'autre solution sera d'utiliser une factory et en particulier la factory proposée avec la distrtibution officielle de SAX : org.xml.sax.helpers.XmlReadersFactory.

      Voyons donc à présent une implémentation rapide d'une classe de démarrage d'une lecture de flux.
      Code:
      /*
       * Created on 2 nov. 03 with Eclipse for Java
       */
      package com.developpez.smeric.xml.sax;
      
      import java.io.IOException;
      
      import org.xml.sax.SAXException;
      import org.xml.sax.XMLReader;
      import org.xml.sax.helpers.XMLReaderFactory;
      
      /**
       * Cette classe est livree tel quel.
       * @author smeric
       * @version 1.0
       */
      public class SimpleSaxParser &#123;
      
              /**
               * Contructeur.
               */
              public SimpleSaxParser&#40;String uri&#41; throws SAXException, IOException &#123;
                              XMLReader saxReader = XMLReaderFactory.createXMLReader&#40;"org.apache.xerces.parsers.SAXParser"&#41;;
                              saxReader.setContentHandler&#40;new SimpleContentHandler&#40;&#41;&#41;;
                              saxReader.parse&#40;uri&#41;;
              &#125;
      
              public static void main&#40;String&#91;&#93; args&#41; &#123;
                      if &#40;0 == args.length || 2 < args.length&#41; &#123;
                              System.out.println&#40;"Usage &#58; SimpleSaxParser uri &#91;parserClassName&#93;"&#41;;
                              System.exit&#40;1&#41;;
                      &#125;
      
                      String uri = args&#91;0&#93;;
      
                      String parserName = null;
                      if &#40;2 == args.length&#41; &#123;
                              parserName = args&#91;1&#93;;
                      &#125;
      
                      try &#123;
                              SimpleSaxParser parser = new SimpleSaxParser&#40;uri&#41;;
                      &#125; catch &#40;Throwable t&#41; &#123;
                              t.printStackTrace&#40;&#41;;
                      &#125;
              &#125;
      &#125;
      
      Ce qui donne comme résultat, lancé sur le fichier de tests suivant &#58;
      
      <?xml version="1.0" encoding="ISO-8859-1" ?>
      <tests>
              <test id="1" nom="mon test"/>
              <test id="2" nom="test 2" type="rien">Un peu de texte
              </test>
      </tests>
      Debut de l'analyse du document
      Ouverture de la balise : tests
      Attributs de la balise :
      #PCDATA :

      Ouverture de la balise : test
      Attributs de la balise :
      - id = 1
      - nom = mon test
      Fermeture de la balise : test
      #PCDATA :

      Ouverture de la balise : test
      Attributs de la balise :
      - id = 2
      - nom = test 2
      - type = rien
      #PCDATA : Un peu de texte

      Fermeture de la balise : test
      #PCDATA :

      Fermeture de la balise : tests
      Fin de l'analyse du document
      Conclusion

      Nous voilà armés pour continuer à étudier l'implémentation de notre monteur à l'aide de l'API SAX en java. L'API reste utilisable dans les divers langages et le portage de ce code ne sera pas compliqué. La prochaine étape de ce petit cours à épisodes nous permettra donc de mettre en oeuvre à la fois cette API, d'implémenter un monteur et de se mettre dans le cadre de l'IOC.

      :KKDS

      Enjoy

      et semholi rah hna

    2. #2
      AZKRI
      Guest

      Par défaut merci

      <center></center>
      <center></center>

      Bravo Mr x_octet
      et bonne continuation


      :hyju

      <center></center>

    3. #3
      LENIH
      Guest

      Par défaut

      merci

    Discussions similaires

    1. Apprentissage du langage Java
      By AZKRI in forum Forum JAVA & Algorithmique
      Réponses: 26
      Dernier message: 16/04/2010, 12h50
    2. Cours XML+ exercices
      By x_octet in forum Forum HTML & XML & ASP
      Réponses: 21
      Dernier message: 04/02/2009, 23h59
    3. 3 éme cours en java ( java de A à Z )
      By AZKRI in forum Forum JAVA & Algorithmique
      Réponses: 10
      Dernier message: 06/02/2008, 00h46
    4. 1 ére Series des cours java ( bien detaillé )
      By AZKRI in forum Forum JAVA & Algorithmique
      Réponses: 26
      Dernier message: 16/03/2007, 01h04
    5. cours de base de donnees bien detaille : )
      By safae in forum Forum Base De données & Analyse
      Réponses: 5
      Dernier message: 07/03/2006, 23h29

    Règles de messages

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •  

    Forum Ti9ni n'est responsable d'aucun accord commercial ou coopératif entre les membres
    Chaque personne assume la responsabilité de la direction de la vente, l'achat, l'accord et l'information de sa position
    Les commentaires publiés ne représentent pas l'opinion de Forum Ti9ni et nous n'en assumons aucune responsabilité (et l'auteur est responsable de la publication)
    Buffer Digg Email Facebook Google LinkedIn Pinterest Print Reddit StumbleUpon Tumblr Twitter VK Yummly