/*
* Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
*/
/*
* 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.
*/
package com.sun.org.apache.xerces.internal.impl.xs;
import com.sun.org.apache.xerces.internal.impl.Constants;
import com.sun.org.apache.xerces.internal.impl.RevalidationHandler;
import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
import com.sun.org.apache.xerces.internal.impl.dv.DatatypeException;
import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo;
import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
import com.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl;
import com.sun.org.apache.xerces.internal.impl.validation.ConfigurableValidationState;
import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
import com.sun.org.apache.xerces.internal.impl.validation.ValidationState;
import com.sun.org.apache.xerces.internal.impl.xs.identity.Field;
import com.sun.org.apache.xerces.internal.impl.xs.identity.FieldActivator;
import com.sun.org.apache.xerces.internal.impl.xs.identity.IdentityConstraint;
import com.sun.org.apache.xerces.internal.impl.xs.identity.KeyRef;
import com.sun.org.apache.xerces.internal.impl.xs.identity.Selector;
import com.sun.org.apache.xerces.internal.impl.xs.identity.UniqueOrKey;
import com.sun.org.apache.xerces.internal.impl.xs.identity.ValueStore;
import com.sun.org.apache.xerces.internal.impl.xs.identity.XPathMatcher;
import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder;
import com.sun.org.apache.xerces.internal.impl.xs.models.CMNodeFactory;
import com.sun.org.apache.xerces.internal.impl.xs.models.XSCMValidator;
import com.sun.org.apache.xerces.internal.impl.xs.util.XS10TypeHelper;
import com.sun.org.apache.xerces.internal.parsers.XMLParser;
import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
import com.sun.org.apache.xerces.internal.util.IntStack;
import com.sun.org.apache.xerces.internal.util.SymbolTable;
import com.sun.org.apache.xerces.internal.util.URI.MalformedURIException;
import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
import com.sun.org.apache.xerces.internal.util.XMLChar;
import com.sun.org.apache.xerces.internal.util.XMLSymbols;
import com.sun.org.apache.xerces.internal.xni.Augmentations;
import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
import com.sun.org.apache.xerces.internal.xni.QName;
import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
import com.sun.org.apache.xerces.internal.xni.XMLLocator;
import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
import com.sun.org.apache.xerces.internal.xni.XMLString;
import com.sun.org.apache.xerces.internal.xni.XNIException;
import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter;
import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
import com.sun.org.apache.xerces.internal.xs.ShortList;
import com.sun.org.apache.xerces.internal.xs.StringList;
import com.sun.org.apache.xerces.internal.xs.XSConstants;
import com.sun.org.apache.xerces.internal.xs.XSObjectList;
import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.Vector;
import javax.xml.XMLConstants;
import jdk.xml.internal.JdkXmlUtils;
/**
* The XML Schema validator. The validator implements a document
* filter: receiving document events from the scanner; validating
* the content and structure; augmenting the InfoSet, if applicable;
* and notifying the parser of the information resulting from the
* validation process.
*
* This component requires the following features and properties from the
* component manager that uses it:
*
*
* @xerces.internal
*
* @author Sandy Gao IBM
* @author Elena Litani IBM
* @author Andy Clark IBM
* @author Neeraj Bajaj, Sun Microsystems, inc.
* @LastModified: Nov 2017
*/
public class XMLSchemaValidator
implements XMLComponent, XMLDocumentFilter, FieldActivator, RevalidationHandler, XSElementDeclHelper {
//
// Constants
//
private static final boolean DEBUG = false;
// feature identifiers
/** Feature identifier: validation. */
protected static final String VALIDATION =
Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
/** Feature identifier: validation. */
protected static final String SCHEMA_VALIDATION =
Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
/** Feature identifier: schema full checking*/
protected static final String SCHEMA_FULL_CHECKING =
Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING;
/** Feature identifier: dynamic validation. */
protected static final String DYNAMIC_VALIDATION =
Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;
/** Feature identifier: expose schema normalized value */
protected static final String NORMALIZE_DATA =
Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE;
/** Feature identifier: send element default value via characters() */
protected static final String SCHEMA_ELEMENT_DEFAULT =
Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT;
/** Feature identifier: augment PSVI */
protected static final String SCHEMA_AUGMENT_PSVI =
Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI;
/** Feature identifier: whether to recognize java encoding names */
protected static final String ALLOW_JAVA_ENCODINGS =
Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
/** Feature identifier: standard uri conformant feature. */
protected static final String STANDARD_URI_CONFORMANT_FEATURE =
Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
/** Feature: generate synthetic annotations */
protected static final String GENERATE_SYNTHETIC_ANNOTATIONS =
Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
/** Feature identifier: validate annotations. */
protected static final String VALIDATE_ANNOTATIONS =
Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE;
/** Feature identifier: honour all schemaLocations */
protected static final String HONOUR_ALL_SCHEMALOCATIONS =
Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;
/** Feature identifier: use grammar pool only */
protected static final String USE_GRAMMAR_POOL_ONLY =
Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
/** Feature identifier: whether to continue parsing a schema after a fatal error is encountered */
protected static final String CONTINUE_AFTER_FATAL_ERROR =
Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
protected static final String PARSER_SETTINGS =
Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
/** Feature identifier: namespace growth */
protected static final String NAMESPACE_GROWTH =
Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE;
/** Feature identifier: tolerate duplicates */
protected static final String TOLERATE_DUPLICATES =
Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE;
/** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */
protected static final String IGNORE_XSI_TYPE =
Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE;
/** Feature identifier: whether to ignore ID/IDREF errors */
protected static final String ID_IDREF_CHECKING =
Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE;
/** Feature identifier: whether to ignore unparsed entity errors */
protected static final String UNPARSED_ENTITY_CHECKING =
Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE;
/** Feature identifier: whether to ignore identity constraint errors */
protected static final String IDENTITY_CONSTRAINT_CHECKING =
Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE;
protected static final String REPORT_WHITESPACE =
Constants.SUN_SCHEMA_FEATURE_PREFIX + Constants.SUN_REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE;
// property identifiers
/** Property identifier: symbol table. */
public static final String SYMBOL_TABLE =
Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
/** Property identifier: error reporter. */
public static final String ERROR_REPORTER =
Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
/** Property identifier: entity resolver. */
public static final String ENTITY_RESOLVER =
Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
/** Property identifier: grammar pool. */
public static final String XMLGRAMMAR_POOL =
Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
protected static final String VALIDATION_MANAGER =
Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
protected static final String ENTITY_MANAGER =
Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
/** Property identifier: schema location. */
protected static final String SCHEMA_LOCATION =
Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION;
/** Property identifier: no namespace schema location. */
protected static final String SCHEMA_NONS_LOCATION =
Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION;
/** Property identifier: JAXP schema source. */
protected static final String JAXP_SCHEMA_SOURCE =
Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
/** Property identifier: JAXP schema language. */
protected static final String JAXP_SCHEMA_LANGUAGE =
Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE;
/** Property identifier: root type definition. */
protected static final String ROOT_TYPE_DEF =
Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_TYPE_DEFINITION_PROPERTY;
/** Property identifier: root element declaration. */
protected static final String ROOT_ELEMENT_DECL =
Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_ELEMENT_DECLARATION_PROPERTY;
/** Property identifier: Schema DV Factory */
protected static final String SCHEMA_DV_FACTORY =
Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY;
/** Property identifier: Security property manager. */
private static final String XML_SECURITY_PROPERTY_MANAGER =
Constants.XML_SECURITY_PROPERTY_MANAGER;
protected static final String USE_SERVICE_MECHANISM = Constants.ORACLE_FEATURE_SERVICE_MECHANISM;
protected static final String USE_CATALOG = XMLConstants.USE_CATALOG;
// recognized features and properties
/** Recognized features. */
private static final String[] RECOGNIZED_FEATURES =
{
VALIDATION,
SCHEMA_VALIDATION,
DYNAMIC_VALIDATION,
SCHEMA_FULL_CHECKING,
ALLOW_JAVA_ENCODINGS,
CONTINUE_AFTER_FATAL_ERROR,
STANDARD_URI_CONFORMANT_FEATURE,
GENERATE_SYNTHETIC_ANNOTATIONS,
VALIDATE_ANNOTATIONS,
HONOUR_ALL_SCHEMALOCATIONS,
USE_GRAMMAR_POOL_ONLY,
IGNORE_XSI_TYPE,
ID_IDREF_CHECKING,
IDENTITY_CONSTRAINT_CHECKING,
UNPARSED_ENTITY_CHECKING,
NAMESPACE_GROWTH,
TOLERATE_DUPLICATES,
USE_SERVICE_MECHANISM,
USE_CATALOG
};
/** Feature defaults. */
private static final Boolean[] FEATURE_DEFAULTS = { null,
// NOTE: The following defaults are nulled out on purpose.
// If they are set, then when the XML Schema validator
// is constructed dynamically, these values may override
// those set by the application. This goes against the
// whole purpose of XMLComponent#getFeatureDefault but
// it can't be helped in this case. -Ac
// NOTE: Instead of adding default values here, add them (and
// the corresponding recognized features) to the objects
// that have an XMLSchemaValidator instance as a member,
// such as the parser configurations. -PM
null, //Boolean.FALSE,
null, //Boolean.FALSE,
null, //Boolean.FALSE,
null, //Boolean.FALSE,
null, //Boolean.FALSE,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
Boolean.TRUE,
JdkXmlUtils.USE_CATALOG_DEFAULT
};
/** Recognized properties. */
private static final String[] RECOGNIZED_PROPERTIES =
{
SYMBOL_TABLE,
ERROR_REPORTER,
ENTITY_RESOLVER,
VALIDATION_MANAGER,
SCHEMA_LOCATION,
SCHEMA_NONS_LOCATION,
JAXP_SCHEMA_SOURCE,
JAXP_SCHEMA_LANGUAGE,
ROOT_TYPE_DEF,
ROOT_ELEMENT_DECL,
SCHEMA_DV_FACTORY,
XML_SECURITY_PROPERTY_MANAGER,
JdkXmlUtils.CATALOG_DEFER,
JdkXmlUtils.CATALOG_FILES,
JdkXmlUtils.CATALOG_PREFER,
JdkXmlUtils.CATALOG_RESOLVE,
JdkXmlUtils.CDATA_CHUNK_SIZE
};
/** Property defaults. */
private static final Object[] PROPERTY_DEFAULTS =
{ null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, JdkXmlUtils.CDATA_CHUNK_SIZE_DEFAULT };
// this is the number of valuestores of each kind
// we expect an element to have. It's almost
// never > 1; so leave it at that.
protected static final int ID_CONSTRAINT_NUM = 1;
// xsi:* attribute declarations
static final XSAttributeDecl XSI_TYPE =
SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_TYPE);
static final XSAttributeDecl XSI_NIL =
SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NIL);
static final XSAttributeDecl XSI_SCHEMALOCATION =
SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_SCHEMALOCATION);
static final XSAttributeDecl XSI_NONAMESPACESCHEMALOCATION =
SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION);
//
// Data
//
/** current PSVI element info */
protected ElementPSVImpl fCurrentPSVI = new ElementPSVImpl();
// since it is the responsibility of each component to an
// Augmentations parameter if one is null, to save ourselves from
// having to create this object continually, it is created here.
// If it is not present in calls that we're passing on, we *must*
// clear this before we introduce it into the pipeline.
protected final AugmentationsImpl fAugmentations = new AugmentationsImpl();
// this is included for the convenience of handleEndElement
protected XMLString fDefaultValue;
// Validation features
protected boolean fDynamicValidation = false;
protected boolean fSchemaDynamicValidation = false;
protected boolean fDoValidation = false;
protected boolean fFullChecking = false;
protected boolean fNormalizeData = true;
protected boolean fSchemaElementDefault = true;
protected boolean fAugPSVI = true;
protected boolean fIdConstraint = false;
protected boolean fUseGrammarPoolOnly = false;
// Namespace growth feature
protected boolean fNamespaceGrowth = false;
/** Schema type: None, DTD, Schema */
private String fSchemaType = null;
// to indicate whether we are in the scope of entity reference or CData
protected boolean fEntityRef = false;
protected boolean fInCDATA = false;
// Did we see only whitespace in element content?
protected boolean fSawOnlyWhitespaceInElementContent = false;
// properties
/** Symbol table. */
protected SymbolTable fSymbolTable;
/**
* While parsing a document, keep the location of the document.
*/
private XMLLocator fLocator;
/**
* A wrapper of the standard error reporter. We'll store all schema errors
* in this wrapper object, so that we can get all errors (error codes) of
* a specific element. This is useful for PSVI.
*/
protected final class XSIErrorReporter {
// the error reporter property
XMLErrorReporter fErrorReporter;
// store error codes; starting position of the errors for each element;
// number of element (depth); and whether to record error
Vector fErrors = new Vector<>();
int[] fContext = new int[INITIAL_STACK_SIZE];
int fContextCount;
// set the external error reporter, clear errors
public void reset(XMLErrorReporter errorReporter) {
fErrorReporter = errorReporter;
fErrors.removeAllElements();
fContextCount = 0;
}
// should be called when starting process an element or an attribute.
// store the starting position for the current context
public void pushContext() {
if (!fAugPSVI) {
return;
}
// resize array if necessary
if (fContextCount == fContext.length) {
int newSize = fContextCount + INC_STACK_SIZE;
int[] newArray = new int[newSize];
System.arraycopy(fContext, 0, newArray, 0, fContextCount);
fContext = newArray;
}
fContext[fContextCount++] = fErrors.size();
}
// should be called on endElement: get all errors of the current element
public String[] popContext() {
if (!fAugPSVI) {
return null;
}
// get starting position of the current element
int contextPos = fContext[--fContextCount];
// number of errors of the current element
int size = fErrors.size() - contextPos;
// if no errors, return null
if (size == 0)
return null;
// copy errors from the list to an string array
String[] errors = new String[size];
for (int i = 0; i < size; i++) {
errors[i] = fErrors.get(contextPos + i);
}
// remove errors of the current element
fErrors.setSize(contextPos);
return errors;
}
// should be called when an attribute is done: get all errors of
// this attribute, but leave the errors to the containing element
// also called after an element was strictly assessed.
public String[] mergeContext() {
if (!fAugPSVI) {
return null;
}
// get starting position of the current element
int contextPos = fContext[--fContextCount];
// number of errors of the current element
int size = fErrors.size() - contextPos;
// if no errors, return null
if (size == 0)
return null;
// copy errors from the list to an string array
String[] errors = new String[size];
for (int i = 0; i < size; i++) {
errors[i] = fErrors.get(contextPos + i);
}
// don't resize the vector: leave the errors for this attribute
// to the containing element
return errors;
}
public void reportError(String domain, String key, Object[] arguments, short severity)
throws XNIException {
String message = fErrorReporter.reportError(domain, key, arguments, severity);
if (fAugPSVI) {
fErrors.add(key);
fErrors.add(message);
}
} // reportError(String,String,Object[],short)
public void reportError(
XMLLocator location,
String domain,
String key,
Object[] arguments,
short severity)
throws XNIException {
String message = fErrorReporter.reportError(location, domain, key, arguments, severity);
if (fAugPSVI) {
fErrors.add(key);
fErrors.add(message);
}
} // reportError(XMLLocator,String,String,Object[],short)
}
/** Error reporter. */
protected final XSIErrorReporter fXSIErrorReporter = new XSIErrorReporter();
/** Entity resolver */
protected XMLEntityResolver fEntityResolver;
// updated during reset
protected ValidationManager fValidationManager = null;
protected ConfigurableValidationState fValidationState = new ConfigurableValidationState();
protected XMLGrammarPool fGrammarPool;
// schema location property values
protected String fExternalSchemas = null;
protected String fExternalNoNamespaceSchema = null;
//JAXP Schema Source property
protected Object fJaxpSchemaSource = null;
/** Schema Grammar Description passed, to give a chance to application to supply the Grammar */
protected final XSDDescription fXSDDescription = new XSDDescription();
protected final Map fLocationPairs = new HashMap<>();
// handlers
/** Document handler. */
protected XMLDocumentHandler fDocumentHandler;
protected XMLDocumentSource fDocumentSource;
boolean reportWhitespace = false;
//
// XMLComponent methods
//
/**
* Returns a list of feature identifiers that are recognized by
* this component. This method may return null if no features
* are recognized by this component.
*/
public String[] getRecognizedFeatures() {
return RECOGNIZED_FEATURES.clone();
} // getRecognizedFeatures():String[]
/**
* Sets the state of a feature. This method is called by the component
* manager any time after reset when a feature changes state.
*
* Note: Components should silently ignore features
* that do not affect the operation of the component.
*
* @param featureId The feature identifier.
* @param state The state of the feature.
*
* @throws SAXNotRecognizedException The component should not throw
* this exception.
* @throws SAXNotSupportedException The component should not throw
* this exception.
*/
public void setFeature(String featureId, boolean state) throws XMLConfigurationException {
} // setFeature(String,boolean)
/**
* Returns a list of property identifiers that are recognized by
* this component. This method may return null if no properties
* are recognized by this component.
*/
public String[] getRecognizedProperties() {
return RECOGNIZED_PROPERTIES.clone();
} // getRecognizedProperties():String[]
/**
* Sets the value of a property. This method is called by the component
* manager any time after reset when a property changes value.
*
* Note: Components should silently ignore properties
* that do not affect the operation of the component.
*
* @param propertyId The property identifier.
* @param value The value of the property.
*
* @throws SAXNotRecognizedException The component should not throw
* this exception.
* @throws SAXNotSupportedException The component should not throw
* this exception.
*/
public void setProperty(String propertyId, Object value) throws XMLConfigurationException {
if (propertyId.equals(ROOT_TYPE_DEF)) {
if (value == null) {
fRootTypeQName = null;
fRootTypeDefinition = null;
}
else if (value instanceof javax.xml.namespace.QName) {
fRootTypeQName = (javax.xml.namespace.QName) value;
fRootTypeDefinition = null;
}
else {
fRootTypeDefinition = (XSTypeDefinition) value;
fRootTypeQName = null;
}
}
else if (propertyId.equals(ROOT_ELEMENT_DECL)) {
if (value == null) {
fRootElementDeclQName = null;
fRootElementDeclaration = null;
}
else if (value instanceof javax.xml.namespace.QName) {
fRootElementDeclQName = (javax.xml.namespace.QName) value;
fRootElementDeclaration = null;
}
else {
fRootElementDeclaration = (XSElementDecl) value;
fRootElementDeclQName = null;
}
}
} // setProperty(String,Object)
/**
* Returns the default state for a feature, or null if this
* component does not want to report a default value for this
* feature.
*
* @param featureId The feature identifier.
*
* @since Xerces 2.2.0
*/
public Boolean getFeatureDefault(String featureId) {
for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
if (RECOGNIZED_FEATURES[i].equals(featureId)) {
return FEATURE_DEFAULTS[i];
}
}
return null;
} // getFeatureDefault(String):Boolean
/**
* Returns the default state for a property, or null if this
* component does not want to report a default value for this
* property.
*
* @param propertyId The property identifier.
*
* @since Xerces 2.2.0
*/
public Object getPropertyDefault(String propertyId) {
for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
return PROPERTY_DEFAULTS[i];
}
}
return null;
} // getPropertyDefault(String):Object
//
// XMLDocumentSource methods
//
/** Sets the document handler to receive information about the document. */
public void setDocumentHandler(XMLDocumentHandler documentHandler) {
fDocumentHandler = documentHandler;
// Init reportWhitespace for this handler
if (documentHandler instanceof XMLParser) {
try {
reportWhitespace =
((XMLParser) documentHandler).getFeature(REPORT_WHITESPACE);
}
catch (Exception e) {
reportWhitespace = false;
}
}
} // setDocumentHandler(XMLDocumentHandler)
/** Returns the document handler */
public XMLDocumentHandler getDocumentHandler() {
return fDocumentHandler;
} // setDocumentHandler(XMLDocumentHandler)
//
// XMLDocumentHandler methods
//
/** Sets the document source */
public void setDocumentSource(XMLDocumentSource source) {
fDocumentSource = source;
} // setDocumentSource
/** Returns the document source */
public XMLDocumentSource getDocumentSource() {
return fDocumentSource;
} // getDocumentSource
/**
* The start of the document.
*
* @param locator The system identifier of the entity if the entity
* is external, null otherwise.
* @param encoding The auto-detected IANA encoding name of the entity
* stream. This value will be null in those situations
* where the entity encoding is not auto-detected (e.g.
* internal entities or a document entity that is
* parsed from a java.io.Reader).
* @param namespaceContext
* The namespace context in effect at the
* start of this document.
* This object represents the current context.
* Implementors of this class are responsible
* for copying the namespace bindings from the
* the current context (and its parent contexts)
* if that information is important.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void startDocument(
XMLLocator locator,
String encoding,
NamespaceContext namespaceContext,
Augmentations augs)
throws XNIException {
fValidationState.setNamespaceSupport(namespaceContext);
fState4XsiType.setNamespaceSupport(namespaceContext);
fState4ApplyDefault.setNamespaceSupport(namespaceContext);
fLocator = locator;
handleStartDocument(locator, encoding);
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs);
}
} // startDocument(XMLLocator,String)
/**
* Notifies of the presence of an XMLDecl line in the document. If
* present, this method will be called immediately following the
* startDocument call.
*
* @param version The XML version.
* @param encoding The IANA encoding name of the document, or null if
* not specified.
* @param standalone The standalone value, or null if not specified.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
throws XNIException {
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.xmlDecl(version, encoding, standalone, augs);
}
} // xmlDecl(String,String,String)
/**
* Notifies of the presence of the DOCTYPE line in the document.
*
* @param rootElement The name of the root element.
* @param publicId The public identifier if an external DTD or null
* if the external DTD is specified using SYSTEM.
* @param systemId The system identifier if an external DTD, null
* otherwise.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void doctypeDecl(
String rootElement,
String publicId,
String systemId,
Augmentations augs)
throws XNIException {
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs);
}
} // doctypeDecl(String,String,String)
/**
* The start of an element.
*
* @param element The name of the element.
* @param attributes The element attributes.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
throws XNIException {
Augmentations modifiedAugs = handleStartElement(element, attributes, augs);
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.startElement(element, attributes, modifiedAugs);
}
} // startElement(QName,XMLAttributes, Augmentations)
/**
* An empty element.
*
* @param element The name of the element.
* @param attributes The element attributes.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
throws XNIException {
Augmentations modifiedAugs = handleStartElement(element, attributes, augs);
// in the case where there is a {value constraint}, and the element
// doesn't have any text content, change emptyElement call to
// start + characters + end
fDefaultValue = null;
// fElementDepth == -2 indicates that the schema validator was removed
// from the pipeline. then we don't need to call handleEndElement.
if (fElementDepth != -2)
modifiedAugs = handleEndElement(element, modifiedAugs);
// call handlers
if (fDocumentHandler != null) {
if (!fSchemaElementDefault || fDefaultValue == null) {
fDocumentHandler.emptyElement(element, attributes, modifiedAugs);
} else {
fDocumentHandler.startElement(element, attributes, modifiedAugs);
fDocumentHandler.characters(fDefaultValue, null);
fDocumentHandler.endElement(element, modifiedAugs);
}
}
} // emptyElement(QName,XMLAttributes, Augmentations)
/**
* Character content.
*
* @param text The content.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void characters(XMLString text, Augmentations augs) throws XNIException {
text = handleCharacters(text);
if (fSawOnlyWhitespaceInElementContent) {
fSawOnlyWhitespaceInElementContent = false;
if (!reportWhitespace) {
ignorableWhitespace(text, augs);
return;
}
}
// call handlers
if (fDocumentHandler != null) {
if (fNormalizeData && fUnionType) {
// for union types we can't normalize data
// thus we only need to send augs information if any;
// the normalized data for union will be send
// after normalization is performed (at the endElement())
if (augs != null)
fDocumentHandler.characters(fEmptyXMLStr, augs);
} else {
fDocumentHandler.characters(text, augs);
}
}
} // characters(XMLString)
/**
* Ignorable whitespace. For this method to be called, the document
* source must have some way of determining that the text containing
* only whitespace characters should be considered ignorable. For
* example, the validator can determine if a length of whitespace
* characters in the document are ignorable based on the element
* content model.
*
* @param text The ignorable whitespace.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
handleIgnorableWhitespace(text);
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.ignorableWhitespace(text, augs);
}
} // ignorableWhitespace(XMLString)
/**
* The end of an element.
*
* @param element The name of the element.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void endElement(QName element, Augmentations augs) throws XNIException {
// in the case where there is a {value constraint}, and the element
// doesn't have any text content, add a characters call.
fDefaultValue = null;
Augmentations modifiedAugs = handleEndElement(element, augs);
// call handlers
if (fDocumentHandler != null) {
if (!fSchemaElementDefault || fDefaultValue == null) {
fDocumentHandler.endElement(element, modifiedAugs);
} else {
fDocumentHandler.characters(fDefaultValue, null);
fDocumentHandler.endElement(element, modifiedAugs);
}
}
} // endElement(QName, Augmentations)
/**
* The start of a CDATA section.
*
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void startCDATA(Augmentations augs) throws XNIException {
// REVISIT: what should we do here if schema normalization is on??
fInCDATA = true;
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.startCDATA(augs);
}
} // startCDATA()
/**
* The end of a CDATA section.
*
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void endCDATA(Augmentations augs) throws XNIException {
// call handlers
fInCDATA = false;
if (fDocumentHandler != null) {
fDocumentHandler.endCDATA(augs);
}
} // endCDATA()
/**
* The end of the document.
*
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void endDocument(Augmentations augs) throws XNIException {
handleEndDocument();
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.endDocument(augs);
}
fLocator = null;
} // endDocument(Augmentations)
//
// DOMRevalidationHandler methods
//
public boolean characterData(String data, Augmentations augs) {
fSawText = fSawText || data.length() > 0;
// REVISIT: this methods basically duplicates implementation of
// handleCharacters(). We should be able to reuse some code
// if whitespace == -1 skip normalization, because it is a complexType
// or a union type.
if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) {
// normalize data
normalizeWhitespace(data, fWhiteSpace == XSSimpleType.WS_COLLAPSE);
fBuffer.append(fNormalizedStr.ch, fNormalizedStr.offset, fNormalizedStr.length);
} else {
if (fAppendBuffer)
fBuffer.append(data);
}
// When it's a complex type with element-only content, we need to
// find out whether the content contains any non-whitespace character.
boolean allWhiteSpace = true;
if (fCurrentType != null
&& fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
// data outside of element content
for (int i = 0; i < data.length(); i++) {
if (!XMLChar.isSpace(data.charAt(i))) {
allWhiteSpace = false;
fSawCharacters = true;
break;
}
}
}
}
return allWhiteSpace;
}
public void elementDefault(String data) {
// no-op
}
//
// XMLDocumentHandler and XMLDTDHandler methods
//
/**
* This method notifies the start of a general entity.
*
* Note: This method is not called for entity references
* appearing as part of attribute values.
*
* @param name The name of the general entity.
* @param identifier The resource identifier.
* @param encoding The auto-detected IANA encoding name of the entity
* stream. This value will be null in those situations
* where the entity encoding is not auto-detected (e.g.
* internal entities or a document entity that is
* parsed from a java.io.Reader).
* @param augs Additional information that may include infoset augmentations
*
* @exception XNIException Thrown by handler to signal an error.
*/
public void startGeneralEntity(
String name,
XMLResourceIdentifier identifier,
String encoding,
Augmentations augs)
throws XNIException {
// REVISIT: what should happen if normalize_data_ is on??
fEntityRef = true;
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs);
}
} // startEntity(String,String,String,String,String)
/**
* Notifies of the presence of a TextDecl line in an entity. If present,
* this method will be called immediately following the startEntity call.
*
* Note: This method will never be called for the
* document entity; it is only called for external general entities
* referenced in document content.
*
* Note: This method is not called for entity references
* appearing as part of attribute values.
*
* @param version The XML version, or null if not specified.
* @param encoding The IANA encoding name of the entity.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void textDecl(String version, String encoding, Augmentations augs) throws XNIException {
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.textDecl(version, encoding, augs);
}
} // textDecl(String,String)
/**
* A comment.
*
* @param text The text in the comment.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by application to signal an error.
*/
public void comment(XMLString text, Augmentations augs) throws XNIException {
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.comment(text, augs);
}
} // comment(XMLString)
/**
* A processing instruction. Processing instructions consist of a
* target name and, optionally, text data. The data is only meaningful
* to the application.
*
* Typically, a processing instruction's data will contain a series
* of pseudo-attributes. These pseudo-attributes follow the form of
* element attributes but are not parsed or presented
* to the application as anything other than text. The application is
* responsible for parsing the data.
*
* @param target The target.
* @param data The data or null if none specified.
* @param augs Additional information that may include infoset augmentations
*
* @throws XNIException Thrown by handler to signal an error.
*/
public void processingInstruction(String target, XMLString data, Augmentations augs)
throws XNIException {
// call handlers
if (fDocumentHandler != null) {
fDocumentHandler.processingInstruction(target, data, augs);
}
} // processingInstruction(String,XMLString)
/**
* This method notifies the end of a general entity.
*
* Note: This method is not called for entity references
* appearing as part of attribute values.
*
* @param name The name of the entity.
* @param augs Additional information that may include infoset augmentations
*
* @exception XNIException
* Thrown by handler to signal an error.
*/
public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
// call handlers
fEntityRef = false;
if (fDocumentHandler != null) {
fDocumentHandler.endGeneralEntity(name, augs);
}
} // endEntity(String)
// constants
static final int INITIAL_STACK_SIZE = 8;
static final int INC_STACK_SIZE = 8;
//
// Data
//
// Schema Normalization
private static final boolean DEBUG_NORMALIZATION = false;
// temporary empty string buffer.
private final XMLString fEmptyXMLStr = new XMLString(null, 0, -1);
// temporary character buffer, and empty string buffer.
private static final int BUFFER_SIZE = 20;
private final XMLString fNormalizedStr = new XMLString();
private boolean fFirstChunk = true;
// got first chunk in characters() (SAX)
private boolean fTrailing = false; // Previous chunk had a trailing space
private short fWhiteSpace = -1; //whiteSpace: preserve/replace/collapse
private boolean fUnionType = false;
/** Schema grammar resolver. */
private final XSGrammarBucket fGrammarBucket = new XSGrammarBucket();
private final SubstitutionGroupHandler fSubGroupHandler = new SubstitutionGroupHandler(this);
/** the DV usd to convert xsi:type to a QName */
// REVISIT: in new simple type design, make things in DVs static,
// so that we can QNameDV.getCompiledForm()
private final XSSimpleType fQNameDV =
(XSSimpleType) SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_QNAME);
private final CMNodeFactory nodeFactory = new CMNodeFactory();
/** used to build content models */
// REVISIT: create decl pool, and pass it to each traversers
private final CMBuilder fCMBuilder = new CMBuilder(nodeFactory);
// Schema grammar loader
private final XMLSchemaLoader fSchemaLoader =
new XMLSchemaLoader(
fXSIErrorReporter.fErrorReporter,
fGrammarBucket,
fSubGroupHandler,
fCMBuilder);
// state
/** String representation of the validation root. */
// REVISIT: what do we store here? QName, XPATH, some ID? use rawname now.
private String fValidationRoot;
/** Skip validation: anything below this level should be skipped */
private int fSkipValidationDepth;
/** anything above this level has validation_attempted != full */
private int fNFullValidationDepth;
/** anything above this level has validation_attempted != none */
private int fNNoneValidationDepth;
/** Element depth: -2: validator not in pipeline; >= -1 current depth. */
private int fElementDepth;
/** Seen sub elements. */
private boolean fSubElement;
/** Seen sub elements stack. */
private boolean[] fSubElementStack = new boolean[INITIAL_STACK_SIZE];
/** Current element declaration. */
private XSElementDecl fCurrentElemDecl;
/** Element decl stack. */
private XSElementDecl[] fElemDeclStack = new XSElementDecl[INITIAL_STACK_SIZE];
/** nil value of the current element */
private boolean fNil;
/** nil value stack */
private boolean[] fNilStack = new boolean[INITIAL_STACK_SIZE];
/** notation value of the current element */
private XSNotationDecl fNotation;
/** notation stack */
private XSNotationDecl[] fNotationStack = new XSNotationDecl[INITIAL_STACK_SIZE];
/** Current type. */
private XSTypeDefinition fCurrentType;
/** type stack. */
private XSTypeDefinition[] fTypeStack = new XSTypeDefinition[INITIAL_STACK_SIZE];
/** Current content model. */
private XSCMValidator fCurrentCM;
/** Content model stack. */
private XSCMValidator[] fCMStack = new XSCMValidator[INITIAL_STACK_SIZE];
/** the current state of the current content model */
private int[] fCurrCMState;
/** stack to hold content model states */
private int[][] fCMStateStack = new int[INITIAL_STACK_SIZE][];
/** whether the curret element is strictly assessed */
private boolean fStrictAssess = true;
/** strict assess stack */
private boolean[] fStrictAssessStack = new boolean[INITIAL_STACK_SIZE];
/** Temporary string buffers. */
private final StringBuilder fBuffer = new StringBuilder();
/** Whether need to append characters to fBuffer */
private boolean fAppendBuffer = true;
/** Did we see any character data? */
private boolean fSawText = false;
/** stack to record if we saw character data */
private boolean[] fSawTextStack = new boolean[INITIAL_STACK_SIZE];
/** Did we see non-whitespace character data? */
private boolean fSawCharacters = false;
/** Stack to record if we saw character data outside of element content*/
private boolean[] fStringContent = new boolean[INITIAL_STACK_SIZE];
/** temporary qname */
private final QName fTempQName = new QName();
/** value of the "root-type-definition" property. */
private javax.xml.namespace.QName fRootTypeQName = null;
private XSTypeDefinition fRootTypeDefinition = null;
/** value of the "root-element-declaration" property. */
private javax.xml.namespace.QName fRootElementDeclQName = null;
private XSElementDecl fRootElementDeclaration = null;
private int fIgnoreXSITypeDepth;
private boolean fIDCChecking;
/** temporary validated info */
private ValidatedInfo fValidatedInfo = new ValidatedInfo();
// used to validate default/fixed values against xsi:type
// only need to check facets, so we set extraChecking to false (in reset)
private ValidationState fState4XsiType = new ValidationState();
// used to apply default/fixed values
// only need to check id/idref/entity, so we set checkFacets to false
private ValidationState fState4ApplyDefault = new ValidationState();
// identity constraint information
/**
* Stack of active XPath matchers for identity constraints. All
* active XPath matchers are notified of startElement
* and endElement callbacks in order to perform their matches.
*
* For each element with identity constraints, the selector of
* each identity constraint is activated. When the selector matches
* its XPath, then all the fields of the identity constraint are
* activated.
*
* Note: Once the activation scope is left, the
* XPath matchers are automatically removed from the stack of
* active matchers and no longer receive callbacks.
*/
protected XPathMatcherStack fMatcherStack = new XPathMatcherStack();
/** Cache of value stores for identity constraint fields. */
protected ValueStoreCache fValueStoreCache = new ValueStoreCache();
//
// Constructors
//
/** Default constructor. */
public XMLSchemaValidator() {
fState4XsiType.setExtraChecking(false);
fState4ApplyDefault.setFacetChecking(false);
} // ()
/*
* Resets the component. The component can query the component manager
* about any features and properties that affect the operation of the
* component.
*
* @param componentManager The component manager.
*
* @throws SAXException Thrown by component on finitialization error.
* For example, if a feature or property is
* required for the operation of the component, the
* component manager may throw a
* SAXNotRecognizedException or a
* SAXNotSupportedException.
*/
public void reset(XMLComponentManager componentManager) throws XMLConfigurationException {
fIdConstraint = false;
//reset XSDDescription
fLocationPairs.clear();
// cleanup id table
fValidationState.resetIDTables();
// reset schema loader
fSchemaLoader.reset(componentManager);
// initialize state
fCurrentElemDecl = null;
fCurrentCM = null;
fCurrCMState = null;
fSkipValidationDepth = -1;
fNFullValidationDepth = -1;
fNNoneValidationDepth = -1;
fElementDepth = -1;
fSubElement = false;
fSchemaDynamicValidation = false;
// datatype normalization
fEntityRef = false;
fInCDATA = false;
fMatcherStack.clear();
// get error reporter
fXSIErrorReporter.reset((XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER));
boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true);
if (!parser_settings) {
// parser settings have not been changed
fValidationManager.addValidationState(fValidationState);
// the node limit on the SecurityManager may have changed so need to refresh.
nodeFactory.reset();
// Re-parse external schema location properties.
XMLSchemaLoader.processExternalHints(
fExternalSchemas,
fExternalNoNamespaceSchema,
fLocationPairs,
fXSIErrorReporter.fErrorReporter);
return;
}
// pass the component manager to the factory..
nodeFactory.reset(componentManager);
// get symbol table. if it's a new one, add symbols to it.
SymbolTable symbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE);
if (symbolTable != fSymbolTable) {
fSymbolTable = symbolTable;
}
fNamespaceGrowth = componentManager.getFeature(NAMESPACE_GROWTH, false);
fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION, false);
if (fDynamicValidation) {
fDoValidation = true;
} else {
fDoValidation = componentManager.getFeature(VALIDATION, false);
}
if (fDoValidation) {
fDoValidation |= componentManager.getFeature(XMLSchemaValidator.SCHEMA_VALIDATION, false);
}
fFullChecking = componentManager.getFeature(SCHEMA_FULL_CHECKING, false);
fNormalizeData = componentManager.getFeature(NORMALIZE_DATA, false);
fSchemaElementDefault = componentManager.getFeature(SCHEMA_ELEMENT_DEFAULT, false);
fAugPSVI = componentManager.getFeature(SCHEMA_AUGMENT_PSVI, true);
fSchemaType =
(String) componentManager.getProperty(
Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, null);
fUseGrammarPoolOnly = componentManager.getFeature(USE_GRAMMAR_POOL_ONLY, false);
fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
fValidationManager = (ValidationManager) componentManager.getProperty(VALIDATION_MANAGER);
fValidationManager.addValidationState(fValidationState);
fValidationState.setSymbolTable(fSymbolTable);
try {
final Object rootType = componentManager.getProperty(ROOT_TYPE_DEF);
if (rootType == null) {
fRootTypeQName = null;
fRootTypeDefinition = null;
}
else if (rootType instanceof javax.xml.namespace.QName) {
fRootTypeQName = (javax.xml.namespace.QName) rootType;
fRootTypeDefinition = null;
}
else {
fRootTypeDefinition = (XSTypeDefinition) rootType;
fRootTypeQName = null;
}
}
catch (XMLConfigurationException e) {
fRootTypeQName = null;
fRootTypeDefinition = null;
}
try {
final Object rootDecl = componentManager.getProperty(ROOT_ELEMENT_DECL);
if (rootDecl == null) {
fRootElementDeclQName = null;
fRootElementDeclaration = null;
}
else if (rootDecl instanceof javax.xml.namespace.QName) {
fRootElementDeclQName = (javax.xml.namespace.QName) rootDecl;
fRootElementDeclaration = null;
}
else {
fRootElementDeclaration = (XSElementDecl) rootDecl;
fRootElementDeclQName = null;
}
}
catch (XMLConfigurationException e) {
fRootElementDeclQName = null;
fRootElementDeclaration = null;
}
boolean ignoreXSIType = componentManager.getFeature(IGNORE_XSI_TYPE, false);
// An initial value of -1 means that the root element considers itself
// below the depth where xsi:type stopped being ignored (which means that
// xsi:type attributes will not be ignored for the entire document)
fIgnoreXSITypeDepth = ignoreXSIType ? 0 : -1;
try {
fIDCChecking = componentManager.getFeature(IDENTITY_CONSTRAINT_CHECKING);
}
catch (XMLConfigurationException e) {
fIDCChecking = true;
}
try {
fValidationState.setIdIdrefChecking(componentManager.getFeature(ID_IDREF_CHECKING));
}
catch (XMLConfigurationException e) {
fValidationState.setIdIdrefChecking(true);
}
try {
fValidationState.setUnparsedEntityChecking(componentManager.getFeature(UNPARSED_ENTITY_CHECKING));
}
catch (XMLConfigurationException e) {
fValidationState.setUnparsedEntityChecking(true);
}
// get schema location properties
try {
fExternalSchemas = (String) componentManager.getProperty(SCHEMA_LOCATION);
fExternalNoNamespaceSchema =
(String) componentManager.getProperty(SCHEMA_NONS_LOCATION);
} catch (XMLConfigurationException e) {
fExternalSchemas = null;
fExternalNoNamespaceSchema = null;
}
// store the external schema locations. they are set when reset is called,
// so any other schemaLocation declaration for the same namespace will be
// effectively ignored. becuase we choose to take first location hint
// available for a particular namespace.
XMLSchemaLoader.processExternalHints(
fExternalSchemas,
fExternalNoNamespaceSchema,
fLocationPairs,
fXSIErrorReporter.fErrorReporter);
fJaxpSchemaSource = componentManager.getProperty(JAXP_SCHEMA_SOURCE, null);
// clear grammars, and put the one for schema namespace there
fGrammarPool = (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL, null);
fState4XsiType.setSymbolTable(symbolTable);
fState4ApplyDefault.setSymbolTable(symbolTable);
} // reset(XMLComponentManager)
//
// FieldActivator methods
//
/**
* Start the value scope for the specified identity constraint. This
* method is called when the selector matches in order to initialize
* the value store.
*
* @param identityConstraint The identity constraint.
*/
public void startValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) {
ValueStoreBase valueStore =
fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
valueStore.startValueScope();
} // startValueScopeFor(IdentityConstraint identityConstraint)
/**
* Request to activate the specified field. This method returns the
* matcher for the field.
*
* @param field The field to activate.
*/
public XPathMatcher activateField(Field field, int initialDepth) {
ValueStore valueStore =
fValueStoreCache.getValueStoreFor(field.getIdentityConstraint(), initialDepth);
XPathMatcher matcher = field.createMatcher(valueStore);
fMatcherStack.addMatcher(matcher);
matcher.startDocumentFragment();
return matcher;
} // activateField(Field):XPathMatcher
/**
* Ends the value scope for the specified identity constraint.
*
* @param identityConstraint The identity constraint.
*/
public void endValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) {
ValueStoreBase valueStore =
fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
valueStore.endValueScope();
} // endValueScopeFor(IdentityConstraint)
// a utility method for Identity constraints
private void activateSelectorFor(IdentityConstraint ic) {
Selector selector = ic.getSelector();
FieldActivator activator = this;
if (selector == null)
return;
XPathMatcher matcher = selector.createMatcher(activator, fElementDepth);
fMatcherStack.addMatcher(matcher);
matcher.startDocumentFragment();
}
// Implements XSElementDeclHelper interface
public XSElementDecl getGlobalElementDecl(QName element) {
final SchemaGrammar sGrammar =
findSchemaGrammar(
XSDDescription.CONTEXT_ELEMENT,
element.uri,
null,
element,
null);
if (sGrammar != null) {
return sGrammar.getGlobalElementDecl(element.localpart);
}
return null;
}
//
// Protected methods
//
/** ensure element stack capacity */
void ensureStackCapacity() {
if (fElementDepth == fElemDeclStack.length) {
int newSize = fElementDepth + INC_STACK_SIZE;
boolean[] newArrayB = new boolean[newSize];
System.arraycopy(fSubElementStack, 0, newArrayB, 0, fElementDepth);
fSubElementStack = newArrayB;
XSElementDecl[] newArrayE = new XSElementDecl[newSize];
System.arraycopy(fElemDeclStack, 0, newArrayE, 0, fElementDepth);
fElemDeclStack = newArrayE;
newArrayB = new boolean[newSize];
System.arraycopy(fNilStack, 0, newArrayB, 0, fElementDepth);
fNilStack = newArrayB;
XSNotationDecl[] newArrayN = new XSNotationDecl[newSize];
System.arraycopy(fNotationStack, 0, newArrayN, 0, fElementDepth);
fNotationStack = newArrayN;
XSTypeDefinition[] newArrayT = new XSTypeDefinition[newSize];
System.arraycopy(fTypeStack, 0, newArrayT, 0, fElementDepth);
fTypeStack = newArrayT;
XSCMValidator[] newArrayC = new XSCMValidator[newSize];
System.arraycopy(fCMStack, 0, newArrayC, 0, fElementDepth);
fCMStack = newArrayC;
newArrayB = new boolean[newSize];
System.arraycopy(fSawTextStack, 0, newArrayB, 0, fElementDepth);
fSawTextStack = newArrayB;
newArrayB = new boolean[newSize];
System.arraycopy(fStringContent, 0, newArrayB, 0, fElementDepth);
fStringContent = newArrayB;
newArrayB = new boolean[newSize];
System.arraycopy(fStrictAssessStack, 0, newArrayB, 0, fElementDepth);
fStrictAssessStack = newArrayB;
int[][] newArrayIA = new int[newSize][];
System.arraycopy(fCMStateStack, 0, newArrayIA, 0, fElementDepth);
fCMStateStack = newArrayIA;
}
} // ensureStackCapacity
// handle start document
void handleStartDocument(XMLLocator locator, String encoding) {
if (fIDCChecking) {
fValueStoreCache.startDocument();
}
if (fAugPSVI) {
fCurrentPSVI.fGrammars = null;
fCurrentPSVI.fSchemaInformation = null;
}
} // handleStartDocument(XMLLocator,String)
void handleEndDocument() {
if (fIDCChecking) {
fValueStoreCache.endDocument();
}
} // handleEndDocument()
// handle character contents
// returns the normalized string if possible, otherwise the original string
XMLString handleCharacters(XMLString text) {
if (fSkipValidationDepth >= 0)
return text;
fSawText = fSawText || text.length > 0;
// Note: data in EntityRef and CDATA is normalized as well
// if whitespace == -1 skip normalization, because it is a complexType
// or a union type.
if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) {
// normalize data
normalizeWhitespace(text, fWhiteSpace == XSSimpleType.WS_COLLAPSE);
text = fNormalizedStr;
}
if (fAppendBuffer)
fBuffer.append(text.ch, text.offset, text.length);
// When it's a complex type with element-only content, we need to
// find out whether the content contains any non-whitespace character.
fSawOnlyWhitespaceInElementContent = false;
if (fCurrentType != null
&& fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
// data outside of element content
for (int i = text.offset; i < text.offset + text.length; i++) {
if (!XMLChar.isSpace(text.ch[i])) {
fSawCharacters = true;
break;
}
fSawOnlyWhitespaceInElementContent = !fSawCharacters;
}
}
}
return text;
} // handleCharacters(XMLString)
/**
* Normalize whitespace in an XMLString according to the rules defined
* in XML Schema specifications.
* @param value The string to normalize.
* @param collapse replace or collapse
*/
private void normalizeWhitespace(XMLString value, boolean collapse) {
boolean skipSpace = collapse;
boolean sawNonWS = false;
boolean leading = false;
boolean trailing = false;
char c;
int size = value.offset + value.length;
// ensure the ch array is big enough
if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < value.length + 1) {
fNormalizedStr.ch = new char[value.length + 1];
}
// don't include the leading ' ' for now. might include it later.
fNormalizedStr.offset = 1;
fNormalizedStr.length = 1;
for (int i = value.offset; i < size; i++) {
c = value.ch[i];
if (XMLChar.isSpace(c)) {
if (!skipSpace) {
// take the first whitespace as a space and skip the others
fNormalizedStr.ch[fNormalizedStr.length++] = ' ';
skipSpace = collapse;
}
if (!sawNonWS) {
// this is a leading whitespace, record it
leading = true;
}
} else {
fNormalizedStr.ch[fNormalizedStr.length++] = c;
skipSpace = false;
sawNonWS = true;
}
}
if (skipSpace) {
if (fNormalizedStr.length > 1) {
// if we finished on a space trim it but also record it
fNormalizedStr.length--;
trailing = true;
} else if (leading && !fFirstChunk) {
// if all we had was whitespace we skipped record it as
// trailing whitespace as well
trailing = true;
}
}
if (fNormalizedStr.length > 1) {
if (!fFirstChunk && (fWhiteSpace == XSSimpleType.WS_COLLAPSE)) {
if (fTrailing) {
// previous chunk ended on whitespace
// insert whitespace
fNormalizedStr.offset = 0;
fNormalizedStr.ch[0] = ' ';
} else if (leading) {
// previous chunk ended on character,
// this chunk starts with whitespace
fNormalizedStr.offset = 0;
fNormalizedStr.ch[0] = ' ';
}
}
}
// The length includes the leading ' '. Now removing it.
fNormalizedStr.length -= fNormalizedStr.offset;
fTrailing = trailing;
if (trailing || sawNonWS)
fFirstChunk = false;
}
private void normalizeWhitespace(String value, boolean collapse) {
boolean skipSpace = collapse;
char c;
int size = value.length();
// ensure the ch array is big enough
if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < size) {
fNormalizedStr.ch = new char[size];
}
fNormalizedStr.offset = 0;
fNormalizedStr.length = 0;
for (int i = 0; i < size; i++) {
c = value.charAt(i);
if (XMLChar.isSpace(c)) {
if (!skipSpace) {
// take the first whitespace as a space and skip the others
fNormalizedStr.ch[fNormalizedStr.length++] = ' ';
skipSpace = collapse;
}
} else {
fNormalizedStr.ch[fNormalizedStr.length++] = c;
skipSpace = false;
}
}
if (skipSpace) {
if (fNormalizedStr.length != 0)
// if we finished on a space trim it but also record it
fNormalizedStr.length--;
}
}
// handle ignorable whitespace
void handleIgnorableWhitespace(XMLString text) {
if (fSkipValidationDepth >= 0)
return;
// REVISIT: the same process needs to be performed as handleCharacters.
// only it's simpler here: we know all characters are whitespaces.
} // handleIgnorableWhitespace(XMLString)
/** Handle element. */
Augmentations handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) {
if (DEBUG) {
System.out.println("==>handleStartElement: " + element);
}
// root element
if (fElementDepth == -1 && fValidationManager.isGrammarFound()) {
if (fSchemaType == null) {
// schemaType is not specified
// if a DTD grammar is found, we do the same thing as Dynamic:
// if a schema grammar is found, validation is performed;
// otherwise, skip the whole document.
fSchemaDynamicValidation = true;
} else {
// [1] Either schemaType is DTD, and in this case validate/schema is turned off
// [2] Validating against XML Schemas only
// [a] dynamic validation is false: report error if SchemaGrammar is not found
// [b] dynamic validation is true: if grammar is not found ignore.
}
}
// get xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes,
// parse them to get the grammars. But only do this if the grammar can grow.
if (!fUseGrammarPoolOnly) {
String sLocation =
attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_SCHEMALOCATION);
String nsLocation =
attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION);
//store the location hints.. we need to do it so that we can defer the loading of grammar until
//there is a reference to a component from that namespace. To provide location hints to the
//application for a namespace
storeLocations(sLocation, nsLocation);
}
// if we are in the content of "skip", then just skip this element
// REVISIT: is this the correct behaviour for ID constraints? -NG
if (fSkipValidationDepth >= 0) {
fElementDepth++;
if (fAugPSVI)
augs = getEmptyAugs(augs);
return augs;
}
// if we are not skipping this element, and there is a content model,
// we try to find the corresponding decl object for this element.
// the reason we move this part of code here is to make sure the
// error reported here (if any) is stored within the parent element's
// context, instead of that of the current element.
Object decl = null;
if (fCurrentCM != null) {
decl = fCurrentCM.oneTransition(element, fCurrCMState, fSubGroupHandler);
// it could be an element decl or a wildcard decl
if (fCurrCMState[0] == XSCMValidator.FIRST_ERROR) {
XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
//REVISIT: is it the only case we will have particle = null?
List