/******************************************************************************* * Copyright (c) 2001, 2007 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 * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * David Carver, Standards for Technology in Automotive Retail, bug 1147033 *******************************************************************************/ package org.eclipse.wst.xsd.core.internal.validation; import java.io.IOException; import java.io.InputStream; 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.w3c.dom.DOMError; /** * The XSDValidator will validate XSD files. */ public class XSDValidator { protected URIResolver uriresolver = null; public ValidationReport validate(String uri) { return validate(uri, null); } public ValidationReport validate(String uri, InputStream inputStream) { return validate(uri, null, 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. * @param configuration * A configuration for this validation run. */ public ValidationReport validate(String uri, InputStream inputStream, XSDValidationConfiguration configuration) { if(configuration == null) { configuration = new XSDValidationConfiguration(); } 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.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); if(configuration.getFeature(XSDValidationConfiguration.HONOUR_ALL_SCHEMA_LOCATIONS)) { try { grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + "honour-all-schemaLocations", true); //$NON-NLS-1$ } catch (Exception e) { // catch the exception and ignore } } if(configuration.getFeature(XSDValidationConfiguration.FULL_SCHEMA_CONFORMANCE)) { try { grammarPreparser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING, true); } catch (Exception e) { // ignore since we don't want to set it or can't. } } grammarPreparser.setErrorHandler(errorHandler); if (uriresolver != null) { XSDEntityResolver resolver = new XSDEntityResolver(uriresolver, uri); if (resolver != null) { grammarPreparser.setEntityResolver(resolver); } } 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); } } catch (Exception e) { // TODO: log error. //System.out.println(e); } return valinfo; } /** * Set the URI resolver to use with XSD validation. * * @param uriresolver * The URI resolver to use. */ public void setURIResolver(URIResolver uriresolver) { this.uriresolver = uriresolver; } /** * The XSDErrorHandler handle Xerces parsing errors and puts the errors * into the given ValidationInfo object. */ protected class XSDErrorHandler implements XMLErrorHandler { private final ValidationInfo valinfo; public XSDErrorHandler(ValidationInfo valinfo) { this.valinfo = valinfo; } /** * 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(String errorKey, XMLParseException exception, int severity) { String systemId = exception.getExpandedSystemId(); if (systemId != null) { if (severity == DOMError.SEVERITY_WARNING) { valinfo.addWarning(exception.getLocalizedMessage(), exception.getLineNumber(), exception.getColumnNumber(), systemId); } else { valinfo.addError(exception.getLocalizedMessage(), exception.getLineNumber(), exception.getColumnNumber(), systemId, errorKey, null); } } } /* (non-Javadoc) * @see org.apache.xerces.xni.parser.XMLErrorHandler#warning(java.lang.String, java.lang.String, org.apache.xerces.xni.parser.XMLParseException) */ public void warning(String domain, String key, XMLParseException exception) throws XNIException { addValidationMessage(key, exception, DOMError.SEVERITY_WARNING); } /* (non-Javadoc) * @see org.apache.xerces.xni.parser.XMLErrorHandler#error(java.lang.String, java.lang.String, org.apache.xerces.xni.parser.XMLParseException) */ public void error(String domain, String key, XMLParseException exception) throws XNIException { addValidationMessage(key, exception, DOMError.SEVERITY_ERROR); } /* (non-Javadoc) * @see org.apache.xerces.xni.parser.XMLErrorHandler#fatalError(java.lang.String, java.lang.String, org.apache.xerces.xni.parser.XMLParseException) */ public void fatalError(String domain, String key, XMLParseException exception) throws XNIException { addValidationMessage(key, exception, DOMError.SEVERITY_FATAL_ERROR); } } /** * The XSDEntityResolver wraps an idresolver to provide entity resolution to * the XSD validator. */ protected class XSDEntityResolver implements XMLEntityResolver { private URIResolver uriresolver = null; /** * Constructor. * * @param idresolver * The idresolver this entity resolver wraps. * @param baselocation The base location to resolve with. */ public XSDEntityResolver(URIResolver uriresolver, String baselocation) { this.uriresolver = uriresolver; } /* (non-Javadoc) * @see org.apache.xerces.xni.parser.XMLEntityResolver#resolveEntity(org.apache.xerces.xni.XMLResourceIdentifier) */ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) throws XNIException, IOException { String literalSystemId = resourceIdentifier.getLiteralSystemId(); if(literalSystemId != null) { resourceIdentifier.setLiteralSystemId(literalSystemId.replace('\\','/')); } // 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); } } }