Advanced java code dealing with real world problems.

Thursday, September 2, 2010

A fast XML schema validator

JAXP 1.3 introduced a SchemaFactory by which you can compile a schema from a xsd file, and use the compiled schema to create a Validator that can be used to validate a XML document. Since the schema compilation takes some time, it would be beneficial in a service oriented environment to reuse the compiled schemas for future requests. Presented here is a simple SchemaValidator class that implements the idea with a hash table.

 /*
 * blog/javaclue/xml/SchemaValidator.java
 *
 * Copyright (C) 2009 JackW
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this library.
 * If not, see .
 */

package blog.javaclue.xml;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Hashtable;
import java.util.Map;

import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

/**
 * Validate XML against schema using SchemaFactory (JAXP 1.3).
 * Schema compilation usually takes time, this class saves the compiled schemas
 * in a hash table so they can be reused by future requests and other instances.
 */
public class SchemaValidator {
    protected static Logger logger = Logger.getLogger(SchemaValidator.class);
    protected static boolean isDebugEnabled = logger.isDebugEnabled();
  
    private final String schema_path;
    private final String schema_file;
    private static final Map schemaPool = new Hashtable();
  
    public SchemaValidator(String schema_path, String schema_file) {
        this.schema_path = schema_path;
        this.schema_file = schema_file;
    }

    /**
     * Validate xmlStream against schema
     *
     * @throws IOException
     * @throws SAXException
     * @throws ParserConfigurationException
     */
    public void validate(Document xml_doc) throws ParserConfigurationException, SAXException,
            IOException {
        validate(xml_doc.getDocumentElement());
    }

    public void validate(Element element) throws SAXException, IOException {
        Schema schema = compileSchema(schema_path + schema_file);
      
        // create a Validator instance, which can be used to validate an
        // instance document
        Validator validator = schema.newValidator();
        validator.setErrorHandler(new SaxErrorHandler());
      
        // validate the DOM tree
        validator.validate(new DOMSource(element));
    }

    private static Schema compileSchema(String schemaFile) throws SAXException {
        if (!schemaPool.containsKey(schemaFile)) {
            if (isDebugEnabled) {
                logger.info("compileSchema() - compile schema file: " + schemaFile);
            }
            // create a SchemaFactory capable of understanding W3C schemas
            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

            factory.setErrorHandler(new SaxErrorHandler());
           
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            URL url = loader.getResource(schemaFile);
            if (url == null) {
                throw new RuntimeException("Could not find Schema file: " + schemaFile);
            }
            InputStream is = loader.getResourceAsStream(schemaFile);
            // load a schema, represented by a Schema instance
            Source schemasrc = new StreamSource(is, url.getPath());
            Schema schema = factory.newSchema(schemasrc);
            schemaPool.put(schemaFile, schema);
        }
        return schemaPool.get(schemaFile);
    }

    public static synchronized void removeFromPool(String schemaFile) {
        schemaPool.remove(schemaFile);
    }

    public static synchronized void clearPool() {
        schemaPool.clear();
    }
  
    public static void main(String[] args) {
        SchemaValidator test = new SchemaValidator("Schemas/", "MySampleSchema.xsd");
        try {
            Document doc = XMLHelper.loadDocument("Test_xmls/MySampleXml.xml");
            test.validate(doc);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

No comments:

Post a Comment

Followers

About Me

An IT professional with more than 20 years of experience in enterprise computing. An Audio enthusiast designed and built DIY audio gears and speakers.