Mega Code Archive

 
Categories / Java / XML
 

Use JAXP Validation API to create a validator and validate input from a DOM which contains inline schemas and multiple validation root

/*  * Licensed to the Apache Software Foundation (ASF) under one or more  * contributor license agreements.  See the NOTICE file distributed with  * this work for additional information regarding copyright ownership.  * The ASF licenses this file to You under the Apache License, Version 2.0  * (the "License"); you may not use this file except in compliance with  * the License.  You may obtain a copy of the License at  *   *      http://www.apache.org/licenses/LICENSE-2.0  *   * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ import java.io.PrintWriter; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Vector; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.SAXParseException; /**  * <p>  * A sample demonstrating how to use the JAXP 1.3 Validation API to create a  * validator and use the validator to validate input from a DOM which contains  * inline schemas and multiple validation roots. The output of this program  * shows the time spent executing the Validator.validate(Source) method.  * </p>  *   * <p>  * This class is useful as a "poor-man's" performance tester to compare the  * speed of various JAXP 1.3 validators with different input sources. However,  * it is important to note that the first validation time of a validator will  * include both VM class load time and validator initialization that would not  * be present in subsequent validations with the same document.  * </p>  *   * <p>  * <strong>Note:</strong> The results produced by this program should never be  * accepted as true performance measurements.  * </p>  *   * @author Michael Glavassevich, IBM  *   * @version $Id: InlineSchemaValidator.java 447685 2006-09-19 02:37:49Z mrglavas $  */ public class InlineSchemaValidator implements ErrorHandler, NamespaceContext {   //   // Constants   //   // feature ids   /**    * Schema full checking feature id    * (http://apache.org/xml/features/validation/schema-full-checking).    */   protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking";   /**    * Honour all schema locations feature id    * (http://apache.org/xml/features/honour-all-schemaLocations).    */   protected static final String HONOUR_ALL_SCHEMA_LOCATIONS_ID = "http://apache.org/xml/features/honour-all-schemaLocations";   /**    * Validate schema annotations feature id    * (http://apache.org/xml/features/validate-annotations)    */   protected static final String VALIDATE_ANNOTATIONS_ID = "http://apache.org/xml/features/validate-annotations";   /**    * Generate synthetic schema annotations feature id    * (http://apache.org/xml/features/generate-synthetic-annotations).    */   protected static final String GENERATE_SYNTHETIC_ANNOTATIONS_ID = "http://apache.org/xml/features/generate-synthetic-annotations";   // default settings   /** Default schema language (http://www.w3.org/2001/XMLSchema). */   protected static final String DEFAULT_SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI;   /** Default repetition (1). */   protected static final int DEFAULT_REPETITION = 1;   /** Default schema full checking support (false). */   protected static final boolean DEFAULT_SCHEMA_FULL_CHECKING = false;   /** Default honour all schema locations (false). */   protected static final boolean DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS = false;   /** Default validate schema annotations (false). */   protected static final boolean DEFAULT_VALIDATE_ANNOTATIONS = false;   /** Default generate synthetic schema annotations (false). */   protected static final boolean DEFAULT_GENERATE_SYNTHETIC_ANNOTATIONS = false;   /** Default memory usage report (false). */   protected static final boolean DEFAULT_MEMORY_USAGE = false;   //   // Data   //   /** Print writer. */   protected PrintWriter fOut = new PrintWriter(System.out);   /** Prefix to URI mappings for the NamespaceContext. */   protected HashMap fPrefixToURIMappings;   /** URI to prefix mappings for the NamespaceContext. */   protected HashMap fURIToPrefixMappings;   //   // Constructors   //   public InlineSchemaValidator(HashMap prefixToURIMappings, HashMap uriToPrefixMappings) {     fPrefixToURIMappings = prefixToURIMappings;     fURIToPrefixMappings = uriToPrefixMappings;   } // <init>(HashMap,HashMap)   //   // Public methods   //   public void validate(Validator validator, Source source, String systemId, int repetitions,       boolean memoryUsage) {     try {       long timeBefore = System.currentTimeMillis();       long memoryBefore = Runtime.getRuntime().freeMemory();       for (int j = 0; j < repetitions; ++j) {         validator.validate(source);       }       long memoryAfter = Runtime.getRuntime().freeMemory();       long timeAfter = System.currentTimeMillis();       long time = timeAfter - timeBefore;       long memory = memoryUsage ? memoryBefore - memoryAfter : Long.MIN_VALUE;       printResults(fOut, systemId, time, memory, repetitions);     } catch (SAXParseException e) {       // ignore     } catch (Exception e) {       System.err.println("error: Parse error occurred - " + e.getMessage());       Exception se = e;       if (e instanceof SAXException) {         se = ((SAXException) e).getException();       }       if (se != null)         se.printStackTrace(System.err);       else         e.printStackTrace(System.err);     }   } // validate(Validator,Source,String,int,boolean)   /** Prints the results. */   public void printResults(PrintWriter out, String uri, long time, long memory, int repetition) {     // filename.xml: 631 ms     out.print(uri);     out.print(": ");     if (repetition == 1) {       out.print(time);     } else {       out.print(time);       out.print('/');       out.print(repetition);       out.print('=');       out.print(((float) time) / repetition);     }     out.print(" ms");     if (memory != Long.MIN_VALUE) {       out.print(", ");       out.print(memory);       out.print(" bytes");     }     out.println();     out.flush();   } // printResults(PrintWriter,String,long,long,int)   //   // ErrorHandler methods   //   /** Warning. */   public void warning(SAXParseException ex) throws SAXException {     printError("Warning", ex);   } // warning(SAXParseException)   /** Error. */   public void error(SAXParseException ex) throws SAXException {     printError("Error", ex);   } // error(SAXParseException)   /** Fatal error. */   public void fatalError(SAXParseException ex) throws SAXException {     printError("Fatal Error", ex);     throw ex;   } // fatalError(SAXParseException)   //   // NamespaceContext methods   //   public String getNamespaceURI(String prefix) {     if (prefix == null) {       throw new IllegalArgumentException("Prefix cannot be null.");     } else if (XMLConstants.XML_NS_PREFIX.equals(prefix)) {       return XMLConstants.XML_NS_URI;     } else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) {       return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;     } else if (fPrefixToURIMappings != null) {       String uri = (String) fPrefixToURIMappings.get(prefix);       if (uri != null) {         return uri;       }     }     return XMLConstants.NULL_NS_URI;   } // getNamespaceURI(String)   public String getPrefix(String namespaceURI) {     if (namespaceURI == null) {       throw new IllegalArgumentException("Namespace URI cannot be null.");     } else if (XMLConstants.XML_NS_URI.equals(namespaceURI)) {       return XMLConstants.XML_NS_PREFIX;     } else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) {       return XMLConstants.XMLNS_ATTRIBUTE;     } else if (fURIToPrefixMappings != null) {       HashSet prefixes = (HashSet) fURIToPrefixMappings.get(namespaceURI);       if (prefixes != null && prefixes.size() > 0) {         return (String) prefixes.iterator().next();       }     }     return null;   } // getPrefix(String)   public Iterator getPrefixes(String namespaceURI) {     if (namespaceURI == null) {       throw new IllegalArgumentException("Namespace URI cannot be null.");     } else if (XMLConstants.XML_NS_URI.equals(namespaceURI)) {       return new Iterator() {         boolean more = true;         public boolean hasNext() {           return more;         }         public Object next() {           if (!hasNext()) {             throw new NoSuchElementException();           }           more = false;           return XMLConstants.XML_NS_PREFIX;         }         public void remove() {           throw new UnsupportedOperationException();         }       };     } else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) {       return new Iterator() {         boolean more = true;         public boolean hasNext() {           return more;         }         public Object next() {           if (!hasNext()) {             throw new NoSuchElementException();           }           more = false;           return XMLConstants.XMLNS_ATTRIBUTE;         }         public void remove() {           throw new UnsupportedOperationException();         }       };     } else if (fURIToPrefixMappings != null) {       HashSet prefixes = (HashSet) fURIToPrefixMappings.get(namespaceURI);       if (prefixes != null && prefixes.size() > 0) {         return prefixes.iterator();       }     }     return Collections.EMPTY_LIST.iterator();   } // getPrefixes(String)   //   // Protected methods   //   /** Prints the error message. */   protected void printError(String type, SAXParseException ex) {     System.err.print("[");     System.err.print(type);     System.err.print("] ");     String systemId = ex.getSystemId();     if (systemId != null) {       int index = systemId.lastIndexOf('/');       if (index != -1)         systemId = systemId.substring(index + 1);       System.err.print(systemId);     }     System.err.print(':');     System.err.print(ex.getLineNumber());     System.err.print(':');     System.err.print(ex.getColumnNumber());     System.err.print(": ");     System.err.print(ex.getMessage());     System.err.println();     System.err.flush();   } // printError(String,SAXParseException)   //   // MAIN   //   /** Main program entry point. */   public static void main(String[] argv) {     // is there anything to do?     if (argv.length == 0) {       printUsage();       System.exit(1);     }     // variables     Vector schemas = null;     Vector instances = null;     HashMap prefixMappings = null;     HashMap uriMappings = null;     String docURI = argv[argv.length - 1];     String schemaLanguage = DEFAULT_SCHEMA_LANGUAGE;     int repetition = DEFAULT_REPETITION;     boolean schemaFullChecking = DEFAULT_SCHEMA_FULL_CHECKING;     boolean honourAllSchemaLocations = DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS;     boolean validateAnnotations = DEFAULT_VALIDATE_ANNOTATIONS;     boolean generateSyntheticAnnotations = DEFAULT_GENERATE_SYNTHETIC_ANNOTATIONS;     boolean memoryUsage = DEFAULT_MEMORY_USAGE;     // process arguments     for (int i = 0; i < argv.length - 1; ++i) {       String arg = argv[i];       if (arg.startsWith("-")) {         String option = arg.substring(1);         if (option.equals("l")) {           // get schema language name           if (++i == argv.length) {             System.err.println("error: Missing argument to -l option.");           } else {             schemaLanguage = argv[i];           }           continue;         }         if (option.equals("x")) {           if (++i == argv.length) {             System.err.println("error: Missing argument to -x option.");             continue;           }           String number = argv[i];           try {             int value = Integer.parseInt(number);             if (value < 1) {               System.err.println("error: Repetition must be at least 1.");               continue;             }             repetition = value;           } catch (NumberFormatException e) {             System.err.println("error: invalid number (" + number + ").");           }           continue;         }         if (arg.equals("-a")) {           // process -a: xpath expressions for schemas           if (schemas == null) {             schemas = new Vector();           }           while (i + 1 < argv.length - 1 && !(arg = argv[i + 1]).startsWith("-")) {             schemas.add(arg);             ++i;           }           continue;         }         if (arg.equals("-i")) {           // process -i: xpath expressions for instance documents           if (instances == null) {             instances = new Vector();           }           while (i + 1 < argv.length - 1 && !(arg = argv[i + 1]).startsWith("-")) {             instances.add(arg);             ++i;           }           continue;         }         if (arg.equals("-nm")) {           String prefix;           String uri;           while (i + 2 < argv.length - 1 && !(prefix = argv[i + 1]).startsWith("-")               && !(uri = argv[i + 2]).startsWith("-")) {             if (prefixMappings == null) {               prefixMappings = new HashMap();               uriMappings = new HashMap();             }             prefixMappings.put(prefix, uri);             HashSet prefixes = (HashSet) uriMappings.get(uri);             if (prefixes == null) {               prefixes = new HashSet();               uriMappings.put(uri, prefixes);             }             prefixes.add(prefix);             i += 2;           }           continue;         }         if (option.equalsIgnoreCase("f")) {           schemaFullChecking = option.equals("f");           continue;         }         if (option.equalsIgnoreCase("hs")) {           honourAllSchemaLocations = option.equals("hs");           continue;         }         if (option.equalsIgnoreCase("va")) {           validateAnnotations = option.equals("va");           continue;         }         if (option.equalsIgnoreCase("ga")) {           generateSyntheticAnnotations = option.equals("ga");           continue;         }         if (option.equalsIgnoreCase("m")) {           memoryUsage = option.equals("m");           continue;         }         if (option.equals("h")) {           printUsage();           continue;         }         System.err.println("error: unknown option (" + option + ").");         continue;       }     }     try {       // Create new instance of inline schema validator.       InlineSchemaValidator inlineSchemaValidator = new InlineSchemaValidator(prefixMappings,           uriMappings);       // Parse document containing schemas and validation roots       DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();       dbf.setNamespaceAware(true);       DocumentBuilder db = dbf.newDocumentBuilder();       db.setErrorHandler(inlineSchemaValidator);       Document doc = db.parse(docURI);       // Create XPath factory for selecting schema and validation roots       XPathFactory xpf = XPathFactory.newInstance();       XPath xpath = xpf.newXPath();       xpath.setNamespaceContext(inlineSchemaValidator);       // Select schema roots from the DOM       NodeList[] schemaNodes = new NodeList[schemas != null ? schemas.size() : 0];       for (int i = 0; i < schemaNodes.length; ++i) {         XPathExpression xpathSchema = xpath.compile((String) schemas.elementAt(i));         schemaNodes[i] = (NodeList) xpathSchema.evaluate(doc, XPathConstants.NODESET);       }       // Select validation roots from the DOM       NodeList[] instanceNodes = new NodeList[instances != null ? instances.size() : 0];       for (int i = 0; i < instanceNodes.length; ++i) {         XPathExpression xpathInstance = xpath.compile((String) instances.elementAt(i));         instanceNodes[i] = (NodeList) xpathInstance.evaluate(doc, XPathConstants.NODESET);       }       // Create SchemaFactory and configure       SchemaFactory factory = SchemaFactory.newInstance(schemaLanguage);       factory.setErrorHandler(inlineSchemaValidator);       try {         factory.setFeature(SCHEMA_FULL_CHECKING_FEATURE_ID, schemaFullChecking);       } catch (SAXNotRecognizedException e) {         System.err.println("warning: SchemaFactory does not recognize feature ("             + SCHEMA_FULL_CHECKING_FEATURE_ID + ")");       } catch (SAXNotSupportedException e) {         System.err.println("warning: SchemaFactory does not support feature ("             + SCHEMA_FULL_CHECKING_FEATURE_ID + ")");       }       try {         factory.setFeature(HONOUR_ALL_SCHEMA_LOCATIONS_ID, honourAllSchemaLocations);       } catch (SAXNotRecognizedException e) {         System.err.println("warning: SchemaFactory does not recognize feature ("             + HONOUR_ALL_SCHEMA_LOCATIONS_ID + ")");       } catch (SAXNotSupportedException e) {         System.err.println("warning: SchemaFactory does not support feature ("             + HONOUR_ALL_SCHEMA_LOCATIONS_ID + ")");       }       try {         factory.setFeature(VALIDATE_ANNOTATIONS_ID, validateAnnotations);       } catch (SAXNotRecognizedException e) {         System.err.println("warning: SchemaFactory does not recognize feature ("             + VALIDATE_ANNOTATIONS_ID + ")");       } catch (SAXNotSupportedException e) {         System.err.println("warning: SchemaFactory does not support feature ("             + VALIDATE_ANNOTATIONS_ID + ")");       }       try {         factory.setFeature(GENERATE_SYNTHETIC_ANNOTATIONS_ID, generateSyntheticAnnotations);       } catch (SAXNotRecognizedException e) {         System.err.println("warning: SchemaFactory does not recognize feature ("             + GENERATE_SYNTHETIC_ANNOTATIONS_ID + ")");       } catch (SAXNotSupportedException e) {         System.err.println("warning: SchemaFactory does not support feature ("             + GENERATE_SYNTHETIC_ANNOTATIONS_ID + ")");       }       // Build Schema from sources       Schema schema;       {         DOMSource[] sources;         int size = 0;         for (int i = 0; i < schemaNodes.length; ++i) {           size += schemaNodes[i].getLength();         }         sources = new DOMSource[size];         if (size == 0) {           schema = factory.newSchema();         } else {           int count = 0;           for (int i = 0; i < schemaNodes.length; ++i) {             NodeList nodeList = schemaNodes[i];             int nodeListLength = nodeList.getLength();             for (int j = 0; j < nodeListLength; ++j) {               sources[count++] = new DOMSource(nodeList.item(j));             }           }           schema = factory.newSchema(sources);         }       }       // Setup validator and input source.       Validator validator = schema.newValidator();       validator.setErrorHandler(inlineSchemaValidator);       try {         validator.setFeature(SCHEMA_FULL_CHECKING_FEATURE_ID, schemaFullChecking);       } catch (SAXNotRecognizedException e) {         System.err.println("warning: Validator does not recognize feature ("             + SCHEMA_FULL_CHECKING_FEATURE_ID + ")");       } catch (SAXNotSupportedException e) {         System.err.println("warning: Validator does not support feature ("             + SCHEMA_FULL_CHECKING_FEATURE_ID + ")");       }       try {         validator.setFeature(HONOUR_ALL_SCHEMA_LOCATIONS_ID, honourAllSchemaLocations);       } catch (SAXNotRecognizedException e) {         System.err.println("warning: Validator does not recognize feature ("             + HONOUR_ALL_SCHEMA_LOCATIONS_ID + ")");       } catch (SAXNotSupportedException e) {         System.err.println("warning: Validator does not support feature ("             + HONOUR_ALL_SCHEMA_LOCATIONS_ID + ")");       }       try {         validator.setFeature(VALIDATE_ANNOTATIONS_ID, validateAnnotations);       } catch (SAXNotRecognizedException e) {         System.err.println("warning: Validator does not recognize feature ("             + VALIDATE_ANNOTATIONS_ID + ")");       } catch (SAXNotSupportedException e) {         System.err.println("warning: Validator does not support feature ("             + VALIDATE_ANNOTATIONS_ID + ")");       }       try {         validator.setFeature(GENERATE_SYNTHETIC_ANNOTATIONS_ID, generateSyntheticAnnotations);       } catch (SAXNotRecognizedException e) {         System.err.println("warning: Validator does not recognize feature ("             + GENERATE_SYNTHETIC_ANNOTATIONS_ID + ")");       } catch (SAXNotSupportedException e) {         System.err.println("warning: Validator does not support feature ("             + GENERATE_SYNTHETIC_ANNOTATIONS_ID + ")");       }       // Validate instance documents       for (int i = 0; i < instanceNodes.length; ++i) {         NodeList nodeList = instanceNodes[i];         int nodeListLength = nodeList.getLength();         for (int j = 0; j < nodeListLength; ++j) {           DOMSource source = new DOMSource(nodeList.item(j));           source.setSystemId(docURI);           inlineSchemaValidator.validate(validator, source, docURI, repetition, memoryUsage);         }       }     } catch (SAXParseException e) {       // ignore     } catch (Exception e) {       System.err.println("error: Parse error occurred - " + e.getMessage());       if (e instanceof SAXException) {         Exception nested = ((SAXException) e).getException();         if (nested != null) {           e = nested;         }       }       e.printStackTrace(System.err);     }   } // main(String[])   //   // Private static methods   //   /** Prints the usage. */   private static void printUsage() {     System.err.println("usage: java jaxp.InlineSchemaValidator (options) uri ...");     System.err.println();     System.err.println("options:");     System.err.println("  -l name          Select schema language by name.");     System.err.println("  -x number        Select number of repetitions.");     System.err.println("  -a xpath    ...  Provide a list of XPath expressions for schema roots");     System.err         .println("  -i xpath    ...  Provide a list of XPath expressions for validation roots");     System.err         .println("  -nm pre uri ...  Provide a list of prefix to namespace URI mappings for the XPath expressions.");     System.err.println("  -f  | -F         Turn on/off Schema full checking.");     System.err         .println("                   NOTE: Not supported by all schema factories and validators.");     System.err.println("  -hs | -HS        Turn on/off honouring of all schema locations.");     System.err         .println("                   NOTE: Not supported by all schema factories and validators.");     System.err.println("  -va | -VA        Turn on/off validation of schema annotations.");     System.err         .println("                   NOTE: Not supported by all schema factories and validators.");     System.err         .println("  -ga | -GA        Turn on/off generation of synthetic schema annotations.");     System.err         .println("                   NOTE: Not supported by all schema factories and validators.");     System.err.println("  -m  | -M         Turn on/off memory usage report");     System.err.println("  -h               This help screen.");     System.err.println();     System.err.println("defaults:");     System.err.println("  Schema language:                 " + DEFAULT_SCHEMA_LANGUAGE);     System.err.println("  Repetition:                      " + DEFAULT_REPETITION);     System.err.print("  Schema full checking:            ");     System.err.println(DEFAULT_SCHEMA_FULL_CHECKING ? "on" : "off");     System.err.print("  Honour all schema locations:     ");     System.err.println(DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS ? "on" : "off");     System.err.print("  Validate annotations:            ");     System.err.println(DEFAULT_VALIDATE_ANNOTATIONS ? "on" : "off");     System.err.print("  Generate synthetic annotations:  ");     System.err.println(DEFAULT_GENERATE_SYNTHETIC_ANNOTATIONS ? "on" : "off");     System.err.print("  Memory:                          ");     System.err.println(DEFAULT_MEMORY_USAGE ? "on" : "off");     System.err.println();     System.err.println("notes:");     System.err         .println("  The speed and memory results from this program should NOT be used as the");     System.err         .println("  basis of parser performance comparison! Real analytical methods should be");     System.err         .println("  used. For better results, perform multiple document validations within the");     System.err         .println("  same virtual machine to remove class loading from parse time and memory usage.");   } // printUsage() } // class InlineSchemaValidator