Hi,

attached is an implementation of xml schema that is parser independent. The logic for Xerces 2.1/Xerces 2.3 and others parser has been splitted into two new classes:

digester/parser/XercesParser
digester/parser/GenericParser

The digester has been modified to call ParserFeatureSetterFactory, which will discover which parser is used (see the attached diff). I have tested with Xerces 2.1, Xerces 2.5 and Crimson (default with JDK 1.4). I also tested the code using Tomcat 5.

Let me know what you think. Once we all agree I will commit it.

Thanks,

-- Jeanfrancois
/*
 *
 * ====================================================================
 * 
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgement:  
 *       "This product includes software developed by the 
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. The names "Apache", "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written 
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache" nor may "Apache" appear in their names without prior 
 *    written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */ 


package org.apache.commons.digester.parser;

import java.util.Properties;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
  
/**
 * Create a <code>SAXParser</code> configured to support XML Schema and DTD.
 *
 * @author Jean-Francois Arcand
 */

public class GenericParser{

    /**
     * The Log to which all SAX event related logging calls will be made.
     */
    protected static Log log =
        LogFactory.getLog("org.apache.commons.digester.Digester.sax");

    /**
     * The JAXP 1.2 property required to set up the schema location.
     */
    private static final String JAXP_SCHEMA_SOURCE =
        "http://java.sun.com/xml/jaxp/properties/schemaSource";;

    /**
     * The JAXP 1.2 property to set up the schemaLanguage used.
     */
    protected static String JAXP_SCHEMA_LANGUAGE =
        "http://java.sun.com/xml/jaxp/properties/schemaLanguage";;

    /**
     * Create a <code>SAXParser</code> configured to support XML Scheman and DTD
     * @param properties parser specific properties/features
     * @return an XML Schema/DTD enabled <code>SAXParser</code>
     */
    public static SAXParser newSAXParser(Properties properties)
            throws ParserConfigurationException, 
                   SAXException,
                   SAXNotRecognizedException{ 

        SAXParserFactory factory = 
                        (SAXParserFactory)properties.get("SAXParserFactory");
        SAXParser parser = factory.newSAXParser();
        String schemaLocation = (String)properties.get("schemaLocation");
        String schemaLanguage = (String)properties.get("schemaLanguage");

        try{
            if (schemaLocation != null) {
                parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage);
                parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation);
            }
        } catch (SAXNotRecognizedException e){
            log.info(parser.getClass().getName() + ": "  
                                        + e.getMessage() + " not supported."); 
        }
        return parser;
    }

}

/*
 *
 * ====================================================================
 * 
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgement:  
 *       "This product includes software developed by the 
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. The names "Apache", "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written 
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache" nor may "Apache" appear in their names without prior 
 *    written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */ 


package org.apache.commons.digester.parser;

import java.lang.reflect.Method;
import java.util.Properties;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;

/**
 * Create a <code>SAXParser</code> based on the underlying Xerces version.
 * Currently, Xerces 2.3 and up doesn't implement schema validation the same way
 * 2.1 was. In other to support schema validation in a portable way between 
 * parser, some features/properties need to be set.
 *
 * @author Jean-Francois Arcand
 */

public class XercesParser{

    /**
     * The Log to which all SAX event related logging calls will be made.
     */
    protected static Log log =
        LogFactory.getLog("org.apache.commons.digester.Digester.sax");


    /**
     * The JAXP 1.2 property required to set up the schema location.
     */
    private static final String JAXP_SCHEMA_SOURCE =
        "http://java.sun.com/xml/jaxp/properties/schemaSource";;


    /**
     * The JAXP 1.2 property to set up the schemaLanguage used.
     */
    protected static String JAXP_SCHEMA_LANGUAGE =
        "http://java.sun.com/xml/jaxp/properties/schemaLanguage";;


    /**
     * Xerces dynamic validation property
     */
    protected static String XERCES_DYNAMIC = 
        "http://apache.org/xml/features/validation/dynamic";;


    /**
     * Xerces schema validation property
     */
    protected static String XERCES_SCHEMA =
        "http://apache.org/xml/features/validation/schema";;

    
    /**
     * A <code>float</code> representing the underlying Xerces version
     */
    protected static float version;


    /**
     * The current Xerces version.
     */
    protected static String versionNumber = null;


    /**
     * Return the current Xerces version.
     * @return the current Xerces version.
     */
    private static String getXercesVersion() {
        // If for some reason we can't get the version, set it to 1.0.
        String versionNumber = "1.0";
        try{
            // Use reflection to avoid a build dependency with Xerces.
            Class versionClass = 
                            Class.forName("org.apache.xerces.impl.Version");
            // Will return Xerces-J 2.x.0
            Method method = 
                versionClass.getMethod("getVersion", null); 
            String version = (String)method.invoke(null,null);
            versionNumber = version.substring( "Xerces-J".length() , 
                                               version.lastIndexOf(".") ); 
        } catch (Exception ex){
            // Do nothing.
        }
        return versionNumber;
    }


    /**
     * Create a <code>SAXParser</code> based on the underlying
     * <code>Xerces</code> version.
     * @param properties parser specific properties/features
     * @return an XML Schema/DTD enabled <code>SAXParser</code>
     */
    public static SAXParser newSAXParser(Properties properties) 
            throws ParserConfigurationException, 
                   SAXException,
                   SAXNotSupportedException {

        SAXParserFactory factory =  
                        (SAXParserFactory)properties.get("SAXParserFactory");

        if (versionNumber == null){
            versionNumber = getXercesVersion();
            version = new Float( versionNumber ).floatValue();
        }
         
        // Note: 2.2 is completely broken (with XML Schema). 
        if (version > 2.1) {
            
            configureXerces(factory);
            return factory.newSAXParser();
        } else {
            SAXParser parser = factory.newSAXParser();
            configureOldXerces(parser,properties);
            return parser;
        }
    }
    

    /**
     * Configure schema validation as recommended by the JAXP 1.2 spec.
     * The <code>properties</code> object may contains information about
     * the schema local and language. 
     * @param properties parser optional info
     */
    private static void configureOldXerces(SAXParser parser, 
                                           Properties properties) 
            throws ParserConfigurationException, 
                   SAXNotSupportedException {
        
        String schemaLocation = (String)properties.get("schemaLocation");
        String schemaLanguage = (String)properties.get("schemaLanguage");
        
        try{
            if (schemaLocation != null) {
                parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage);
                parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation);
            }
        } catch (SAXNotRecognizedException e){
            log.info(parser.getClass().getName() + ": " 
                                        + e.getMessage() + " not supported."); 
        }

    }


    /**
     * Configure schema validation as recommended by the Xerces spec. 
     * Both DTD and Schema validation will be enabled simultaneously.
     * @param properties parser optional info
     */
    private static void configureXerces(SAXParserFactory factory)
            throws ParserConfigurationException, 
                   SAXNotRecognizedException, 
                   SAXNotSupportedException {
                       
        factory.setFeature(XERCES_DYNAMIC, true);
        factory.setFeature(XERCES_SCHEMA, true);

    }
}



/*
 *
 * ====================================================================
 * 
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgement:  
 *       "This product includes software developed by the 
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. The names "Apache", "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written 
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache" nor may "Apache" appear in their names without prior 
 *    written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */ 


package org.apache.commons.digester;

import java.lang.reflect.Method;
import java.util.Properties;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.digester.parser.GenericParser;
import org.apache.commons.digester.parser.XercesParser;

import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;

/**
 * Creates a <code>SAXParser</code> based on the underlying parser.
 *
 * @author Jean-Francois Arcand
 */
public class ParserFeatureSetterFactory{

    /**
     * <code>true</code> is Xerces is used.
     */
    private static boolean isXercesUsed; 
    
    static {
        try{
            // Use reflection to avoid a build dependency with Xerces.
            Class versionClass = 
                            Class.forName("org.apache.xerces.impl.Version");
            isXercesUsed = true;
        } catch (Exception ex){
            isXercesUsed = false;
        }
    }
    
    /**
     * Create a new <code>SAXParser</code>
     * @return a <code>SAXParser</code> configured based on the underlying
     * parser implementation.
     */
    public static SAXParser newSAXParser(Properties properties)
            throws ParserConfigurationException, 
                   SAXException,
                   SAXNotRecognizedException, 
                   SAXNotSupportedException {

        if (isXercesUsed){
            return XercesParser.newSAXParser(properties);
        } else {
            return GenericParser.newSAXParser(properties);
        }
    }

}


? ParserFeatureSetterFactory.java
? diff.txt
? parser
Index: Digester.java
===================================================================
RCS file: 
/home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/Digester.java,v
retrieving revision 1.86
diff -u -r1.86 Digester.java
--- Digester.java       19 Nov 2003 21:05:19 -0000      1.86
+++ Digester.java       2 Dec 2003 22:49:07 -0000
@@ -74,6 +74,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
@@ -113,8 +114,8 @@
  * even from the same thread.</p>
  *
  * <p><strong>IMPLEMENTATION NOTE</strong> - A bug in Xerces 2.0.2 prevents
- * the support of XML schema. You need Xerces 2.1 or JAXP 1.2.1 to make
- * that class working with XML schema</p>
+ * the support of XML schema. You need Xerces 2.1/2.3 and up to make
+ * this class working with XML schema</p>
  *
  * @author Craig McClanahan
  * @author Scott Sanders
@@ -224,19 +225,6 @@
      */
     protected SAXParserFactory factory = null;
 
-
-    /**
-     * The JAXP 1.2 property required to set up the schema location.
-     */
-    private static final String JAXP_SCHEMA_SOURCE =
-        "http://java.sun.com/xml/jaxp/properties/schemaSource";;
-
-    /**
-     * The JAXP 1.2 property to set up the schemaLanguage used.
-     */
-    protected String JAXP_SCHEMA_LANGUAGE =
-        "http://java.sun.com/xml/jaxp/properties/schemaLanguage";;
-
     
     /**
      * The Locator associated with our parser.
@@ -702,21 +690,21 @@
 
         // Create a new parser
         try {
-            parser = getFactory().newSAXParser();         
+            if (validating) {
+                Properties properties = new Properties();
+                properties.put("SAXParserFactory", getFactory());
+                if (schemaLocation != null) {
+                    properties.put("schemaLocation", schemaLocation);
+                    properties.put("schemaLanguage", schemaLanguage);
+                }
+                parser = ParserFeatureSetterFactory.newSAXParser(properties);         
      } else {
+                parser = getFactory().newSAXParser();
+            }
         } catch (Exception e) {
             log.error("Digester.getParser: ", e);
             return (null);
         }
 
-        // Configure standard properties and return the new instance
-        try {
-            if (schemaLocation != null) {
-                setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage);
-                setProperty(JAXP_SCHEMA_SOURCE, schemaLocation);
-            }
-        } catch (Exception e) {
-            log.warn("" + e);
-        }
         return (parser);
 
     }

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to