| /******************************************************************************* |
| * 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); |
| |
| } |
| } |
| } |