IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Format d'échange (XML, JSON...) Java Discussion :

[JAXP 1.2] Valider XML par schéma externe avec SAX (voire DOM)


Sujet :

Format d'échange (XML, JSON...) Java

  1. #1
    Membre éclairé Avatar de g_rare
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    608
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 608
    Points : 683
    Points
    683
    Par défaut [JAXP 1.2] Valider XML par schéma externe avec SAX (voire DOM)
    Bonjour à tous !

    Je dois valider une structure XML avec un fichier XSD, seulement ce schéma n'est pas référencé dans le XML lui-même (il est externe au fichier donc sans déclaration dans celui-ci) :
    - JAXP 1.2 permet-il de valider du XML à partir d'un schéma externe (ie. avec autre chose qu'une DTD interne) ?
    - si oui ; en quel mode (SAX ou DOM) et comment ?
    - si non ; quelle API (JDOM ou autre) peut faire ça rapidement et comment ?

    J'ai fouillé dans la faq + sur le forum + sur le net... mais "chou blanc".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    SAXParserFactory fabrique = SAXParserFactory.newInstance();
    fabrique.setNamespaceAware(true); // 'espace de nom' (si schemas de domaines distincts)
    fabrique.setValidating(true); // validation (cf. schemas du "setFeature")
    SAXParser parseur = fabrique.newSAXParser();
    InputStream xml = null; // ...
    DefaultHandler gestionnaire = new DefaultHandler();
    parseur.parse(xml,gestionnaire); // comment preciser le xsd ???
    " Jag blev dömd för fildelning och allt jag fick var en sketen t-shirt. " (tankafritt.nu)
    PAS DE REPONSE PAR MESSAGE PRIVE ! Penser au bouton Résolu en bas de la discussion...

  2. #2
    Membre habitué Avatar de Xavinou
    Inscrit en
    Mai 2005
    Messages
    135
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 135
    Points : 156
    Points
    156
    Par défaut
    C'est possible avec SAX :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    static boolean validateWithSax(File $xml, File $xsd) throws ParserConfigurationException, SAXException,
    			IOException {
     
    		final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    		final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
    		final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
     
    		// create factory
    		SAXParserFactory factory = SAXParserFactory.newInstance();
    		factory.setValidating(true);
     
    		// create parser
    		SAXParser parser = factory.newSAXParser();
     
    		// set schema
    		parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
    		parser.setProperty(JAXP_SCHEMA_SOURCE, $xsd);
     
    		// parse file
    		ValidationHandler validationHandler = new ValidationHandler();
    		parser.parse($xml, validationHandler);
     
    		// return validation result
    		return validationHandler.isValid();
    	}
    Avec une classe ValidationHandler qui met à jour un flag lorsqu'une erreur est rencontrée lors du parsing :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    	private static class ValidationHandler extends DefaultHandler {
     
    		private boolean _valid = true;
     
    		ValidationHandler() {
    			super();
    		}
     
    		public boolean isValid() {
    			return _valid;
    		}
     
    		/**
                     * @inheritDoc
                     */
    		@Override
    		public void error(SAXParseException $e) throws SAXException {
    			_valid = false;
    			System.err.println($e);
    		}
     
    		/**
                     * @inheritDoc
                     */
    		@Override
    		public void fatalError(SAXParseException $e) throws SAXException {
    			_valid = false;
    			System.err.println($e);
    		}
     
    		/**
                     * @inheritDoc
                     */
    		@Override
    		public void warning(SAXParseException $e) throws SAXException {
    			_valid = false;
    			System.err.println($e);
    		}
    	}
    A noter que dans le jdk 1.5, il existe un package "javax.xml.validation".

  3. #3
    Membre éclairé Avatar de g_rare
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    608
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 608
    Points : 683
    Points
    683
    Par défaut
    Merci bien pour cette piste, mais j'ai (encore) 2 questions de newbie XML :
    _ le fait de configurer le parseur SAX avec la propiété "schemaLanguage" pointant vers l'URL de la w3c signifie-t-il que l'application va s'y connecter pour récupérer le schéma XSD de tous les schémas XSD ?
    _ Comment créer un "InputStream" (cf. fonction utilitaire ci-dessous histoire d'être le plus souple possible) à partir d'un String contenant le XML ?

    Pour info ; voici mon code...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    public class HandlerUtil extends DefaultHandler {
    
        /**
         * Constante Java de cle pour la propriete (de parseur) de validation par schema.
         */
        public final static String JAXP_SCHEMA_LANGUAGE =
            "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    
        /**
         * Constante Java de valeur pour la propriete (de parseur) de validation par schema.
         */
        public final static String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
    
        /**
         * Constante Java de cle pour la propriete (de parseur) de choix pour schema.
         */
        public final static String JAXP_SCHEMA_SOURCE =
            "http://java.sun.com/xml/jaxp/properties/schemaSource";
    
        /**
         * Constructeur (par defaut).
         */
        public HandlerUtil() {
            super();
        }
    
        /**
         * Valide le XML en parametre, selon le schema XSD specifie (avec ce gestionnaire).
         */
        public static void validerSchema(InputStream xml, InputStream xsd)
            throws IOException, ParserConfigurationException, SAXException {
    
            SAXParserFactory fabrique = SAXParserFactory.newInstance();
            fabrique.setNamespaceAware(true); // 'espace de nom' (si schemas de domaines distincts)
            fabrique.setValidating(true); // validation (cf. schemas du "setFeature")
            SAXParser parseur = fabrique.newSAXParser();
            // validation exclusivement par schema XML (meme si DTD declaree en interne)
            parseur.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); // en 1e pour schemaSource
            // c'est le namespace interne qui sera utilise si celui du schema est different
            parseur.setProperty(JAXP_SCHEMA_SOURCE, xsd); // String|InputStream|File|InputSource
            DefaultHandler gestionnaire = new HandlerUtil();
            parseur.parse(xml, gestionnaire);
        }
    
        /**
         * TODO validation
         * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
         */
        public void warning(SAXParseException erreur) throws SAXException {
            super.warning(erreur); // does nothing
            throw erreur;
        }
    
        /**
         * TODO validation
         * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
         */
        public void error(SAXParseException erreur) throws SAXException {
            super.error(erreur); // does nothing
            throw erreur;
        }
    
        /**
         * TODO validation
         * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
         */
        public void fatalError(SAXParseException erreur) throws SAXException {
            super.fatalError(erreur); // throws SAXParseException
        }
    
        /*
         * comment convertir un String en InputStream ?
         */
        public static void main(String[] args) {
            String sourceXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>helloworld</test>";
            InputStream deprecatedXML = new StringBufferInputStream(sourceXML);
            InputStream incompatibleXSD = null; // meme probleme ici
            boolean validiteXSD = true;
            try {
                validerSchema(deprecatedXML, incompatibleXSD);
            } catch (Exception erreur) {
                validiteXSD = false;
            }
            System.out.println(validiteXSD);
        }
    
    }
    MERCI ENCORE
    " Jag blev dömd för fildelning och allt jag fick var en sketen t-shirt. " (tankafritt.nu)
    PAS DE REPONSE PAR MESSAGE PRIVE ! Penser au bouton Résolu en bas de la discussion...

  4. #4
    Membre éclairé Avatar de g_rare
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    608
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 608
    Points : 683
    Points
    683
    Par défaut S.o.s.
    true
    true
    org.apache.xerces.parsers.SAXParser@8a0d5d
    org.apache.xerces.parsers.SAXParser@8a0d5d
    false

    org.xml.sax.SAXNotRecognizedException: http://java.sun.com/xml/jaxp/properties/schemaSource
    at org.apache.xerces.parsers.AbstractSAXParser.setProperty(AbstractSAXParser.java:1691)
    at org.apache.xerces.jaxp.SAXParserImpl.setProperty(SAXParserImpl.java:205)
    at fr.xxx.Tmp.main(Tmp.java:89)
    J'utilise WSAD 5.1.2, donc "a priori" JAXP 1.2(.3) et Xerces 2.0.0 : pourtant cette propriété se retrouve dans tous les tutoriels du net... on suppose donc quelle est supportée !
    Pourquoi cette erreur ?
    Je galère très sérieusement ; donc MERCI INFINIMENT de tout aide.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    /** les exemples choisis sont ceux de wikipedia */
    public class Tmp {
    
        public static void main(String[] args) {
    
            String texte =
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
            + "<personne"
          //+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"personne.xsd\"" +
            + ">"
            + "  <nom>De Latour</nom>"
            + "  <prenom>Jean</prenom>"
            + "  <date_naissance>1967-08-13</date_naissance>"
            + "</personne>";
            Reader caracteres = new StringReader(texte);
            InputSource xml = new InputSource(caracteres);
    
            Reader schema = new StringReader(
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
                + "  <xs:element name=\"personne\">"
                + "     <xs:complexType>"
                + "        <xs:sequence>"
                + "           <xs:element name=\"nom\" type=\"xs:string\"/>"
                + "           <xs:element name=\"prenom\" type=\"xs:string\"/>"
                + "           <xs:element name=\"date_naissance\" type=\"xs:date\"/>"
                + "        </xs:sequence>"
                + "     </xs:complexType>"
                + "  </xs:element>"
                + "</xs:schema>"
            );                    
            InputSource xsd = new InputSource(schema);
    
            boolean ok = true;
    
            try {
                
                SAXParserFactory fabrique = SAXParserFactory.newInstance();
                fabrique.setNamespaceAware(true); // 'espace de nom' (si schemas de domaines distincts)
                fabrique.setValidating(true); // validation (cf. schemas du "setFeature")
    
                SAXParser parseur = fabrique.newSAXParser();
    
                System.out.println(parseur.isNamespaceAware());
                System.out.println(parseur.isValidating());
                System.out.println(parseur.getParser());
                System.out.println(parseur.getXMLReader());
    
                // validation exclusivement par schema XML (meme si DTD declaree en interne)
                parseur.setProperty(
                    "http://java.sun.com/xml/jaxp/properties/schemaLanguage",
                    "http://www.w3.org/2001/XMLSchema"); // en 1e pour schemaSource
                // c'est le namespace interne qui sera utilise si celui du schema est different
                parseur.setProperty(
                    "http://java.sun.com/xml/jaxp/properties/schemaSource",
                    xsd); // String|InputStream|File|InputSource
    
                DefaultHandler gestionnaire = new DefaultHandler();
                parseur.parse(xml, gestionnaire);
                
            } catch (Exception erreur) {
                ok = false;
                Throwable cause = erreur.getCause();
                if (cause != null) {
                    cause.printStackTrace();
                }
                erreur.printStackTrace();
            }
            System.out.println(ok);
        }
    
    }
    " Jag blev dömd för fildelning och allt jag fick var en sketen t-shirt. " (tankafritt.nu)
    PAS DE REPONSE PAR MESSAGE PRIVE ! Penser au bouton Résolu en bas de la discussion...

  5. #5
    Membre habitué Avatar de Xavinou
    Inscrit en
    Mai 2005
    Messages
    135
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 135
    Points : 156
    Points
    156
    Par défaut
    Bonjour,

    Ta version de xerces est relativement ancienne, c'est sans doute pour cela qu'elle ne supporte pas cette propriété. J'espère pour toi que tu peux télécharger une version plus récente (je crois qu'ils en sont à 2.8), sinon ça va devenir compliqué ;-)

    Sinon concernant ton code, il ne faut pas se baser uniquement sur l'exception levée par l'appel de la méthode parse : il faut gérer cela dans le Handler (regarde celui de l'exemple que je t'ai donné, il contient une méthode isValid() à appeler après le parsing).

  6. #6
    Membre éclairé Avatar de g_rare
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    608
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 608
    Points : 683
    Points
    683
    Par défaut
    Pour information, voici un bilan sur la validation d'un schéma XML externe (en mode SAX et DOM) compatible JAXP 1.2 / JRE 1.4 avec Xerces comme parseur :
    - fonctionnalité reconnue par Xerces depuis la version 2.0.1 ;
    - bug provoquant un "StackOverFlow" pour Xerces 2.0.2 ;
    - fonctionnalité effective depuis Xerces 2.1.0 !

    Je recherche donc un autre moyen de valider un schéma XML, utilisant JAXP ou une API quelconque, par lequel je pourrais spécifier explicitement quel parseur utiliser lors de la validation par XSD extérieur au XML ?

    MERCI à ceux qui liront jusqu'au bout
    " Jag blev dömd för fildelning och allt jag fick var en sketen t-shirt. " (tankafritt.nu)
    PAS DE REPONSE PAR MESSAGE PRIVE ! Penser au bouton Résolu en bas de la discussion...

  7. #7
    Membre habitué Avatar de Xavinou
    Inscrit en
    Mai 2005
    Messages
    135
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 135
    Points : 156
    Points
    156
    Par défaut
    Il te suffit de télécharger une version plus récente de xerces et de la placer dans ton classpath avant le parser du jdk.

  8. #8
    Membre éclairé Avatar de g_rare
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    608
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 608
    Points : 683
    Points
    683
    Par défaut
    Bon finalement Xavinou avait raison (MERCI), bien qu'on puisse se baser sur "SAXParseException" comme erreur de validation "SAXException" dans le handler : toute la configuration fonctionne correctement avec Xerces-J 2.8.0 sur une JRE 1.4 maintenant !
    " Jag blev dömd för fildelning och allt jag fick var en sketen t-shirt. " (tankafritt.nu)
    PAS DE REPONSE PAR MESSAGE PRIVE ! Penser au bouton Résolu en bas de la discussion...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [SAX] Validation XML par XSD
    Par KernelControl dans le forum Format d'échange (XML, JSON...)
    Réponses: 4
    Dernier message: 21/01/2009, 14h46
  2. Validation XML par XSD
    Par jago31 dans le forum C#
    Réponses: 5
    Dernier message: 14/05/2008, 08h01
  3. [DOM] Validation XML par un Schéma XSD en php5
    Par cydream dans le forum Bibliothèques et frameworks
    Réponses: 2
    Dernier message: 26/01/2007, 10h32
  4. [DOM] Problème de validation XML par rapport à un Schéma XSD
    Par apisto dans le forum Format d'échange (XML, JSON...)
    Réponses: 2
    Dernier message: 20/09/2006, 15h32
  5. Réponses: 3
    Dernier message: 27/01/2004, 16h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo