blob: ad698885c01841803166c7cb33665d1c28bb61ab [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2009 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 - STAR - [205989] - [validation] validate XML after XInclude resolution
*******************************************************************************/
package org.eclipse.wst.xml.core.internal.validation;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.ConnectException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.xerces.impl.XMLErrorReporter;
import org.apache.xerces.impl.msg.XMLMessageFormatter;
import org.apache.xerces.parsers.XIncludeAwareParserConfiguration;
import org.apache.xerces.xni.Augmentations;
import org.apache.xerces.xni.NamespaceContext;
import org.apache.xerces.xni.QName;
import org.apache.xerces.xni.XMLAttributes;
import org.apache.xerces.xni.XMLLocator;
import org.apache.xerces.xni.XMLResourceIdentifier;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.parser.XMLEntityResolver;
import org.apache.xerces.xni.parser.XMLInputSource;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver;
import org.eclipse.wst.common.uriresolver.internal.util.URIHelper;
import org.eclipse.wst.validation.ValidationResult;
import org.eclipse.wst.xml.core.internal.Logger;
import org.eclipse.wst.xml.core.internal.validation.core.LazyURLInputStream;
import org.eclipse.wst.xml.core.internal.validation.core.NestedValidatorContext;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.DeclHandler;
import org.xml.sax.helpers.DefaultHandler;
/**
* This class performs validation using a xerces sax parser.
* Here's a quick overview of the details :
* - an ErrorHandler is used to collect errors into a list (so they may be displayed by the UI)
* - an EntityResolver is used along with the xerces "external-schemaLocation" property to implement XML Catalog support
*/
public class XMLValidator
{
protected URIResolver uriResolver = null;
protected Hashtable ingoredErrorKeyTable = new Hashtable();
protected Set adjustLocationErrorKeySet = new TreeSet();
protected static final String IGNORE_ALWAYS = "IGNORE_ALWAYS"; //$NON-NLS-1$
protected static final String IGNORE_IF_DTD_WITHOUT_ELEMENT_DECL = "IGNORE_IF_DTD_WITHOUT_ELEMENT_DECL"; //$NON-NLS-1$
protected static final String PREMATURE_EOF = "PrematureEOF"; //$NON-NLS-1$
protected static final String ROOT_ELEMENT_TYPE_MUST_MATCH_DOCTYPEDECL = "RootElementTypeMustMatchDoctypedecl"; //$NON-NLS-1$
protected static final String MSG_ELEMENT_NOT_DECLARED = "MSG_ELEMENT_NOT_DECLARED"; //$NON-NLS-1$
// WTP XML validator specific key.
protected static final String NO_GRAMMAR_FOUND = "NO_GRAMMAR_FOUND"; //$NON-NLS-1$
private static final String FILE_NOT_FOUND_KEY = "FILE_NOT_FOUND"; //$NON-NLS-1$
/**
* Constructor.
*/
public XMLValidator()
{
// Here we add some error keys that we need to filter out when we're validation
// against a DTD without any element declarations.
ingoredErrorKeyTable.put(PREMATURE_EOF, IGNORE_ALWAYS);
ingoredErrorKeyTable.put(ROOT_ELEMENT_TYPE_MUST_MATCH_DOCTYPEDECL, IGNORE_IF_DTD_WITHOUT_ELEMENT_DECL);
ingoredErrorKeyTable.put(MSG_ELEMENT_NOT_DECLARED, IGNORE_IF_DTD_WITHOUT_ELEMENT_DECL);
// Here we add some error keys that we need to adjust the location information for.
// The location information will be adjusted to place the message on the line of the starting
// element instead of on the line of the closing element.
adjustLocationErrorKeySet.add("MSG_CONTENT_INVALID");
adjustLocationErrorKeySet.add("MSG_CONTENT_INCOMPLETE");
adjustLocationErrorKeySet.add("cvc-complex-type.2.4.b");
adjustLocationErrorKeySet.add("cvc-complex-type.2.3");
}
/**
* Set the URI Resolver to use.
*
* @param uriResolver The URI Resolver to use.
*/
public void setURIResolver(URIResolver uriResolver)
{
this.uriResolver = uriResolver;
//entityResolver = new MyEntityResolver(uriResolver);
}
/**
* Create an XML Reader.
*
* @return The newly created XML reader or null if unsuccessful.
* @throws Exception
*/
protected XMLReader createXMLReader(final XMLValidationInfo valinfo, XMLEntityResolver entityResolver) throws Exception
{
XMLReader reader = null;
// move to Xerces-2... add the contextClassLoader stuff
ClassLoader prevClassLoader = Thread.currentThread().getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
MyStandardParserConfiguration configuration = new MyStandardParserConfiguration(valinfo);
reader = new org.apache.xerces.parsers.SAXParser(configuration)
{
private XMLLocator locator = null;
/* (non-Javadoc)
* @see org.apache.xerces.parsers.AbstractSAXParser#startDocument(org.apache.xerces.xni.XMLLocator, java.lang.String, org.apache.xerces.xni.NamespaceContext, org.apache.xerces.xni.Augmentations)
*/
public void startDocument(org.apache.xerces.xni.XMLLocator theLocator, java.lang.String encoding, NamespaceContext nscontext, org.apache.xerces.xni.Augmentations augs)
{
locator = theLocator;
valinfo.setXMLLocator(theLocator);
super.startDocument(theLocator, encoding, nscontext, augs);
}
/* (non-Javadoc)
* @see org.apache.xerces.parsers.AbstractSAXParser#startElement(org.apache.xerces.xni.QName, org.apache.xerces.xni.XMLAttributes, org.apache.xerces.xni.Augmentations)
*/
public void startElement(QName arg0, XMLAttributes arg1, Augmentations arg2) throws XNIException
{
valinfo.getStartElementLocations().push(new LocationCoordinate(locator.getLineNumber(), locator.getColumnNumber()));
super.startElement(arg0, arg1, arg2);
}
/* (non-Javadoc)
* @see org.apache.xerces.parsers.AbstractSAXParser#endElement(org.apache.xerces.xni.QName, org.apache.xerces.xni.Augmentations)
*/
public void endElement(QName arg0, Augmentations arg1) throws XNIException {
super.endElement(arg0, arg1);
valinfo.getStartElementLocations().pop();
}
};
reader.setFeature("http://apache.org/xml/features/continue-after-fatal-error", false); //$NON-NLS-1$
reader.setFeature("http://xml.org/sax/features/namespace-prefixes", valinfo.isNamespaceEncountered()); //$NON-NLS-1$
reader.setFeature("http://xml.org/sax/features/namespaces", valinfo.isNamespaceEncountered()); //$NON-NLS-1$
reader.setFeature("http://xml.org/sax/features/validation", valinfo.isGrammarEncountered()); //$NON-NLS-1$
reader.setFeature("http://apache.org/xml/features/validation/schema", valinfo.isGrammarEncountered()); //$NON-NLS-1$
reader.setContentHandler(new DefaultHandler()
{
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
valinfo.getErrorCustomizationManager().startElement(uri, localName);
}
public void endElement(String uri, String localName, String qName) throws SAXException {
valinfo.getErrorCustomizationManager().endElement(uri, localName);
}
});
// MH make sure validation works even when a customer entityResolver is note set (i.e. via setURIResolver())
if (entityResolver != null)
{
reader.setProperty("http://apache.org/xml/properties/internal/entity-resolver", entityResolver); //$NON-NLS-1$
}
reader.setProperty("http://xml.org/sax/properties/declaration-handler", new MyDeclHandler()); //$NON-NLS-1$
}
catch(Exception e)
{
Logger.logException(e);
//e.printStackTrace();
}
finally
{
Thread.currentThread().setContextClassLoader(prevClassLoader);
}
return reader;
}
/**
* Validate the file located at the given URI.
*
* @param uri The URI of the file to validate.
* @return Returns an XML validation report.
*/
public XMLValidationReport validate(String uri)
{
return validate(uri, null, new XMLValidationConfiguration());
}
final String createStringForInputStream(InputStream inputStream)
{
// Here we are reading the file and storing to a stringbuffer.
StringBuffer fileString = new StringBuffer();
try
{
InputStreamReader inputReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader reader = new BufferedReader(inputReader);
char[] chars = new char[1024];
int numberRead = reader.read(chars);
while (numberRead != -1)
{
fileString.append(chars, 0, numberRead);
numberRead = reader.read(chars);
}
}
catch (Exception e)
{
//TODO: log error message
//e.printStackTrace();
}
return fileString.toString();
}
/**
* Validate the inputStream
*
* @param uri The URI of the file to validate.
* @param the inputStream of the file to validate
* @return Returns an XML validation report.
*/
public XMLValidationReport validate(String uri, InputStream inputStream)
{
return validate(uri, inputStream, new XMLValidationConfiguration());
}
/**
* Validate the inputStream
*
* @param uri
* The URI of the file to validate.
* @param inputstream
* The inputStream of the file to validate
* @param configuration
* A configuration for this validation session.
* @return
* Returns an XML validation report.
*/
public XMLValidationReport validate(String uri, InputStream inputStream, XMLValidationConfiguration configuration)
{
return validate(uri, inputStream, configuration, null);
}
/**
* Validate the inputStream
*
* @param uri
* The URI of the file to validate.
* @param inputstream
* The inputStream of the file to validate
* @param configuration
* A configuration for this validation session.
* @param result
* The validation result
* @return
* Returns an XML validation report.
*/
public XMLValidationReport validate(String uri, InputStream inputStream, XMLValidationConfiguration configuration, ValidationResult result)
{
return validate(uri, inputStream, configuration, null, null);
}
/**
* Validate the inputStream
*
* @param uri
* The URI of the file to validate.
* @param inputstream
* The inputStream of the file to validate
* @param configuration
* A configuration for this validation session.
* @param result
* The validation result
* @param context
* The validation context
* @return
* Returns an XML validation report.
*/
public XMLValidationReport validate(String uri, InputStream inputStream, XMLValidationConfiguration configuration, ValidationResult result, NestedValidatorContext context)
{
String grammarFile = "";
Reader reader1 = null; // Used for the preparse.
Reader reader2 = null; // Used for validation parse.
if (inputStream != null)
{
String string = createStringForInputStream(inputStream);
reader1 = new StringReader(string);
reader2 = new StringReader(string);
}
XMLValidationInfo valinfo = new XMLValidationInfo(uri);
MyEntityResolver entityResolver = new MyEntityResolver(uriResolver, context);
ValidatorHelper helper = new ValidatorHelper();
try
{
helper.computeValidationInformation(uri, reader1, uriResolver);
valinfo.setDTDEncountered(helper.isDTDEncountered);
valinfo.setElementDeclarationCount(helper.numDTDElements);
valinfo.setNamespaceEncountered(helper.isNamespaceEncountered);
valinfo.setGrammarEncountered(helper.isGrammarEncountered);
XMLReader reader = createXMLReader(valinfo, entityResolver);
// Set the configuration option
if (configuration.getFeature(XMLValidationConfiguration.HONOUR_ALL_SCHEMA_LOCATIONS))
{
reader.setFeature("http://apache.org/xml/features/honour-all-schemaLocations", true); //$NON-NLS-1$
}
if (configuration.getFeature(XMLValidationConfiguration.USE_XINCLUDE))
{
reader.setFeature("http://apache.org/xml/features/xinclude", true); //$NON-NLS-1$
}
XMLErrorHandler errorhandler = new XMLErrorHandler(valinfo);
reader.setErrorHandler(errorhandler);
InputSource inputSource = new InputSource(uri);
inputSource.setCharacterStream(reader2);
reader.parse(inputSource);
if(configuration.getIntFeature(XMLValidationConfiguration.INDICATE_NO_GRAMMAR) > 0 &&
valinfo.isValid() && !helper.isGrammarEncountered)
{
if(configuration.getIntFeature(XMLValidationConfiguration.INDICATE_NO_GRAMMAR) == 1)
valinfo.addWarning(XMLValidationMessages._WARN_NO_GRAMMAR, 1, 0, uri, NO_GRAMMAR_FOUND, null);
else // 2
valinfo.addError(XMLValidationMessages._WARN_NO_GRAMMAR, 1, 0, uri, NO_GRAMMAR_FOUND, null);
}
if (helper.isDTDEncountered)
grammarFile = entityResolver.getLocation();
else
grammarFile = helper.schemaLocationString;
}
catch (SAXParseException saxParseException)
{
// These errors are caught by the error handler.
//addValidationMessage(valinfo, saxParseException);
}
catch (IOException ioException)
{
addValidationMessage(valinfo, ioException);
}
catch (Exception exception)
{
Logger.logException(exception.getLocalizedMessage(), exception);
}
// Now set up the dependencies
// Wrap with try catch so that if something wrong happens, validation can
// still proceed as before
if (result != null)
{
try
{
IResource resource = getWorkspaceFileFromLocation(grammarFile);
ArrayList resources = new ArrayList();
if (resource != null)
resources.add(resource);
result.setDependsOn((IResource [])resources.toArray(new IResource [0]));
}
catch (Exception e)
{
Logger.logException(e.getLocalizedMessage(), e);
}
}
return valinfo;
}
/**
* Add a validation message to the specified list.
*
* @param valinfo The validation info object to add the error to.
* @param exception The exception that contains the validation information.
*/
protected void addValidationMessage(XMLValidationInfo valinfo, IOException exception)
{
String validationMessageStr = exception.getMessage();
Throwable cause = exception.getCause() != null ? exception.getCause() : exception;
while(validationMessageStr == null && cause != null){
String localizedMessage = cause.getLocalizedMessage();
cause = cause.getCause();
if(cause == null && localizedMessage != null )
{
validationMessageStr = localizedMessage;
}
}
if (validationMessageStr != null)
{
if (cause instanceof FileNotFoundException)
{
validationMessageStr = NLS.bind(XMLValidationMessages._UI_PROBLEMS_VALIDATING_FILE_NOT_FOUND, new Object [] { validationMessageStr });
}
else if (cause instanceof UnknownHostException)
{
validationMessageStr = NLS.bind(XMLValidationMessages._UI_PROBLEMS_VALIDATING_UNKNOWN_HOST, new Object [] { validationMessageStr });
}
else if(cause instanceof ConnectException)
{
validationMessageStr = XMLValidationMessages._UI_PROBLEMS_CONNECTION_REFUSED;
}
}
if (validationMessageStr != null)
{
XMLLocator locator = valinfo.getXMLLocator();
valinfo.addWarning(validationMessageStr, locator != null ? locator.getLineNumber() : 1, locator != null ? locator.getColumnNumber() : 0, valinfo.getFileURI(), FILE_NOT_FOUND_KEY, null);
}
}
/**
* Add a validation message to the specified list.
*
* @param valinfo The validation info object to add the error to.
* @param exception The exception that contains the validation information.
*/
protected void addValidationMessage(XMLValidationInfo valinfo, SAXParseException exception)
{
if (exception.getMessage() != null)
{
valinfo.addError(exception.getLocalizedMessage(), exception.getLineNumber(), exception.getColumnNumber(), exception.getSystemId());
}
}
/**
* A custom entity resolver that uses the URI resolver specified to resolve entities.
*/
protected class MyEntityResolver implements XMLEntityResolver
{
private URIResolver uriResolver;
private String resolvedDTDLocation;
private NestedValidatorContext context;
/**
* Constructor.
*
* @param uriResolver The URI resolver to use with this entity resolver.
* @param context The XML validator context.
*/
public MyEntityResolver(URIResolver uriResolver, NestedValidatorContext context)
{
this.uriResolver = uriResolver;
this.context = context;
}
/* (non-Javadoc)
* @see org.apache.xerces.xni.parser.XMLEntityResolver#resolveEntity(org.apache.xerces.xni.XMLResourceIdentifier)
*/
public XMLInputSource resolveEntity(XMLResourceIdentifier rid) throws XNIException, IOException
{
XMLInputSource inputSource = _internalResolveEntity(uriResolver, rid, context);
if (inputSource != null)
{
resolvedDTDLocation = inputSource.getSystemId();
}
return inputSource;
}
public String getLocation()
{
return resolvedDTDLocation;
}
}
// cs : I've refactored the common SAX based resolution code into this method for use by other validators
// (i.e. XML Schema, WSDL etc). The other approach is maintain a copy for each validator that has
// identical code. In any case we should strive to ensure that the validators perform resolution consistently.
public static XMLInputSource _internalResolveEntity(URIResolver uriResolver, XMLResourceIdentifier rid) throws IOException
{
return _internalResolveEntity(uriResolver, rid, null);
}
public static XMLInputSource _internalResolveEntity(URIResolver uriResolver, XMLResourceIdentifier rid, NestedValidatorContext context) throws IOException
{
XMLInputSource is = null;
if (uriResolver != null)
{
String id = rid.getPublicId();
if(id == null)
{
id = rid.getNamespace();
}
String location = null;
if (id != null || rid.getLiteralSystemId() != null)
{
location = uriResolver.resolve(rid.getBaseSystemId(), id, rid.getLiteralSystemId());
}
if (location != null)
{
String physical = uriResolver.resolvePhysicalLocation(rid.getBaseSystemId(), id, location);
// if physical is already a known bad uri, just go ahead and throw an exception
if (context instanceof XMLNestedValidatorContext)
{
XMLNestedValidatorContext xmlContext = ((XMLNestedValidatorContext)context);
if (xmlContext.isURIMarkedInaccessible(physical))
{
throw new FileNotFoundException(physical);
}
}
is = new XMLInputSource(rid.getPublicId(), location, location);
// This block checks that the file exists. If it doesn't we need to throw
// an exception so Xerces will report an error. note: This may not be
// necessary with all versions of Xerces but has specifically been
// experienced with the version included in IBM's 1.4.2 JDK.
InputStream isTemp = null;
try
{
isTemp = new URL(physical).openStream();
}
catch (IOException e)
{
// physical was a bad url, so cache it so we know next time
if (context instanceof XMLNestedValidatorContext)
{
XMLNestedValidatorContext xmlContext = ((XMLNestedValidatorContext)context);
xmlContext.markURIInaccessible(physical);
}
throw e;
}
finally
{
if(isTemp != null)
{
isTemp.close();
}
}
is.setByteStream(new LazyURLInputStream(physical));
}
}
return is;
}
/**
* An error handler to catch errors encountered while parsing the XML document.
*/
protected class XMLErrorHandler implements org.xml.sax.ErrorHandler
{
private final int ERROR = 0;
private final int WARNING = 1;
private XMLValidationInfo valinfo;
/**
* Constructor.
*
* @param valinfo The XML validation info object that will hold the validation messages.
*/
public XMLErrorHandler(XMLValidationInfo valinfo)
{
this.valinfo = valinfo;
}
/**
* Add a validation message with the given severity.
*
* @param exception The exception that contains the message.
* @param severity The severity of the message.
*/
protected void addValidationMessage(SAXParseException exception, int severity)
{
if(exception.getSystemId() != null)
{
int lineNumber = exception.getLineNumber();
int columnNumber = exception.getColumnNumber();
// For the following three errors the line number will be modified to use that of the start
// tag instead of the end tag.
String currentErrorKey = valinfo.currentErrorKey;
if (currentErrorKey != null && adjustLocationErrorKeySet.contains(currentErrorKey))
{
LocationCoordinate adjustedCoordinates = (LocationCoordinate)valinfo.getStartElementLocations().peek();
lineNumber = adjustedCoordinates.getLineNumber();
columnNumber = adjustedCoordinates.getColumnNumner();
}
if(severity == WARNING)
{
valinfo.addWarning(exception.getLocalizedMessage(), lineNumber, columnNumber, exception.getSystemId());
}
else
{
valinfo.addError(exception.getLocalizedMessage(), lineNumber, columnNumber, exception.getSystemId(), valinfo.getCurrentErrorKey(), valinfo.getMessageArguments());
}
}
}
/* (non-Javadoc)
* @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
*/
public void error(SAXParseException exception) throws SAXException
{
addValidationMessage(exception, ERROR);
}
/* (non-Javadoc)
* @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
*/
public void fatalError(SAXParseException exception) throws SAXException
{
addValidationMessage(exception, ERROR);
}
/* (non-Javadoc)
* @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
*/
public void warning(SAXParseException exception) throws SAXException
{
addValidationMessage(exception, WARNING);
}
}
/**
* This class is used to count the elementDecls that are encountered in a DTD.
*/
protected class MyDeclHandler implements DeclHandler
{
/**
* Constructor.
*
* @param valinfo The XMLValidationInfo object that will count the declarations.
*/
public MyDeclHandler()
{
}
/* (non-Javadoc)
* @see org.xml.sax.ext.DeclHandler#attributeDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
*/
public void attributeDecl(String eName, String aName, String type, String valueDefault, String value)
{
}
/* (non-Javadoc)
* @see org.xml.sax.ext.DeclHandler#elementDecl(java.lang.String, java.lang.String)
*/
public void elementDecl(String name, String model)
{
//valinfo.increaseElementDeclarationCount();
}
/* (non-Javadoc)
* @see org.xml.sax.ext.DeclHandler#externalEntityDecl(java.lang.String, java.lang.String, java.lang.String)
*/
public void externalEntityDecl(String name, String publicId, String systemId)
{
}
/* (non-Javadoc)
* @see org.xml.sax.ext.DeclHandler#internalEntityDecl(java.lang.String, java.lang.String)
*/
public void internalEntityDecl(String name, String value)
{
}
}
/**
* A XIncludeAwareParserConfiguration that creates an error reporter which can ignore
* DTD error messages for DTD's with no elements defined.
*/
protected class MyStandardParserConfiguration extends XIncludeAwareParserConfiguration
{
XMLValidationInfo valinfo = null;
List reportedExceptions = new ArrayList();
/**
* Constructor.
*
* @param valinfo The XMLValidationInfo object to use.
*/
public MyStandardParserConfiguration(XMLValidationInfo valinfo)
{
this.valinfo = valinfo;
XMLErrorReporter errorReporter = createErrorReporter();
if (errorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) {
XMLMessageFormatter xmft = new XMLMessageFormatter();
errorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft);
errorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft);
}
fErrorReporter = errorReporter;
setProperty(ERROR_REPORTER, errorReporter);
fCommonComponents.remove(fErrorReporter);
fCommonComponents.add(fErrorReporter);
}
/* (non-Javadoc)
* @see org.apache.xerces.parsers.DTDConfiguration#createErrorReporter()
*/
protected XMLErrorReporter createErrorReporter()
{
return new XMLErrorReporter()
{
/* (non-Javadoc)
* @see org.apache.xerces.impl.XMLErrorReporter#reportError(java.lang.String, java.lang.String, java.lang.Object[], short)
*/
public void reportError(String domain, String key, Object[] arguments, short severity) throws XNIException
{
boolean reportError = true;
valinfo.setCurrentErrorKey(key);
valinfo.setMessageArguments(arguments);
String ignoreCondition = (String)ingoredErrorKeyTable.get(key);
if (ignoreCondition != null)
{
if (ignoreCondition.equals(XMLValidator.IGNORE_IF_DTD_WITHOUT_ELEMENT_DECL))
{
boolean isDTDWithoutElementDeclarationEncountered = valinfo.isDTDWithoutElementDeclarationEncountered();
reportError = !isDTDWithoutElementDeclarationEncountered;
}
else
{
reportError = false;
}
}
if ("schema_reference.4".equals(key) && arguments.length > 0) //$NON-NLS-1$
{
Object location = arguments[0];
if (location != null)
{
if(reportedExceptions.contains(location))
{
reportError = false;
}
else
{
reportedExceptions.add(location);
}
}
}
if (reportError)
{
super.reportError(domain, key, arguments, severity);
valinfo.getErrorCustomizationManager().considerReportedError(valinfo, key, arguments);
}
}
};
}
}
/**
* A line and column number coordinate.
*/
protected class LocationCoordinate
{
private int lineNo = -1;
private int columnNo = -1;
public LocationCoordinate(int lineNumber, int columnNumber)
{
this.lineNo = lineNumber;
this.columnNo = columnNumber;
}
public int getLineNumber()
{
return this.lineNo;
}
public int getColumnNumner()
{
return this.columnNo;
}
}
protected IResource getWorkspaceFileFromLocation(String location)
{
if (location == null) return null;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
// To canonicalize the EMF URI
IPath canonicalForm = new Path(location);
// Need to convert to absolute location...
IPath pathLocation = new Path(URIHelper.removeProtocol(canonicalForm.toString()));
// ...to find the resource file that is in the workspace
IResource resourceFile = workspace.getRoot().getFileForLocation(pathLocation);
// If the resource is resolved to a file from http, or a file outside
// the workspace, then we will just ignore it.
return resourceFile;
}
}