[117266] Updated XSD validator to use grammar preparser.
diff --git a/bundles/org.eclipse.wst.xsd.core/src-validation/org/eclipse/wst/xsd/core/internal/validation/XSDValidator.java b/bundles/org.eclipse.wst.xsd.core/src-validation/org/eclipse/wst/xsd/core/internal/validation/XSDValidator.java index a346aa0..f16d9c0 100644 --- a/bundles/org.eclipse.wst.xsd.core/src-validation/org/eclipse/wst/xsd/core/internal/validation/XSDValidator.java +++ b/bundles/org.eclipse.wst.xsd.core/src-validation/org/eclipse/wst/xsd/core/internal/validation/XSDValidator.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2001, 2004 IBM Corporation and others. + * Copyright (c) 2001, 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,159 +10,102 @@ *******************************************************************************/ package org.eclipse.wst.xsd.core.internal.validation; -import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.net.URL; -import org.apache.xerces.parsers.SAXParser; +import org.apache.xerces.impl.Constants; +import org.apache.xerces.parsers.XMLGrammarPreparser; +import org.apache.xerces.util.XMLGrammarPoolImpl; import org.apache.xerces.xni.XMLResourceIdentifier; import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; import org.apache.xerces.xni.parser.XMLEntityResolver; +import org.apache.xerces.xni.parser.XMLErrorHandler; import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParseException; import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver; import org.eclipse.wst.xml.core.internal.validation.XMLValidator; import org.eclipse.wst.xml.core.internal.validation.core.ValidationInfo; import org.eclipse.wst.xml.core.internal.validation.core.ValidationReport; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.XMLReader; +import org.w3c.dom.DOMError; /** * The XSDValidator will validate XSD files. - * - * @author Lawrence Mandel, IBM */ public class XSDValidator { - - private final String XML_INSTANCE_DOC_TOP = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<root \n" //$NON-NLS-1$//$NON-NLS-2$ - + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"; //$NON-NLS-1$ - - private final String XML_INSTANCE_DOC_MID = " xsi:noNamespaceSchemaLocation=\""; //$NON-NLS-1$ - - private final String XML_INSTANCE_DOC_BOT = "\">\n" + "</root>\n"; //$NON-NLS-1$//$NON-NLS-2$ - - private final String DUMMY_URI = "http://example.org/dummy"; //$NON-NLS-1$ - private URIResolver uriresolver = null; public ValidationReport validate(String uri) { return validate(uri, null); } - + /** * Validate the XSD file specified by the URI. * * @param uri * The URI of the XSD file to validate. + * @param inputStream An input stream representing the XSD file to validate. */ public ValidationReport validate(String uri, InputStream inputStream) { - ValidationInfo valinfo = new ValidationInfo(uri); - try - { - String ns = null; - String schemaLocationString = ""; + ValidationInfo valinfo = new ValidationInfo(uri); + XSDErrorHandler errorHandler = new XSDErrorHandler(valinfo); + try + { + XMLGrammarPreparser grammarPreparser = new XMLGrammarPreparser(); + grammarPreparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA,null/*schemaLoader*/); + + grammarPreparser.setProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY, new XMLGrammarPoolImpl()); + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE, false); + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE, true); + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE, true); + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATION_FEATURE, true); + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE, true); + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING, false); + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE, true); + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE, true); + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE, true); + + try + { + grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + "http://apache.org/xml/features/honour-all-schemaLocations", true); + } + catch (Exception e) + { + // catch the exception and ignore + } + + grammarPreparser.setErrorHandler(errorHandler); + if (uriresolver != null) + { + XSDEntityResolver resolver = new XSDEntityResolver(uriresolver, uri); + if (resolver != null) + { + grammarPreparser.setEntityResolver(resolver); + } + } - URL url = new URL(uri); - if (url != null) - { - BufferedReader bufreader = new BufferedReader(new InputStreamReader(url.openStream())); - - if (bufreader != null) - { - StringBuffer source = new StringBuffer(); - while (bufreader.ready()) - { - source.append(bufreader.readLine()); - } - bufreader.close(); - int tn = source.indexOf("targetNamespace"); - if (tn != -1) - { - int firstquote = source.indexOf("\"", tn) + 1; - int secondquote = source.indexOf("\"", firstquote); - ns = source.substring(firstquote, secondquote); - } - } - bufreader.close(); + try + { + XMLInputSource is = new XMLInputSource(null, uri, uri, inputStream, null); + grammarPreparser.getLoader(XMLGrammarDescription.XML_SCHEMA); + grammarPreparser.preparseGrammar(XMLGrammarDescription.XML_SCHEMA,is); + } + catch (Exception e) + { + //parser will return null pointer exception if the document is structurally invalid + //TODO: log error message + //System.out.println(e); } - - XSDErrorHandler errorHandler = new XSDErrorHandler(valinfo); - try - { - StringBuffer instanceDoc = new StringBuffer(XML_INSTANCE_DOC_TOP); - if (ns != null && !ns.equals("")) - { - instanceDoc.append(" xmlns=\"").append(ns).append("\"\n"); - instanceDoc.append(" xsi:schemaLocation=\""); - instanceDoc.append(ns); - instanceDoc.append(" "); - } else - { - instanceDoc.append(XML_INSTANCE_DOC_MID); - } - instanceDoc.append(uri.replaceAll(" ", "%20")); - if (!schemaLocationString.equals("")) - { - instanceDoc.append(" ").append(schemaLocationString); - } - instanceDoc.append(XML_INSTANCE_DOC_BOT); - InputSource is = new InputSource(new StringReader(instanceDoc.toString())); - is.setSystemId(DUMMY_URI); - - String soapFile = "platform:/plugin/org.eclipse.wst.wsdl.validation./xsd/xml-soap.xsd"; - XMLReader reader = new SAXParser(); - try - { - reader.setFeature("http://apache.org/xml/features/continue-after-fatal-error", false); - reader.setFeature("http://xml.org/sax/features/namespaces", true); - reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); - reader.setFeature("http://xml.org/sax/features/validation", true); - reader.setFeature("http://apache.org/xml/features/validation/schema", true); - reader.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true); - reader.setFeature("http://xml.org/sax/features/external-general-entities", true); - reader.setFeature("http://xml.org/sax/features/external-parameter-entities", true); - reader.setFeature("http://apache.org/xml/features/validation/warn-on-duplicate-attdef", true); - - reader.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation", - "http://xml.apache.org/xml-soap " + soapFile); - reader.setErrorHandler(errorHandler); - - if (uriresolver != null) - { - XSDEntityResolver resolver = new XSDEntityResolver(uriresolver, uri, inputStream); - try - { - reader.setProperty("http://apache.org/xml/properties/internal/entity-resolver", resolver); - } - catch (Exception e) - { - // TODO: log failure to register the entity resolver. - } - } - - reader.parse(is); - - } catch (SAXException e) - { - //LoggerFactory.getLoggerInstance().logError("XSD Validator Exception: ", e); - } - } catch (IOException except) - { - //LoggerFactory.getLoggerInstance().logError("XSD Validator Exception: ", except); - } - } catch (Exception e) - { - //LoggerFactory.getLoggerInstance().logError("XSD Validator Exception: ", e); - } - - return valinfo; + } + catch (Exception e) + { + // TODO: log error. + //System.out.println(e); + } + return valinfo; } /** @@ -179,16 +122,10 @@ /** * The XSDErrorHandler handle Xerces parsing errors and puts the errors * into the given ValidationInfo object. - * - * @author Lawrence Mandel, IBM */ - protected class XSDErrorHandler implements org.xml.sax.ErrorHandler + protected class XSDErrorHandler implements XMLErrorHandler { - - private final int ERROR = 0; - - private final int WARNING = 1; - + private final ValidationInfo valinfo; public XSDErrorHandler(ValidationInfo valinfo) @@ -199,57 +136,49 @@ /** * Add a validation message with the given severity. * + * @param errorKey The Xerces error key. * @param exception The exception that contains the information about the message. * @param severity The severity of the validation message. */ - protected void addValidationMessage(SAXParseException exception, int severity) + protected void addValidationMessage(String errorKey, XMLParseException exception, int severity) { - // get the error key by taking the substring of what is before the ':' in the error message: - String errorKey = exception.getLocalizedMessage(); - if (errorKey != null) + String systemId = exception.getExpandedSystemId(); + if (systemId != null) { - int index = errorKey.indexOf(':'); - if (index != -1) - { errorKey = errorKey.substring(0, index); - } - } - - if (exception.getSystemId() != null && !exception.getSystemId().equals(DUMMY_URI)) - { - if (severity == WARNING) + if (severity == DOMError.SEVERITY_WARNING) { - valinfo.addWarning(exception.getLocalizedMessage(), exception.getLineNumber(), exception.getColumnNumber(), exception.getSystemId()); + valinfo.addWarning(exception.getLocalizedMessage(), exception.getLineNumber(), exception.getColumnNumber(), systemId); } else { - valinfo.addError(exception.getLocalizedMessage(), exception.getLineNumber(), exception.getColumnNumber(), exception.getSystemId(), errorKey, null); + valinfo.addError(exception.getLocalizedMessage(), exception.getLineNumber(), exception.getColumnNumber(), systemId, errorKey, null); } } } /* (non-Javadoc) - * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException) + * @see org.apache.xerces.xni.parser.XMLErrorHandler#warning(java.lang.String, java.lang.String, org.apache.xerces.xni.parser.XMLParseException) */ - public void error(SAXParseException exception) throws SAXException - { - addValidationMessage(exception, ERROR); - } + public void warning(String domain, String key, XMLParseException exception) throws XNIException + { + addValidationMessage(key, exception, DOMError.SEVERITY_WARNING); + } /* (non-Javadoc) - * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException) + * @see org.apache.xerces.xni.parser.XMLErrorHandler#error(java.lang.String, java.lang.String, org.apache.xerces.xni.parser.XMLParseException) */ - public void fatalError(SAXParseException exception) throws SAXException + public void error(String domain, String key, XMLParseException exception) throws XNIException { - addValidationMessage(exception, ERROR); - } + addValidationMessage(key, exception, DOMError.SEVERITY_ERROR); + } /* (non-Javadoc) - * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) + * @see org.apache.xerces.xni.parser.XMLErrorHandler#fatalError(java.lang.String, java.lang.String, org.apache.xerces.xni.parser.XMLParseException) */ - public void warning(SAXParseException exception) throws SAXException - { - addValidationMessage(exception, WARNING); - } + public void fatalError(String domain, String key, XMLParseException exception) throws XNIException + { + addValidationMessage(key, exception, DOMError.SEVERITY_FATAL_ERROR); + } } /** @@ -260,8 +189,6 @@ { private URIResolver uriresolver = null; - private InputStream inputStream; - /** * Constructor. * @@ -269,10 +196,9 @@ * The idresolver this entity resolver wraps. * @param baselocation The base location to resolve with. */ - public XSDEntityResolver(URIResolver uriresolver, String baselocation, InputStream inputStream) + public XSDEntityResolver(URIResolver uriresolver, String baselocation) { this.uriresolver = uriresolver; - this.inputStream = inputStream; } /* (non-Javadoc) @@ -280,23 +206,17 @@ */ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) throws XNIException, IOException { - // consider the resourceIdentifier's fields to see we're actually in the dummy xml file - // and if this is the reference to the schema we want to validate - // ... if so return an XMLInputSource built from the dirty copy of the schema - boolean isDummyXML = DUMMY_URI.equals(resourceIdentifier.getBaseSystemId()); - if (isDummyXML && inputStream != null) + String literalSystemId = resourceIdentifier.getLiteralSystemId(); + if(literalSystemId != null) { - XMLInputSource inputSource = new XMLInputSource(null, resourceIdentifier.getLiteralSystemId(), null, inputStream, null); - return inputSource; + resourceIdentifier.setLiteralSystemId(literalSystemId.replace('\\','/')); } - else - { // TODO cs: In revision 1.1 we explicitly opened a stream to ensure // file I/O problems produced messages. I've remove this fudge for now // since I can't seem to reproduce the problem it was intended to fix. // I'm hoping the newer Xerces code base has fixed this problem and the fudge is defunct. return XMLValidator._internalResolveEntity(uriresolver, resourceIdentifier); - } + } } }