blob: 5a69574d6acdd9d2f1c0bda0eafc1008968b6e8f [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999,2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xerces.validators.common;
import org.apache.xerces.framework.XMLAttrList;
import org.apache.xerces.framework.XMLContentSpec;
import org.apache.xerces.framework.XMLDocumentHandler;
import org.apache.xerces.framework.XMLDocumentScanner;
import org.apache.xerces.framework.XMLErrorReporter;
import org.apache.xerces.readers.DefaultEntityHandler;
import org.apache.xerces.readers.XMLEntityHandler;
import org.apache.xerces.utils.ChunkyCharArray;
import org.apache.xerces.utils.Hash2intTable;
import org.apache.xerces.utils.NamespacesScope;
import org.apache.xerces.utils.QName;
import org.apache.xerces.utils.StringPool;
import org.apache.xerces.utils.XMLCharacterProperties;
import org.apache.xerces.utils.XMLMessages;
import org.apache.xerces.utils.ImplementationMessages;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.EntityResolver;
import org.xml.sax.Locator;
import org.xml.sax.helpers.LocatorImpl;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
import org.apache.xerces.validators.dtd.DTDGrammar;
import org.apache.xerces.validators.schema.EquivClassComparator;
import org.apache.xerces.validators.schema.SchemaGrammar;
import org.apache.xerces.validators.schema.SchemaMessageProvider;
import org.apache.xerces.validators.schema.SchemaSymbols;
import org.apache.xerces.validators.schema.TraverseSchema;
import org.apache.xerces.validators.datatype.DatatypeValidatorFactoryImpl;
import org.apache.xerces.validators.datatype.DatatypeValidator;
import org.apache.xerces.validators.datatype.InvalidDatatypeValueException;
import org.apache.xerces.validators.datatype.StateMessageDatatype;
import org.apache.xerces.validators.datatype.IDREFDatatypeValidator;
import org.apache.xerces.validators.datatype.IDDatatypeValidator;
import org.apache.xerces.validators.datatype.ENTITYDatatypeValidator;
/**
* This class is the super all-in-one validator used by the parser.
*
* @version $Id$
*/
public final class XMLValidator
implements DefaultEntityHandler.EventHandler,
XMLEntityHandler.CharDataHandler,
XMLDocumentScanner.EventHandler,
NamespacesScope.NamespacesHandler {
//
// Constants
//
// debugging
private static final boolean PRINT_EXCEPTION_STACK_TRACE = false;
private static final boolean DEBUG_PRINT_ATTRIBUTES = false;
private static final boolean DEBUG_PRINT_CONTENT = false;
private static final boolean DEBUG_SCHEMA_VALIDATION = false;
private static final boolean DEBUG_ELEMENT_CHILDREN = false;
// Chunk size constants
private static final int CHUNK_SHIFT = 8; // 2^8 = 256
private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
private static final int CHUNK_MASK = CHUNK_SIZE - 1;
private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k
private Hashtable fIdDefs = null;
private StateMessageDatatype fStoreIDRef = new StateMessageDatatype() {
private Hashtable fIdDefs;
public Object getDatatypeObject(){
return(Object) fIdDefs;
}
public int getDatatypeState(){
return IDREFDatatypeValidator.IDREF_STORE;
}
public void setDatatypeObject( Object data ){
fIdDefs = (Hashtable) data;
}
};
private StateMessageDatatype fResetID = new StateMessageDatatype() {
public Object getDatatypeObject(){
return(Object) null;
}
public int getDatatypeState(){
return IDDatatypeValidator.ID_CLEAR;
}
public void setDatatypeObject( Object data ){
}
};
private StateMessageDatatype fResetIDRef = new StateMessageDatatype() {
public Object getDatatypeObject(){
return(Object) null;
}
public int getDatatypeState(){
return IDREFDatatypeValidator.IDREF_CLEAR;
}
public void setDatatypeObject( Object data ){
}
};
private StateMessageDatatype fValidateIDRef = new StateMessageDatatype() {
public Object getDatatypeObject(){
return(Object) null;
}
public int getDatatypeState(){
return IDREFDatatypeValidator.IDREF_VALIDATE;
}
public void setDatatypeObject( Object data ){
}
};
private StateMessageDatatype fValidateENTITYMsg = new StateMessageDatatype() {
private Object packagedMessage = null;
public Object getDatatypeObject(){
return packagedMessage;
}
public int getDatatypeState(){
return ENTITYDatatypeValidator.ENTITY_INITIALIZE;//No state
}
public void setDatatypeObject( Object data ){
packagedMessage = data;// Set Entity Handler
}
};
/*
private StateMessageDatatype fValidateNOTATIONMsg = new StateMessageDatatype() {
private Object packagedMessage = null;
public Object getDatatypeObject(){
return packagedMessage;
}
public int getDatatypeState(){
return NOTATIONDatatypeValidator.ENTITY_INITIALIZE;//No state
}
public void setDatatypeObject( Object data ){
packagedMessage = data;// Set Entity Handler
}
};
*/
//
// Data
//
// REVISIT: The data should be regrouped and re-organized so that
// it's easier to find a meaningful field.
// debugging
// private static boolean DEBUG = false;
// other
// attribute validators
private AttributeValidator fAttValidatorNOTATION = new AttValidatorNOTATION();
private AttributeValidator fAttValidatorENUMERATION = new AttValidatorENUMERATION();
private AttributeValidator fAttValidatorDATATYPE = null;
// Package access for use by AttributeValidator classes.
StringPool fStringPool = null;
boolean fValidating = false;
boolean fInElementContent = false;
int fStandaloneReader = -1;
// settings
private boolean fValidationEnabled = false;
private boolean fDynamicValidation = false;
private boolean fSchemaValidation = true;
private boolean fValidationEnabledByDynamic = false;
private boolean fDynamicDisabledByValidation = false;
private boolean fWarningOnDuplicateAttDef = false;
private boolean fWarningOnUndeclaredElements = false;
private boolean fLoadDTDGrammar = true;
// declarations
private int fDeclaration[];
private XMLErrorReporter fErrorReporter = null;
private DefaultEntityHandler fEntityHandler = null;
private QName fCurrentElement = new QName();
private ContentLeafNameTypeVector[] fContentLeafStack = new ContentLeafNameTypeVector[8];
private int[] fValidationFlagStack = new int[8];
private int[] fScopeStack = new int[8];
private int[] fGrammarNameSpaceIndexStack = new int[8];
private int[] fElementEntityStack = new int[8];
private int[] fElementIndexStack = new int[8];
private int[] fContentSpecTypeStack = new int[8];
private static final int sizeQNameParts = 8;
private QName[] fElementQNamePartsStack = new QName[sizeQNameParts];
private QName[] fElementChildren = new QName[32];
private int fElementChildrenLength = 0;
private int[] fElementChildrenOffsetStack = new int[32];
private int fElementDepth = -1;
private boolean fNamespacesEnabled = false;
private NamespacesScope fNamespacesScope = null;
private int fNamespacesPrefix = -1;
private QName fRootElement = new QName();
private int fAttrListHandle = -1;
private int fCurrentElementEntity = -1;
private int fCurrentElementIndex = -1;
private int fCurrentContentSpecType = -1;
private boolean fSeenDoctypeDecl = false;
private final int TOP_LEVEL_SCOPE = -1;
private int fCurrentScope = TOP_LEVEL_SCOPE;
private int fCurrentSchemaURI = -1;
private int fEmptyURI = - 1;
private int fXsiPrefix = - 1;
private int fXsiURI = -2;
private int fXsiTypeAttValue = -1;
private DatatypeValidator fXsiTypeValidator = null;
private Grammar fGrammar = null;
private int fGrammarNameSpaceIndex = -1;
private GrammarResolver fGrammarResolver = null;
// state and stuff
private boolean fScanningDTD = false;
private XMLDocumentScanner fDocumentScanner = null;
private boolean fCalledStartDocument = false;
private XMLDocumentHandler fDocumentHandler = null;
private XMLDocumentHandler.DTDHandler fDTDHandler = null;
private boolean fSeenRootElement = false;
private XMLAttrList fAttrList = null;
private int fXMLLang = -1;
private LocatorImpl fAttrNameLocator = null;
private boolean fCheckedForSchema = false;
private boolean fDeclsAreExternal = false;
private StringPool.CharArrayRange fCurrentElementCharArrayRange = null;
private char[] fCharRefData = null;
private boolean fSendCharDataAsCharArray = false;
private boolean fBufferDatatype = false;
private StringBuffer fDatatypeBuffer = new StringBuffer();
private QName fTempQName = new QName();
private XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl();
private XMLAttributeDecl fTempAttributeDecl = new XMLAttributeDecl();
private XMLElementDecl fTempElementDecl = new XMLElementDecl();
private boolean fGrammarIsDTDGrammar = false;
private boolean fGrammarIsSchemaGrammar = false;
private boolean fNeedValidationOff = false;
// symbols
private int fEMPTYSymbol = -1;
private int fANYSymbol = -1;
private int fMIXEDSymbol = -1;
private int fCHILDRENSymbol = -1;
private int fCDATASymbol = -1;
private int fIDSymbol = -1;
private int fIDREFSymbol = -1;
private int fIDREFSSymbol = -1;
private int fENTITYSymbol = -1;
private int fENTITIESSymbol = -1;
private int fNMTOKENSymbol = -1;
private int fNMTOKENSSymbol = -1;
private int fNOTATIONSymbol = -1;
private int fENUMERATIONSymbol = -1;
private int fREQUIREDSymbol = -1;
private int fFIXEDSymbol = -1;
private int fDATATYPESymbol = -1;
private int fEpsilonIndex = -1;
//Datatype Registry
private DatatypeValidatorFactoryImpl fDataTypeReg =
DatatypeValidatorFactoryImpl.getDatatypeRegistry();
private DatatypeValidator fValID = this.fDataTypeReg.getDatatypeValidator("ID" );
private DatatypeValidator fValIDRef = this.fDataTypeReg.getDatatypeValidator("IDREF" );
private DatatypeValidator fValIDRefs = this.fDataTypeReg.getDatatypeValidator("IDREFS" );
private DatatypeValidator fValENTITY = this.fDataTypeReg.getDatatypeValidator("ENTITY" );
private DatatypeValidator fValENTITIES = this.fDataTypeReg.getDatatypeValidator("ENTITIES" );
private DatatypeValidator fValNMTOKEN = this.fDataTypeReg.getDatatypeValidator("NMTOKEN");
private DatatypeValidator fValNMTOKENS = this.fDataTypeReg.getDatatypeValidator("NMTOKENS");
private DatatypeValidator fValNOTATION = this.fDataTypeReg.getDatatypeValidator("NOTATION" );
//
// Constructors
//
/** Constructs an XML validator. */
public XMLValidator(StringPool stringPool,
XMLErrorReporter errorReporter,
DefaultEntityHandler entityHandler,
XMLDocumentScanner documentScanner) {
// keep references
fStringPool = stringPool;
fErrorReporter = errorReporter;
fEntityHandler = entityHandler;
fDocumentScanner = documentScanner;
fEmptyURI = fStringPool.addSymbol("");
fXsiURI = fStringPool.addSymbol(SchemaSymbols.URI_XSI);
// initialize
fAttrList = new XMLAttrList(fStringPool);
entityHandler.setEventHandler(this);
entityHandler.setCharDataHandler(this);
fDocumentScanner.setEventHandler(this);
for (int i = 0; i < sizeQNameParts; i++) {
fElementQNamePartsStack[i] = new QName();
}
init();
} // <init>(StringPool,XMLErrorReporter,DefaultEntityHandler,XMLDocumentScanner)
public void setGrammarResolver(GrammarResolver grammarResolver){
fGrammarResolver = grammarResolver;
}
//
// Public methods
//
// initialization
/** Set char data processing preference and handlers. */
public void initHandlers(boolean sendCharDataAsCharArray,
XMLDocumentHandler docHandler,
XMLDocumentHandler.DTDHandler dtdHandler) {
fSendCharDataAsCharArray = sendCharDataAsCharArray;
fEntityHandler.setSendCharDataAsCharArray(fSendCharDataAsCharArray);
fDocumentHandler = docHandler;
fDTDHandler = dtdHandler;
} // initHandlers(boolean,XMLDocumentHandler,XMLDocumentHandler.DTDHandler)
/** Reset or copy. */
public void resetOrCopy(StringPool stringPool) throws Exception {
fAttrList = new XMLAttrList(stringPool);
resetCommon(stringPool);
}
/** Reset. */
public void reset(StringPool stringPool) throws Exception {
fAttrList.reset(stringPool);
resetCommon(stringPool);
}
// settings
/**
* Turning on validation/dynamic turns on validation if it is off, and
* this is remembered. Turning off validation DISABLES validation/dynamic
* if it is on. Turning off validation/dynamic DOES NOT turn off
* validation if it was explicitly turned on, only if it was turned on
* BECAUSE OF the call to turn validation/dynamic on. Turning on
* validation will REENABLE and turn validation/dynamic back on if it
* was disabled by a call that turned off validation while
* validation/dynamic was enabled.
*/
public void setValidationEnabled(boolean flag) throws Exception {
fValidationEnabled = flag;
fValidationEnabledByDynamic = false;
if (fValidationEnabled) {
if (fDynamicDisabledByValidation) {
fDynamicValidation = true;
fDynamicDisabledByValidation = false;
}
} else if (fDynamicValidation) {
fDynamicValidation = false;
fDynamicDisabledByValidation = true;
}
fValidating = fValidationEnabled;
}
/** Returns true if validation is enabled. */
public boolean getValidationEnabled() {
return fValidationEnabled;
}
/** Sets whether Schema support is on/off. */
public void setSchemaValidationEnabled(boolean flag) {
fSchemaValidation = flag;
}
/** Returns true if Schema support is on. */
public boolean getSchemaValidationEnabled() {
return fSchemaValidation;
}
/** Sets whether validation is dynamic. */
public void setDynamicValidationEnabled(boolean flag) throws Exception {
fDynamicValidation = flag;
fDynamicDisabledByValidation = false;
if (!fDynamicValidation) {
if (fValidationEnabledByDynamic) {
fValidationEnabled = false;
fValidationEnabledByDynamic = false;
}
} else if (!fValidationEnabled) {
fValidationEnabled = true;
fValidationEnabledByDynamic = true;
}
fValidating = fValidationEnabled;
}
/** Returns true if validation is dynamic. */
public boolean getDynamicValidationEnabled() {
return fDynamicValidation;
}
/** Sets fLoadDTDGrammar when validation is off **/
public void setLoadDTDGrammar(boolean loadDG){
if (fValidating) {
fLoadDTDGrammar = true;
} else {
fLoadDTDGrammar = loadDG;
}
}
/** Returns fLoadDTDGrammar **/
public boolean getLoadDTDGrammar() {
return fLoadDTDGrammar;
}
/** Sets whether namespaces are enabled. */
public void setNamespacesEnabled(boolean flag) {
fNamespacesEnabled = flag;
}
/** Returns true if namespaces are enabled. */
public boolean getNamespacesEnabled() {
return fNamespacesEnabled;
}
/** Sets whether duplicate attribute definitions signal a warning. */
public void setWarningOnDuplicateAttDef(boolean flag) {
fWarningOnDuplicateAttDef = flag;
}
/** Returns true if duplicate attribute definitions signal a warning. */
public boolean getWarningOnDuplicateAttDef() {
return fWarningOnDuplicateAttDef;
}
/** Sets whether undeclared elements signal a warning. */
public void setWarningOnUndeclaredElements(boolean flag) {
fWarningOnUndeclaredElements = flag;
}
/** Returns true if undeclared elements signal a warning. */
public boolean getWarningOnUndeclaredElements() {
return fWarningOnUndeclaredElements;
}
//
// DefaultEntityHandler.EventHandler methods
//
/** Start entity reference. */
public void startEntityReference(int entityName, int entityType, int entityContext) throws Exception {
fDocumentHandler.startEntityReference(entityName, entityType, entityContext);
}
/** End entity reference. */
public void endEntityReference(int entityName, int entityType, int entityContext) throws Exception {
fDocumentHandler.endEntityReference(entityName, entityType, entityContext);
}
/** Send end of input notification. */
public void sendEndOfInputNotifications(int entityName, boolean moreToFollow) throws Exception {
fDocumentScanner.endOfInput(entityName, moreToFollow);
/***
if (fScanningDTD) {
fDTDImporter.sendEndOfInputNotifications(entityName, moreToFollow);
}
/***/
}
/** Send reader change notifications. */
public void sendReaderChangeNotifications(XMLEntityHandler.EntityReader reader, int readerId) throws Exception {
fDocumentScanner.readerChange(reader, readerId);
/***
if (fScanningDTD) {
fDTDImporter.sendReaderChangeNotifications(reader, readerId);
}
/***/
}
/** External entity standalone check. */
public boolean externalEntityStandaloneCheck() {
return(fStandaloneReader != -1 && fValidating);
}
/** Return true if validating. */
public boolean getValidating() {
return fValidating;
}
//
// XMLEntityHandler.CharDataHandler methods
//
/** Process characters. */
public void processCharacters(char[] chars, int offset, int length) throws Exception {
if (fValidating) {
if (fInElementContent || fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
charDataInContent();
}
if (fBufferDatatype) {
fDatatypeBuffer.append(chars, offset, length);
}
}
fDocumentHandler.characters(chars, offset, length);
}
/** Process characters. */
public void processCharacters(int data) throws Exception {
if (fValidating) {
if (fInElementContent || fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
charDataInContent();
}
if (fBufferDatatype) {
fDatatypeBuffer.append(fStringPool.toString(data));
}
}
fDocumentHandler.characters(data);
}
/** Process whitespace. */
public void processWhitespace(char[] chars, int offset, int length)
throws Exception {
if (fInElementContent) {
if (fStandaloneReader != -1 && fValidating && getElementDeclIsExternal(fCurrentElementIndex)) {
reportRecoverableXMLError(XMLMessages.MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION);
}
fDocumentHandler.ignorableWhitespace(chars, offset, length);
} else {
if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
charDataInContent();
}
fDocumentHandler.characters(chars, offset, length);
}
} // processWhitespace(char[],int,int)
/** Process whitespace. */
public void processWhitespace(int data) throws Exception {
if (fInElementContent) {
if (fStandaloneReader != -1 && fValidating && getElementDeclIsExternal(fCurrentElementIndex)) {
reportRecoverableXMLError(XMLMessages.MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION);
}
fDocumentHandler.ignorableWhitespace(data);
} else {
if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
charDataInContent();
}
fDocumentHandler.characters(data);
}
} // processWhitespace(int)
//
// XMLDocumentScanner.EventHandler methods
//
/** Scans element type. */
public void scanElementType(XMLEntityHandler.EntityReader entityReader,
char fastchar, QName element) throws Exception {
if (!fNamespacesEnabled) {
element.clear();
element.localpart = entityReader.scanName(fastchar);
element.rawname = element.localpart;
} else {
entityReader.scanQName(fastchar, element);
if (entityReader.lookingAtChar(':', false)) {
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_TWO_COLONS_IN_QNAME,
XMLMessages.P5_INVALID_CHARACTER,
null,
XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
entityReader.skipPastNmtoken(' ');
}
}
} // scanElementType(XMLEntityHandler.EntityReader,char,QName)
/** Scans expected element type. */
public boolean scanExpectedElementType(XMLEntityHandler.EntityReader entityReader,
char fastchar, QName element)
throws Exception {
if (fCurrentElementCharArrayRange == null) {
fCurrentElementCharArrayRange = fStringPool.createCharArrayRange();
}
fStringPool.getCharArrayRange(fCurrentElement.rawname, fCurrentElementCharArrayRange);
return entityReader.scanExpectedName(fastchar, fCurrentElementCharArrayRange);
} // scanExpectedElementType(XMLEntityHandler.EntityReader,char,QName)
/** Scans attribute name. */
public void scanAttributeName(XMLEntityHandler.EntityReader entityReader,
QName element, QName attribute)
throws Exception {
if (!fSeenRootElement) {
fSeenRootElement = true;
rootElementSpecified(element);
fStringPool.resetShuffleCount();
}
if (!fNamespacesEnabled) {
attribute.clear();
attribute.localpart = entityReader.scanName('=');
attribute.rawname = attribute.localpart;
} else {
entityReader.scanQName('=', attribute);
if (entityReader.lookingAtChar(':', false)) {
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_TWO_COLONS_IN_QNAME,
XMLMessages.P5_INVALID_CHARACTER,
null,
XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
entityReader.skipPastNmtoken(' ');
}
}
} // scanAttributeName(XMLEntityHandler.EntityReader,QName,QName)
/** Call start document. */
public void callStartDocument() throws Exception {
if (!fCalledStartDocument) {
fDocumentHandler.startDocument();
fCalledStartDocument = true;
}
}
/** Call end document. */
public void callEndDocument() throws Exception {
if (fCalledStartDocument) {
fDocumentHandler.endDocument();
}
}
/** Call XML declaration. */
public void callXMLDecl(int version, int encoding, int standalone) throws Exception {
fDocumentHandler.xmlDecl(version, encoding, standalone);
}
public void callStandaloneIsYes() throws Exception {
// standalone = "yes". said XMLDocumentScanner.
fStandaloneReader = fEntityHandler.getReaderId() ;
}
/** Call text declaration. */
public void callTextDecl(int version, int encoding) throws Exception {
fDocumentHandler.textDecl(version, encoding);
}
/**
* Signal the scanning of an element name in a start element tag.
*
* @param element Element name scanned.
*/
public void element(QName element) throws Exception {
fAttrListHandle = -1;
}
/**
* Signal the scanning of an attribute associated to the previous
* start element tag.
*
* @param element Element name scanned.
* @param attrName Attribute name scanned.
* @param attrValue The string pool index of the attribute value.
*/
public boolean attribute(QName element, QName attrName, int attrValue) throws Exception {
if (fAttrListHandle == -1) {
fAttrListHandle = fAttrList.startAttrList();
}
// if fAttrList.addAttr returns -1, indicates duplicate att in start tag of an element.
// specified: true, search : true
return fAttrList.addAttr(attrName, attrValue, fCDATASymbol, true, true) == -1;
}
/** Call start element. */
public void callStartElement(QName element) throws Exception {
if ( DEBUG_SCHEMA_VALIDATION )
System.out.println("\n=======StartElement : " + fStringPool.toString(element.localpart));
//
// Check after all specified attrs are scanned
// (1) report error for REQUIRED attrs that are missing (V_TAGc)
// (2) add default attrs (FIXED and NOT_FIXED)
//
if (!fSeenRootElement) {
fSeenRootElement = true;
rootElementSpecified(element);
fStringPool.resetShuffleCount();
}
if (fGrammar != null && fGrammarIsDTDGrammar) {
fAttrListHandle = addDTDDefaultAttributes(element, fAttrList, fAttrListHandle, fValidating, fStandaloneReader != -1);
}
fCheckedForSchema = true;
if (fNamespacesEnabled) {
bindNamespacesToElementAndAttributes(element, fAttrList);
}
validateElementAndAttributes(element, fAttrList);
if (fAttrListHandle != -1) {
fAttrList.endAttrList();
}
fDocumentHandler.startElement(element, fAttrList, fAttrListHandle);
fAttrListHandle = -1;
//before we increment the element depth, add this element's QName to its enclosing element 's children list
fElementDepth++;
//if (fElementDepth >= 0) {
if (fValidating) {
// push current length onto stack
if (fElementChildrenOffsetStack.length < fElementDepth) {
int newarray[] = new int[fElementChildrenOffsetStack.length * 2];
System.arraycopy(fElementChildrenOffsetStack, 0, newarray, 0, fElementChildrenOffsetStack.length);
fElementChildrenOffsetStack = newarray;
}
fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength;
// add this element to children
if (fElementChildren.length <= fElementChildrenLength) {
QName[] newarray = new QName[fElementChildrenLength * 2];
System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length);
fElementChildren = newarray;
}
QName qname = fElementChildren[fElementChildrenLength];
if (qname == null) {
for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
fElementChildren[i] = new QName();
}
qname = fElementChildren[fElementChildrenLength];
}
qname.setValues(element);
fElementChildrenLength++;
if (DEBUG_ELEMENT_CHILDREN) {
printChildren();
printStack();
}
}
// One more level of depth
//fElementDepth++;
ensureStackCapacity(fElementDepth);
fCurrentElement.setValues(element);
fCurrentElementEntity = fEntityHandler.getReaderId();
fElementQNamePartsStack[fElementDepth].setValues(fCurrentElement);
fElementEntityStack[fElementDepth] = fCurrentElementEntity;
fElementIndexStack[fElementDepth] = fCurrentElementIndex;
fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType;
if (fNeedValidationOff) {
fValidating = false;
fNeedValidationOff = false;
}
if (fValidating && fGrammarIsSchemaGrammar) {
pushContentLeafStack();
}
fValidationFlagStack[fElementDepth] = fValidating ? 0 : -1;
fScopeStack[fElementDepth] = fCurrentScope;
fGrammarNameSpaceIndexStack[fElementDepth] = fGrammarNameSpaceIndex;
} // callStartElement(QName)
private void pushContentLeafStack() throws Exception {
int contentType = getContentSpecType(fCurrentElementIndex);
if ( contentType == XMLElementDecl.TYPE_CHILDREN) {
XMLContentModel cm = getElementContentModel(fCurrentElementIndex);
ContentLeafNameTypeVector cv = cm.getContentLeafNameTypeVector();
if (cm != null) {
fContentLeafStack[fElementDepth] = cv;
}
}
}
private void ensureStackCapacity ( int newElementDepth) {
if (newElementDepth == fElementQNamePartsStack.length ) {
int[] newStack = new int[newElementDepth * 2];
System.arraycopy(fScopeStack, 0, newStack, 0, newElementDepth);
fScopeStack = newStack;
newStack = new int[newElementDepth * 2];
System.arraycopy(fGrammarNameSpaceIndexStack, 0, newStack, 0, newElementDepth);
fGrammarNameSpaceIndexStack = newStack;
QName[] newStackOfQueue = new QName[newElementDepth * 2];
System.arraycopy(this.fElementQNamePartsStack, 0, newStackOfQueue, 0, newElementDepth );
fElementQNamePartsStack = newStackOfQueue;
QName qname = fElementQNamePartsStack[newElementDepth];
if (qname == null) {
for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) {
fElementQNamePartsStack[i] = new QName();
}
}
newStack = new int[newElementDepth * 2];
System.arraycopy(fElementEntityStack, 0, newStack, 0, newElementDepth);
fElementEntityStack = newStack;
newStack = new int[newElementDepth * 2];
System.arraycopy(fElementIndexStack, 0, newStack, 0, newElementDepth);
fElementIndexStack = newStack;
newStack = new int[newElementDepth * 2];
System.arraycopy(fContentSpecTypeStack, 0, newStack, 0, newElementDepth);
fContentSpecTypeStack = newStack;
newStack = new int[newElementDepth * 2];
System.arraycopy(fValidationFlagStack, 0, newStack, 0, newElementDepth);
fValidationFlagStack = newStack;
ContentLeafNameTypeVector[] newStackV = new ContentLeafNameTypeVector[newElementDepth * 2];
System.arraycopy(fContentLeafStack, 0, newStackV, 0, newElementDepth);
fContentLeafStack = newStackV;
}
}
/** Call end element. */
public void callEndElement(int readerId) throws Exception {
if ( DEBUG_SCHEMA_VALIDATION )
System.out.println("=======EndElement : " + fStringPool.toString(fCurrentElement.localpart)+"\n");
int prefixIndex = fCurrentElement.prefix;
int elementType = fCurrentElement.rawname;
if (fCurrentElementEntity != readerId) {
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_ELEMENT_ENTITY_MISMATCH,
XMLMessages.P78_NOT_WELLFORMED,
new Object[] { fStringPool.toString(elementType)},
XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
}
fElementDepth--;
if (fValidating) {
int elementIndex = fCurrentElementIndex;
if (elementIndex != -1 && fCurrentContentSpecType != -1) {
QName children[] = fElementChildren;
int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
int childrenLength = fElementChildrenLength - childrenOffset;
if (DEBUG_ELEMENT_CHILDREN) {
System.out.println("endElement("+fStringPool.toString(fCurrentElement.rawname)+')');
System.out.println("fCurrentContentSpecType : " + fCurrentContentSpecType );
System.out.print("offset: ");
System.out.print(childrenOffset);
System.out.print(", length: ");
System.out.print(childrenLength);
System.out.println();
printChildren();
printStack();
}
int result = checkContent(elementIndex,
children, childrenOffset, childrenLength);
if ( DEBUG_SCHEMA_VALIDATION )
System.out.println("!!!!!!!!In XMLValidator, the return value from checkContent : " + result);
if (result != -1) {
int majorCode = result != childrenLength ? XMLMessages.MSG_CONTENT_INVALID : XMLMessages.MSG_CONTENT_INCOMPLETE;
fGrammar.getElementDecl(elementIndex, fTempElementDecl);
if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
reportRecoverableXMLError(majorCode,
0,
fStringPool.toString(elementType),
"EMPTY");
} else
reportRecoverableXMLError(majorCode,
0,
fStringPool.toString(elementType),
XMLContentSpec.toString(fGrammar, fStringPool, fTempElementDecl.contentSpecIndex));
}
}
fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
}
fDocumentHandler.endElement(fCurrentElement);
if (fNamespacesEnabled) {
fNamespacesScope.decreaseDepth();
}
// now pop this element off the top of the element stack
//if (fElementDepth-- < 0) {
if (fElementDepth < -1) {
throw new RuntimeException("FWK008 Element stack underflow");
}
if (fElementDepth < 0) {
fCurrentElement.clear();
fCurrentElementEntity = -1;
fCurrentElementIndex = -1;
fCurrentContentSpecType = -1;
fInElementContent = false;
//
// Check after document is fully parsed
// (1) check that there was an element with a matching id for every
// IDREF and IDREFS attr (V_IDREF0)
//
if (fValidating ) {
try {
this.fValIDRef.validate( null, this.fValidateIDRef );
this.fValIDRefs.validate( null, this.fValidateIDRef );
} catch ( InvalidDatatypeValueException ex ) {
reportRecoverableXMLError( ex.getMajorCode(), ex.getMinorCode(),
ex.getMessage() );
}
}
try {//Reset datatypes state
this.fValID.validate( null, this.fResetID );
this.fValIDRef.validate(null, this.fResetIDRef );
this.fValIDRefs.validate(null, this.fResetIDRef );
} catch ( InvalidDatatypeValueException ex ) {
System.err.println("Error re-Initializing: ID,IDRef,IDRefs pools" );
}
return;
}
//restore enclosing element to all the "current" variables
// REVISIT: Validation. This information needs to be stored.
fCurrentElement.prefix = -1;
if (fNamespacesEnabled) { //If Namespace enable then localName != rawName
fCurrentElement.localpart = fElementQNamePartsStack[fElementDepth].localpart;
} else {//REVISIT - jeffreyr - This is so we still do old behavior when namespace is off
fCurrentElement.localpart = fElementQNamePartsStack[fElementDepth].rawname;
}
fCurrentElement.rawname = fElementQNamePartsStack[fElementDepth].rawname;
fCurrentElement.uri = fElementQNamePartsStack[fElementDepth].uri;
fCurrentElement.prefix = fElementQNamePartsStack[fElementDepth].prefix;
fCurrentElementEntity = fElementEntityStack[fElementDepth];
fCurrentElementIndex = fElementIndexStack[fElementDepth];
fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth];
fValidating = fValidationFlagStack[fElementDepth] == 0 ? true : false;
fCurrentScope = fScopeStack[fElementDepth];
//if ( DEBUG_SCHEMA_VALIDATION ) {
/****
System.out.println("+++++ currentElement : " + fStringPool.toString(elementType)+
"\n fCurrentElementIndex : " + fCurrentElementIndex +
"\n fCurrentScope : " + fCurrentScope +
"\n fCurrentContentSpecType : " + fCurrentContentSpecType +
"\n++++++++++++++++++++++++++++++++++++++++++++++++" );
/****/
//}
// if enclosing element's Schema is different, need to switch "context"
if ( fGrammarNameSpaceIndex != fGrammarNameSpaceIndexStack[fElementDepth] ) {
fGrammarNameSpaceIndex = fGrammarNameSpaceIndexStack[fElementDepth];
if ( fValidating && fGrammarIsSchemaGrammar )
if ( !switchGrammar(fGrammarNameSpaceIndex) ) {
reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR, XMLMessages.SCHEMA_GENERIC_ERROR,
"Grammar with uri : " + fStringPool.toString(fGrammarNameSpaceIndex)
+ " , can not found");
}
}
if (fValidating) {
fBufferDatatype = false;
}
fInElementContent = (fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN);
} // callEndElement(int)
/** Call start CDATA section. */
public void callStartCDATA() throws Exception {
fDocumentHandler.startCDATA();
}
/** Call end CDATA section. */
public void callEndCDATA() throws Exception {
fDocumentHandler.endCDATA();
}
/** Call characters. */
public void callCharacters(int ch) throws Exception {
if (fCharRefData == null) {
fCharRefData = new char[2];
}
int count = (ch < 0x10000) ? 1 : 2;
if (count == 1) {
fCharRefData[0] = (char)ch;
} else {
fCharRefData[0] = (char)(((ch-0x00010000)>>10)+0xd800);
fCharRefData[1] = (char)(((ch-0x00010000)&0x3ff)+0xdc00);
}
if (fValidating && (fInElementContent || fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY)) {
charDataInContent();
}
if (fSendCharDataAsCharArray) {
fDocumentHandler.characters(fCharRefData, 0, count);
} else {
int index = fStringPool.addString(new String(fCharRefData, 0, count));
fDocumentHandler.characters(index);
}
} // callCharacters(int)
/** Call processing instruction. */
public void callProcessingInstruction(int target, int data) throws Exception {
fDocumentHandler.processingInstruction(target, data);
}
/** Call comment. */
public void callComment(int comment) throws Exception {
fDocumentHandler.comment(comment);
}
//
// NamespacesScope.NamespacesHandler methods
//
/** Start a new namespace declaration scope. */
public void startNamespaceDeclScope(int prefix, int uri) throws Exception {
fDocumentHandler.startNamespaceDeclScope(prefix, uri);
}
/** End a namespace declaration scope. */
public void endNamespaceDeclScope(int prefix) throws Exception {
fDocumentHandler.endNamespaceDeclScope(prefix);
}
// attributes
// other
/** Sets the root element. */
public void setRootElementType(QName rootElement) {
fRootElement.setValues(rootElement);
}
/**
* Returns true if the element declaration is external.
* <p>
* <strong>Note:</strong> This method is primarilly useful for
* DTDs with internal and external subsets.
*/
private boolean getElementDeclIsExternal(int elementIndex) {
/*if (elementIndex < 0 || elementIndex >= fElementCount) {
return false;
}
int chunk = elementIndex >> CHUNK_SHIFT;
int index = elementIndex & CHUNK_MASK;
return (fElementDeclIsExternal[chunk][index] != 0);
*/
if (fGrammarIsDTDGrammar ) {
return((DTDGrammar) fGrammar).getElementDeclIsExternal(elementIndex);
}
return false;
}
/** Returns the content spec type for an element index. */
public int getContentSpecType(int elementIndex) {
int contentSpecType = -1;
if ( elementIndex > -1) {
if ( fGrammar.getElementDecl(elementIndex,fTempElementDecl) ) {
contentSpecType = fTempElementDecl.type;
}
}
return contentSpecType;
}
/** Returns the content spec handle for an element index. */
public int getContentSpecHandle(int elementIndex) {
int contentSpecHandle = -1;
if ( elementIndex > -1) {
if ( fGrammar.getElementDecl(elementIndex,fTempElementDecl) ) {
contentSpecHandle = fTempElementDecl.contentSpecIndex;
}
}
return contentSpecHandle;
}
//
// Protected methods
//
// error reporting
/** Report a recoverable xml error. */
protected void reportRecoverableXMLError(int majorCode, int minorCode)
throws Exception {
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
majorCode,
minorCode,
null,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
} // reportRecoverableXMLError(int,int)
/** Report a recoverable xml error. */
protected void reportRecoverableXMLError(int majorCode, int minorCode,
int stringIndex1)
throws Exception {
Object[] args = { fStringPool.toString(stringIndex1)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
majorCode,
minorCode,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
} // reportRecoverableXMLError(int,int,int)
/** Report a recoverable xml error. */
protected void reportRecoverableXMLError(int majorCode, int minorCode,
String string1) throws Exception {
Object[] args = { string1};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
majorCode,
minorCode,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
} // reportRecoverableXMLError(int,int,String)
/** Report a recoverable xml error. */
protected void reportRecoverableXMLError(int majorCode, int minorCode,
int stringIndex1, int stringIndex2)
throws Exception {
Object[] args = { fStringPool.toString(stringIndex1), fStringPool.toString(stringIndex2)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
majorCode,
minorCode,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
} // reportRecoverableXMLError(int,int,int,int)
/** Report a recoverable xml error. */
protected void reportRecoverableXMLError(int majorCode, int minorCode,
String string1, String string2)
throws Exception {
Object[] args = { string1, string2};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
majorCode,
minorCode,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
} // reportRecoverableXMLError(int,int,String,String)
/** Report a recoverable xml error. */
protected void reportRecoverableXMLError(int majorCode, int minorCode,
String string1, String string2,
String string3) throws Exception {
Object[] args = { string1, string2, string3};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
majorCode,
minorCode,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
} // reportRecoverableXMLError(int,int,String,String,String)
// content spec
/**
* Returns information about which elements can be placed at a particular point
* in the passed element's content model.
* <p>
* Note that the incoming content model to test must be valid at least up to
* the insertion point. If not, then -1 will be returned and the info object
* will not have been filled in.
* <p>
* If, on return, the info.isValidEOC flag is set, then the 'insert after'
* elemement is a valid end of content, i.e. nothing needs to be inserted
* after it to make the parent element's content model valid.
*
* @param elementIndex The index within the <code>ElementDeclPool</code> of the
* element which is being querying.
* @param fullyValid Only return elements that can be inserted and still
* maintain the validity of subsequent elements past the
* insertion point (if any). If the insertion point is at
* the end, and this is true, then only elements that can
* be legal final states will be returned.
* @param info An object that contains the required input data for the method,
* and which will contain the output information if successful.
*
* @return The value -1 if fully valid, else the 0 based index of the child
* that first failed before the insertion point. If the value
* returned is equal to the number of children, then the specified
* children are valid but additional content is required to reach a
* valid ending state.
*
* @exception Exception Thrown on error.
*
* @see InsertableElementsInfo
*/
protected int whatCanGoHere(int elementIndex, boolean fullyValid,
InsertableElementsInfo info) throws Exception {
//
// Do some basic sanity checking on the info packet. First, make sure
// that insertAt is not greater than the child count. It can be equal,
// which means to get appendable elements, but not greater. Or, if
// the current children array is null, that's bad too.
//
// Since the current children array must have a blank spot for where
// the insert is going to be, the child count must always be at least
// one.
//
// Make sure that the child count is not larger than the current children
// array. It can be equal, which means get appendable elements, but not
// greater.
//
if (info.insertAt > info.childCount || info.curChildren == null ||
info.childCount < 1 || info.childCount > info.curChildren.length) {
fErrorReporter.reportError(fErrorReporter.getLocator(),
ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
ImplementationMessages.VAL_WCGHI,
0,
null,
XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
}
int retVal = 0;
try {
// Get the content model for this element
final XMLContentModel cmElem = getElementContentModel(elementIndex);
// And delegate this call to it
retVal = cmElem.whatCanGoHere(fullyValid, info);
} catch (CMException excToCatch) {
// REVISIT - Translate caught error to the protected error handler interface
int majorCode = excToCatch.getErrorCode();
fErrorReporter.reportError(fErrorReporter.getLocator(),
ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
majorCode,
0,
null,
XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
throw excToCatch;
}
return retVal;
} // whatCanGoHere(int,boolean,InsertableElementsInfo):int
// attribute information
/** Protected for use by AttributeValidator classes. */
protected boolean getAttDefIsExternal(QName element, QName attribute) {
int attDefIndex = getAttDef(element, attribute);
if (fGrammarIsDTDGrammar ) {
return((DTDGrammar) fGrammar).getAttributeDeclIsExternal(attDefIndex);
}
return false;
}
//
// Private methods
//
// other
/** Returns true if using a standalone reader. */
private boolean usingStandaloneReader() {
return fStandaloneReader == -1 || fEntityHandler.getReaderId() == fStandaloneReader;
}
/** Returns a locator implementation. */
private LocatorImpl getLocatorImpl(LocatorImpl fillin) {
Locator here = fErrorReporter.getLocator();
if (fillin == null)
return new LocatorImpl(here);
fillin.setPublicId(here.getPublicId());
fillin.setSystemId(here.getSystemId());
fillin.setLineNumber(here.getLineNumber());
fillin.setColumnNumber(here.getColumnNumber());
return fillin;
} // getLocatorImpl(LocatorImpl):LocatorImpl
// initialization
/** Reset pool. */
private void poolReset() {
try {
//System.out.println("We reset" );
this.fValID.validate( null, this.fResetID );
this.fValIDRef.validate(null, this.fResetIDRef );
this.fValIDRefs.validate(null, this.fResetIDRef );
} catch ( InvalidDatatypeValueException ex ) {
System.err.println("Error re-Initializing: ID,IDRef,IDRefs pools" );
}
} // poolReset()
/** Reset common. */
private void resetCommon(StringPool stringPool) throws Exception {
fStringPool = stringPool;
fValidating = fValidationEnabled;
fValidationEnabledByDynamic = false;
fDynamicDisabledByValidation = false;
poolReset();
fCalledStartDocument = false;
fStandaloneReader = -1;
fElementChildrenLength = 0;
fElementDepth = -1;
fSeenRootElement = false;
fSeenDoctypeDecl = false;
fNamespacesScope = null;
fNamespacesPrefix = -1;
fRootElement.clear();
fAttrListHandle = -1;
fCheckedForSchema = false;
fCurrentScope = TOP_LEVEL_SCOPE;
fCurrentSchemaURI = -1;
fEmptyURI = - 1;
fXsiPrefix = - 1;
fXsiTypeValidator = null;
fGrammar = null;
fGrammarNameSpaceIndex = -1;
//fGrammarResolver = null;
if (fGrammarResolver != null) {
fGrammarResolver.clearGrammarResolver();
}
fGrammarIsDTDGrammar = false;
fGrammarIsSchemaGrammar = false;
init();
} // resetCommon(StringPool)
/** Initialize. */
private void init() {
fEmptyURI = fStringPool.addSymbol("");
fXsiURI = fStringPool.addSymbol(SchemaSymbols.URI_XSI);
fEMPTYSymbol = fStringPool.addSymbol("EMPTY");
fANYSymbol = fStringPool.addSymbol("ANY");
fMIXEDSymbol = fStringPool.addSymbol("MIXED");
fCHILDRENSymbol = fStringPool.addSymbol("CHILDREN");
fCDATASymbol = fStringPool.addSymbol("CDATA");
fIDSymbol = fStringPool.addSymbol("ID");
fIDREFSymbol = fStringPool.addSymbol("IDREF");
fIDREFSSymbol = fStringPool.addSymbol("IDREFS");
fENTITYSymbol = fStringPool.addSymbol("ENTITY");
fENTITIESSymbol = fStringPool.addSymbol("ENTITIES");
fNMTOKENSymbol = fStringPool.addSymbol("NMTOKEN");
fNMTOKENSSymbol = fStringPool.addSymbol("NMTOKENS");
fNOTATIONSymbol = fStringPool.addSymbol("NOTATION");
fENUMERATIONSymbol = fStringPool.addSymbol("ENUMERATION");
fREQUIREDSymbol = fStringPool.addSymbol("#REQUIRED");
fFIXEDSymbol = fStringPool.addSymbol("#FIXED");
fDATATYPESymbol = fStringPool.addSymbol("<<datatype>>");
fEpsilonIndex = fStringPool.addSymbol("<<CMNODE_EPSILON>>");
fXMLLang = fStringPool.addSymbol("xml:lang");
try {//Initialize ENTITIES and ENTITY Validators
Object[] packageArgsEntityVal = { (Object) this.fEntityHandler,
(Object) this.fStringPool};
fValidateENTITYMsg.setDatatypeObject( (Object ) packageArgsEntityVal);
fValENTITIES.validate( null, fValidateENTITYMsg );
fValENTITY.validate( null, fValidateENTITYMsg );
} catch ( InvalidDatatypeValueException ex ) {
System.err.println("Error: " + ex.getLocalizedMessage() );//Should not happen
}
} // init()
// other
// default attribute
/** addDefaultAttributes. */
private int addDefaultAttributes(int elementIndex, XMLAttrList attrList, int attrIndex, boolean validationEnabled, boolean standalone) throws Exception {
//System.out.println("XMLValidator#addDefaultAttributes");
//System.out.print(" ");
//fGrammar.printAttributes(elementIndex);
//
// Check after all specified attrs are scanned
// (1) report error for REQUIRED attrs that are missing (V_TAGc)
// (2) check that FIXED attrs have matching value (V_TAGd)
// (3) add default attrs (FIXED and NOT_FIXED)
//
fGrammar.getElementDecl(elementIndex,fTempElementDecl);
int elementNameIndex = fTempElementDecl.name.localpart;
int attlistIndex = fGrammar.getFirstAttributeDeclIndex(elementIndex);
int firstCheck = attrIndex;
int lastCheck = -1;
while (attlistIndex != -1) {
fGrammar.getAttributeDecl(attlistIndex, fTempAttDecl);
int attPrefix = fTempAttDecl.name.prefix;
int attName = fTempAttDecl.name.localpart;
int attType = attributeTypeName(fTempAttDecl);
int attDefType =fTempAttDecl.defaultType;
int attValue = -1 ;
if (fTempAttDecl.defaultValue != null ) {
attValue = fStringPool.addSymbol(fTempAttDecl.defaultValue);
}
boolean specified = false;
boolean required = attDefType == XMLAttributeDecl.DEFAULT_TYPE_REQUIRED;
if (firstCheck != -1) {
boolean cdata = attType == fCDATASymbol;
if (!cdata || required || attValue != -1) {
int i = attrList.getFirstAttr(firstCheck);
while (i != -1 && (lastCheck == -1 || i <= lastCheck)) {
if ( (fGrammarIsDTDGrammar && (attrList.getAttrName(i) == fTempAttDecl.name.rawname)) ||
( fStringPool.equalNames(attrList.getAttrLocalpart(i), attName)
&& fStringPool.equalNames(attrList.getAttrURI(i), fTempAttDecl.name.uri) ) ) {
if (validationEnabled && attDefType == XMLAttributeDecl.DEFAULT_TYPE_FIXED) {
int alistValue = attrList.getAttValue(i);
if (alistValue != attValue &&
!fStringPool.toString(alistValue).equals(fStringPool.toString(attValue))) {
Object[] args = { fStringPool.toString(elementNameIndex),
fStringPool.toString(attName),
fStringPool.toString(alistValue),
fStringPool.toString(attValue)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_FIXED_ATTVALUE_INVALID,
XMLMessages.VC_FIXED_ATTRIBUTE_DEFAULT,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
}
specified = true;
break;
}
i = attrList.getNextAttr(i);
}
}
}
if (!specified) {
if (required) {
if (validationEnabled) {
Object[] args = { fStringPool.toString(elementNameIndex),
fStringPool.toString(attName)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED,
XMLMessages.VC_REQUIRED_ATTRIBUTE,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
} else if (attValue != -1) {
if (validationEnabled && standalone )
if ( fGrammarIsDTDGrammar
&& ((DTDGrammar) fGrammar).getAttributeDeclIsExternal(attlistIndex) ) {
Object[] args = { fStringPool.toString(elementNameIndex),
fStringPool.toString(attName)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
if (attType == fIDREFSymbol) {
this.fValIDRef.validate( fStringPool.toString(attValue), this.fStoreIDRef );
} else if (attType == fIDREFSSymbol) {
this.fValIDRefs.validate( fStringPool.toString(attValue), this.fStoreIDRef );
}
if (attrIndex == -1) {
attrIndex = attrList.startAttrList();
}
// REVISIT: Validation. What should the prefix be?
fTempQName.setValues(attPrefix, attName, attName, fTempAttDecl.name.uri);
int newAttr = attrList.addAttr(fTempQName,
attValue, attType,
false, false);
if (lastCheck == -1) {
lastCheck = newAttr;
}
}
}
attlistIndex = fGrammar.getNextAttributeDeclIndex(attlistIndex);
}
return attrIndex;
} // addDefaultAttributes(int,XMLAttrList,int,boolean,boolean):int
/** addDTDDefaultAttributes. */
private int addDTDDefaultAttributes(QName element, XMLAttrList attrList, int attrIndex, boolean validationEnabled, boolean standalone) throws Exception {
//
// Check after all specified attrs are scanned
// (1) report error for REQUIRED attrs that are missing (V_TAGc)
// (2) check that FIXED attrs have matching value (V_TAGd)
// (3) add default attrs (FIXED and NOT_FIXED)
//
int elementIndex = fGrammar.getElementDeclIndex(element, -1);
if (elementIndex == -1) {
return attrIndex;
}
fGrammar.getElementDecl(elementIndex,fTempElementDecl);
int elementNameIndex = fTempElementDecl.name.rawname;
int attlistIndex = fGrammar.getFirstAttributeDeclIndex(elementIndex);
int firstCheck = attrIndex;
int lastCheck = -1;
while (attlistIndex != -1) {
fGrammar.getAttributeDecl(attlistIndex, fTempAttDecl);
// TO DO: For ericye Debug only
/***
if (fTempAttDecl != null) {
XMLElementDecl element = new XMLElementDecl();
fGrammar.getElementDecl(elementIndex, element);
System.out.println("element: "+fStringPool.toString(element.name.localpart));
System.out.println("attlistIndex " + attlistIndex + "\n"+
"attName : '"+fStringPool.toString(fTempAttDecl.name.localpart) + "'\n"
+ "attType : "+fTempAttDecl.type + "\n"
+ "attDefaultType : "+fTempAttDecl.defaultType + "\n"
+ "attDefaultValue : '"+fTempAttDecl.defaultValue + "'\n"
+ attrList.getLength() +"\n"
);
}
/***/
int attPrefix = fTempAttDecl.name.prefix;
int attName = fTempAttDecl.name.rawname;
int attLocalpart = fTempAttDecl.name.localpart;
int attType = attributeTypeName(fTempAttDecl);
int attDefType =fTempAttDecl.defaultType;
int attValue = -1 ;
if (fTempAttDecl.defaultValue != null ) {
attValue = fStringPool.addSymbol(fTempAttDecl.defaultValue);
}
boolean specified = false;
boolean required = attDefType == XMLAttributeDecl.DEFAULT_TYPE_REQUIRED;
/****
if (fValidating && fGrammar != null && fGrammarIsDTDGrammar && attValue != -1) {
normalizeAttValue(null, fTempAttDecl.name,
attValue,attType,fTempAttDecl.list,
fTempAttDecl.enumeration);
}
/****/
if (firstCheck != -1) {
boolean cdata = attType == fCDATASymbol;
if (!cdata || required || attValue != -1) {
int i = attrList.getFirstAttr(firstCheck);
while (i != -1 && (lastCheck == -1 || i <= lastCheck)) {
if ( attrList.getAttrName(i) == fTempAttDecl.name.rawname ) {
if (validationEnabled && attDefType == XMLAttributeDecl.DEFAULT_TYPE_FIXED) {
int alistValue = attrList.getAttValue(i);
if (alistValue != attValue &&
!fStringPool.toString(alistValue).equals(fStringPool.toString(attValue))) {
Object[] args = { fStringPool.toString(elementNameIndex),
fStringPool.toString(attName),
fStringPool.toString(alistValue),
fStringPool.toString(attValue)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_FIXED_ATTVALUE_INVALID,
XMLMessages.VC_FIXED_ATTRIBUTE_DEFAULT,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
}
specified = true;
break;
}
i = attrList.getNextAttr(i);
}
}
}
if (!specified) {
if (required) {
if (validationEnabled) {
Object[] args = { fStringPool.toString(elementNameIndex),
fStringPool.toString(attName)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED,
XMLMessages.VC_REQUIRED_ATTRIBUTE,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
} else if (attValue != -1) {
if (validationEnabled && standalone )
if ( fGrammarIsDTDGrammar
&& ((DTDGrammar) fGrammar).getAttributeDeclIsExternal(attlistIndex) ) {
Object[] args = { fStringPool.toString(elementNameIndex),
fStringPool.toString(attName)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
if (attType == fIDREFSymbol) {
this.fValIDRef.validate( fStringPool.toString(attValue), this.fStoreIDRef );
} else if (attType == fIDREFSSymbol) {
this.fValIDRefs.validate( fStringPool.toString(attValue), this.fStoreIDRef );
}
if (attrIndex == -1) {
attrIndex = attrList.startAttrList();
}
fTempQName.setValues(attPrefix, attLocalpart, attName, fTempAttDecl.name.uri);
int newAttr = attrList.addAttr(fTempQName,
attValue, attType,
false, false);
if (lastCheck == -1) {
lastCheck = newAttr;
}
}
}
attlistIndex = fGrammar.getNextAttributeDeclIndex(attlistIndex);
}
return attrIndex;
} // addDTDDefaultAttributes(int,XMLAttrList,int,boolean,boolean):int
// content models
/** Queries the content model for the specified element index. */
private XMLContentModel getElementContentModel(int elementIndex) throws CMException {
XMLContentModel contentModel = null;
if ( elementIndex > -1) {
if ( fGrammar.getElementDecl(elementIndex,fTempElementDecl) ) {
contentModel = fGrammar.getElementContentModel(elementIndex);
}
}
//return fGrammar.getElementContentModel(elementIndex);
return contentModel;
}
// query attribute information
/** Returns an attribute definition for an element type. */
// this is only used by DTD validation.
private int getAttDef(QName element, QName attribute) {
if (fGrammar != null) {
int scope = fCurrentScope;
if (element.uri > -1) {
scope = TOP_LEVEL_SCOPE;
}
int elementIndex = fGrammar.getElementDeclIndex(element,scope);
if (elementIndex == -1) {
return -1;
}
int attDefIndex = fGrammar.getFirstAttributeDeclIndex(elementIndex);
while (attDefIndex != -1) {
fGrammar.getAttributeDecl(attDefIndex, fTempAttributeDecl);
if (fTempAttributeDecl.name.localpart == attribute.localpart &&
fTempAttributeDecl.name.uri == attribute.uri ) {
return attDefIndex;
}
attDefIndex = fGrammar.getNextAttributeDeclIndex(attDefIndex);
}
}
return -1;
} // getAttDef(QName,QName)
/** Returns an attribute definition for an element type. */
private int getAttDefByElementIndex(int elementIndex, QName attribute) {
if (fGrammar != null && elementIndex > -1) {
if (elementIndex == -1) {
return -1;
}
int attDefIndex = fGrammar.getFirstAttributeDeclIndex(elementIndex);
while (attDefIndex != -1) {
fGrammar.getAttributeDecl(attDefIndex, fTempAttDecl);
if (fGrammarIsDTDGrammar) {
if (fTempAttDecl.name.rawname == attribute.rawname )
return attDefIndex;
} else
if (fTempAttDecl.name.localpart == attribute.localpart &&
fTempAttDecl.name.uri == attribute.uri ) {
return attDefIndex;
}
if (fGrammarIsSchemaGrammar) {
if (fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_ANY) {
return attDefIndex;
} else if (fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_LOCAL) {
if (attribute.uri == -1) {
return attDefIndex;
}
} else if (fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_OTHER) {
if (attribute.uri != fTempAttDecl.name.uri) {
return attDefIndex;
}
} else if (fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_LIST) {
if (fStringPool.stringInList(fTempAttDecl.enumeration, attribute.uri)) {
return attDefIndex;
}
}
}
attDefIndex = fGrammar.getNextAttributeDeclIndex(attDefIndex);
}
}
return -1;
} // getAttDef(QName,QName)
// validation
/** Root element specified. */
private void rootElementSpecified(QName rootElement) throws Exception {
// this is what it used to be
//if (fDynamicValidation && !fSeenDoctypeDecl) {
//fValidating = false;
//}
if ( fLoadDTDGrammar )
// initialize the grammar to be the default one,
// it definitely should be a DTD Grammar at this case;
if (fGrammar == null) {
fGrammar = fGrammarResolver.getGrammar("");
//TO DO, for ericye debug only
if (fGrammar == null && DEBUG_SCHEMA_VALIDATION) {
System.out.println("Oops! no grammar is found for validation");
}
if (fDynamicValidation && fGrammar==null) {
fValidating = false;
}
if (fGrammar != null) {
if (fGrammar instanceof DTDGrammar) {
fGrammarIsDTDGrammar = true;
fGrammarIsSchemaGrammar = false;
} else if ( fGrammar instanceof SchemaGrammar ) {
fGrammarIsSchemaGrammar = true;
fGrammarIsDTDGrammar = false;
}
fGrammarNameSpaceIndex = fEmptyURI;
}
}
if (fValidating) {
if ( fGrammarIsDTDGrammar &&
((DTDGrammar) fGrammar).getRootElementQName(fRootElement) ) {
String root1 = fStringPool.toString(fRootElement.rawname);
String root2 = fStringPool.toString(rootElement.rawname);
if (!root1.equals(root2)) {
reportRecoverableXMLError(XMLMessages.MSG_ROOT_ELEMENT_TYPE,
XMLMessages.VC_ROOT_ELEMENT_TYPE,
fRootElement.rawname,
rootElement.rawname);
}
}
}
if (fNamespacesEnabled) {
if (fNamespacesScope == null) {
fNamespacesScope = new NamespacesScope(this);
fNamespacesPrefix = fStringPool.addSymbol("xmlns");
fNamespacesScope.setNamespaceForPrefix(fNamespacesPrefix, -1);
int xmlSymbol = fStringPool.addSymbol("xml");
int xmlNamespace = fStringPool.addSymbol("http://www.w3.org/XML/1998/namespace");
fNamespacesScope.setNamespaceForPrefix(xmlSymbol, xmlNamespace);
}
}
} // rootElementSpecified(QName)
/** Switchs to correct validating symbol tables when Schema changes.*/
private boolean switchGrammar(int newGrammarNameSpaceIndex) throws Exception {
Grammar tempGrammar = fGrammarResolver.getGrammar(fStringPool.toString(newGrammarNameSpaceIndex));
if (tempGrammar == null) {
// This is a case where namespaces is on with a DTD grammar.
tempGrammar = fGrammarResolver.getGrammar("");
}
if (tempGrammar == null) {
return false;
} else {
fGrammar = tempGrammar;
if (fGrammar instanceof DTDGrammar) {
fGrammarIsDTDGrammar = true;
fGrammarIsSchemaGrammar = false;
} else if ( fGrammar instanceof SchemaGrammar ) {
fGrammarIsSchemaGrammar = true;
fGrammarIsDTDGrammar = false;
}
return true;
}
}
/** Binds namespaces to the element and attributes. */
private void bindNamespacesToElementAndAttributes(QName element,
XMLAttrList attrList)
throws Exception {
fNamespacesScope.increaseDepth();
//Vector schemaCandidateURIs = null;
Hashtable locationUriPairs = null;
if (fAttrListHandle != -1) {
int index = attrList.getFirstAttr(fAttrListHandle);
while (index != -1) {
int attName = attrList.getAttrName(index);
int attPrefix = attrList.getAttrPrefix(index);
if (fStringPool.equalNames(attName, fXMLLang)) {
/***
// NOTE: This check is done in the validateElementsAndAttributes
// method.
fDocumentScanner.checkXMLLangAttributeValue(attrList.getAttValue(index));
/***/
} else if (fStringPool.equalNames(attName, fNamespacesPrefix)) {
int uri = fStringPool.addSymbol(attrList.getAttValue(index));
fNamespacesScope.setNamespaceForPrefix(StringPool.EMPTY_STRING, uri);
} else {
if (attPrefix == fNamespacesPrefix) {
int nsPrefix = attrList.getAttrLocalpart(index);
int uri = fStringPool.addSymbol(attrList.getAttValue(index));
fNamespacesScope.setNamespaceForPrefix(nsPrefix, uri);
if (fValidating && fSchemaValidation) {
boolean seeXsi = false;
String attrValue = fStringPool.toString(attrList.getAttValue(index));
if (attrValue.equals(SchemaSymbols.URI_XSI)) {
fXsiPrefix = nsPrefix;
seeXsi = true;
}
if (!seeXsi) {
/***
if (schemaCandidateURIs == null) {
schemaCandidateURIs = new Vector();
}
schemaCandidateURIs.addElement( fStringPool.toString(uri) );
/***/
}
}
}
}
index = attrList.getNextAttr(index);
}
// if validating, walk through the list again to deal with "xsi:...."
if (fValidating && fSchemaValidation) {
fXsiTypeAttValue = -1;
index = attrList.getFirstAttr(fAttrListHandle);
while (index != -1) {
int attName = attrList.getAttrName(index);
int attPrefix = attrList.getAttrPrefix(index);
if (fStringPool.equalNames(attName, fNamespacesPrefix)) {
// REVISIT
} else {
if ( DEBUG_SCHEMA_VALIDATION ) {
System.out.println("deal with XSI");
System.out.println("before find XSI: "+fStringPool.toString(attPrefix)
+","+fStringPool.toString(fXsiPrefix) );
}
if ( fXsiPrefix != -1 && attPrefix == fXsiPrefix ) {
if (DEBUG_SCHEMA_VALIDATION) {
System.out.println("find XSI: "+fStringPool.toString(attPrefix)
+","+fStringPool.toString(attName) );
}
int localpart = attrList.getAttrLocalpart(index);
if (localpart == fStringPool.addSymbol(SchemaSymbols.XSI_SCHEMALOCACTION)) {
if (locationUriPairs == null) {
locationUriPairs = new Hashtable();
}
parseSchemaLocation(fStringPool.toString(attrList.getAttValue(index)), locationUriPairs);
} else if (localpart == fStringPool.addSymbol(SchemaSymbols.XSI_NONAMESPACESCHEMALOCACTION)) {
if (locationUriPairs == null) {
locationUriPairs = new Hashtable();
}
locationUriPairs.put(fStringPool.toString(attrList.getAttValue(index)), "");
if (fNamespacesScope != null) {
//bind prefix "" to URI "" in this case
fNamespacesScope.setNamespaceForPrefix( fStringPool.addSymbol(""),
fStringPool.addSymbol(""));
}
} else if (localpart == fStringPool.addSymbol(SchemaSymbols.XSI_TYPE)) {
fXsiTypeAttValue = attrList.getAttValue(index);
}
// REVISIT: should we break here?
//break;
}
}
index = attrList.getNextAttr(index);
}
// try to resolve all the grammars here
if (locationUriPairs != null) {
Enumeration locations = locationUriPairs.keys();
while (locations.hasMoreElements()) {
String loc = (String) locations.nextElement();
String uri = (String) locationUriPairs.get(loc);
resolveSchemaGrammar( loc, uri);
//schemaCandidateURIs.removeElement(uri);
}
}
//TO DO: This should be a feature that can be turned on or off
/*****
for (int i=0; i< schemaCandidateURIs.size(); i++) {
String uri = (String) schemaCandidateURIs.elementAt(i);
resolveSchemaGrammar(uri);
}
/*****/
}
}
// bind element to URI
int prefix = element.prefix != -1 ? element.prefix : 0;
int uri = fNamespacesScope.getNamespaceForPrefix(prefix);
if (element.prefix != -1 || uri != -1) {
element.uri = uri;
if (element.uri == -1) {
Object[] args = { fStringPool.toString(element.prefix)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XMLNS_DOMAIN,
XMLMessages.MSG_PREFIX_DECLARED,
XMLMessages.NC_PREFIX_DECLARED,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
}
if (fAttrListHandle != -1) {
int index = attrList.getFirstAttr(fAttrListHandle);
while (index != -1) {
int attName = attrList.getAttrName(index);
if (!fStringPool.equalNames(attName, fNamespacesPrefix)) {
int attPrefix = attrList.getAttrPrefix(index);
if (attPrefix != fNamespacesPrefix) {
if (attPrefix != -1 ) {
int attrUri = fNamespacesScope.getNamespaceForPrefix(attPrefix);
if (attrUri == -1) {
Object[] args = { fStringPool.toString(attPrefix)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XMLNS_DOMAIN,
XMLMessages.MSG_PREFIX_DECLARED,
XMLMessages.NC_PREFIX_DECLARED,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
attrList.setAttrURI(index, attrUri);
}
}
}
index = attrList.getNextAttr(index);
}
}
} // bindNamespacesToElementAndAttributes(QName,XMLAttrList)
void parseSchemaLocation(String schemaLocationStr, Hashtable locationUriPairs){
if (locationUriPairs != null) {
StringTokenizer tokenizer = new StringTokenizer(schemaLocationStr, " \n\t\r", false);
int tokenTotal = tokenizer.countTokens();
if (tokenTotal % 2 != 0 ) {
// TO DO: report warning - malformed schemaLocation string
} else {
while (tokenizer.hasMoreTokens()) {
String uri = tokenizer.nextToken();
String location = tokenizer.nextToken();
locationUriPairs.put(location, uri);
}
}
} else {
// TO DO: should report internal error here
}
}// parseSchemaLocaltion(String, Hashtable)
private void resolveSchemaGrammar( String loc, String uri) throws Exception {
SchemaGrammar grammar = (SchemaGrammar) fGrammarResolver.getGrammar(uri);
if (grammar == null) {
DOMParser parser = new DOMParser();
parser.setEntityResolver( new Resolver(fEntityHandler) );
parser.setErrorHandler( new ErrorHandler() );
try {
parser.setFeature("http://xml.org/sax/features/validation", false);
parser.setFeature("http://xml.org/sax/features/namespaces", true);
parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
} catch ( org.xml.sax.SAXNotRecognizedException e ) {
e.printStackTrace();
} catch ( org.xml.sax.SAXNotSupportedException e ) {
e.printStackTrace();
}
// expand it before passing it to the parser
InputSource source = null;
EntityResolver currentER = parser.getEntityResolver();
if (currentER != null) {
source = currentER.resolveEntity("", loc);
}
if (source == null) {
loc = fEntityHandler.expandSystemId(loc);
source = new InputSource(loc);
}
try {
parser.parse( source );
} catch ( IOException e ) {
e.printStackTrace();
} catch ( SAXException e ) {
//System.out.println("loc = "+loc);
//e.printStackTrace();
reportRecoverableXMLError( XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
XMLMessages.SCHEMA_GENERIC_ERROR, e.getMessage() );
}
Document document = parser.getDocument(); //Our Grammar
TraverseSchema tst = null;
try {
if (DEBUG_SCHEMA_VALIDATION) {
System.out.println("I am geting the Schema Document");
}
Element root = document.getDocumentElement();// This is what we pass to TraverserSchema
if (root == null) {
reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR, XMLMessages.SCHEMA_GENERIC_ERROR, "Can't get back Schema document's root element :" + loc);
} else {
if (uri == null || !uri.equals(root.getAttribute(SchemaSymbols.ATT_TARGETNAMESPACE)) ) {
reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR, XMLMessages.SCHEMA_GENERIC_ERROR, "Schema in " + loc + " has a different target namespace " +
"from the one specified in the instance document :" + uri);
}
grammar = new SchemaGrammar();
grammar.setGrammarDocument(document);
tst = new TraverseSchema( root, fStringPool, (SchemaGrammar)grammar, fGrammarResolver, fErrorReporter, source.getSystemId());
fGrammarResolver.putGrammar(document.getDocumentElement().getAttribute("targetNamespace"), grammar);
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
private void resolveSchemaGrammar(String uri) throws Exception{
resolveSchemaGrammar(uri, uri);
}
static class Resolver implements EntityResolver {
//
// Constants
//
private static final String SYSTEM[] = {
"http://www.w3.org/TR/2000/WD-xmlschema-1-20000407/structures.dtd",
"http://www.w3.org/TR/2000/WD-xmlschema-1-20000407/datatypes.dtd",
"http://www.w3.org/TR/2000/WD-xmlschema-1-20000407/versionInfo.ent",
};
private static final String PATH[] = {
"structures.dtd",
"datatypes.dtd",
"versionInfo.ent",
};
//
// Data
//
private DefaultEntityHandler fEntityHandler;
//
// Constructors
//
public Resolver(DefaultEntityHandler handler) {
fEntityHandler = handler;
}
//
// EntityResolver methods
//
public InputSource resolveEntity(String publicId, String systemId)
throws IOException, SAXException {
// looking for the schema DTDs?
for (int i = 0; i < SYSTEM.length; i++) {
if (systemId.equals(SYSTEM[i])) {
InputSource source = new InputSource(getClass().getResourceAsStream(PATH[i]));
source.setPublicId(publicId);
source.setSystemId(systemId);
return source;
}
}
// first try to resolve using user's entity resolver
EntityResolver resolver = fEntityHandler.getEntityResolver();
if (resolver != null) {
InputSource source = resolver.resolveEntity(publicId, systemId);
if (source != null) {
return source;
}
}
// use default resolution
return new InputSource(fEntityHandler.expandSystemId(systemId));
} // resolveEntity(String,String):InputSource
} // class Resolver
static class ErrorHandler implements org.xml.sax.ErrorHandler {
/** Warning. */
public void warning(SAXParseException ex) {
System.err.println("[Warning] "+
getLocationString(ex)+": "+
ex.getMessage());
}
/** Error. */
public void error(SAXParseException ex) {
System.err.println("[Error] "+
getLocationString(ex)+": "+
ex.getMessage());
}
/** Fatal error. */
public void fatalError(SAXParseException ex) {
System.err.println("[Fatal Error] "+
getLocationString(ex)+": "+
ex.getMessage());
//throw ex;
}
//
// Private methods
//
/** Returns a string of the location. */
private String getLocationString(SAXParseException ex) {
StringBuffer str = new StringBuffer();
String systemId_ = ex.getSystemId();
if (systemId_ != null) {
int index = systemId_.lastIndexOf('/');
if (index != -1)
systemId_ = systemId_.substring(index + 1);
str.append(systemId_);
}
str.append(':');
str.append(ex.getLineNumber());
str.append(':');
str.append(ex.getColumnNumber());
return str.toString();
} // getLocationString(SAXParseException):String
}
private int attributeTypeName(XMLAttributeDecl attrDecl) {
switch (attrDecl.type) {
case XMLAttributeDecl.TYPE_ENTITY: {
return attrDecl.list ? fENTITIESSymbol : fENTITYSymbol;
}
case XMLAttributeDecl.TYPE_ENUMERATION: {
String enumeration = fStringPool.stringListAsString(attrDecl.enumeration);
return fStringPool.addString(enumeration);
}
case XMLAttributeDecl.TYPE_ID: {
return fIDSymbol;
}
case XMLAttributeDecl.TYPE_IDREF: {
return attrDecl.list ? fIDREFSSymbol : fIDREFSymbol;
}
case XMLAttributeDecl.TYPE_NMTOKEN: {
return attrDecl.list ? fNMTOKENSSymbol : fNMTOKENSSymbol;
}
case XMLAttributeDecl.TYPE_NOTATION: {
return fNOTATIONSymbol;
}
}
return fCDATASymbol;
}
/** Validates element and attributes. */
private void validateElementAndAttributes(QName element,
XMLAttrList attrList)
throws Exception {
if ((fElementDepth >= 0 && fValidationFlagStack[fElementDepth] != 0 )||
(fGrammar == null && !fValidating && !fNamespacesEnabled) ) {
fCurrentElementIndex = -1;
fCurrentContentSpecType = -1;
fInElementContent = false;
if (fAttrListHandle != -1) {
fAttrList.endAttrList();
int index = fAttrList.getFirstAttr(fAttrListHandle);
while (index != -1) {
if (fStringPool.equalNames(fAttrList.getAttrName(index), fXMLLang)) {
fDocumentScanner.checkXMLLangAttributeValue(fAttrList.getAttValue(index));
break;
}
index = fAttrList.getNextAttr(index);
}
}
return;
}
int elementIndex = -1;
int contentSpecType = -1;
boolean skipThisOne = false;
boolean laxThisOne = false;
if ( fGrammarIsSchemaGrammar && fContentLeafStack[fElementDepth] != null ) {
ContentLeafNameTypeVector cv = fContentLeafStack[fElementDepth];
QName[] fElemMap = cv.leafNames;
for (int i=0; i<cv.leafCount; i++) {
int type = cv.leafTypes[i] ;
//System.out.println("******* see a ANY_OTHER_SKIP, "+type+","+element+","+fElemMap[i]+"\n*******");
if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
if (fElemMap[i].uri==element.uri
&& fElemMap[i].localpart == element.localpart)
break;
} else if (type == XMLContentSpec.CONTENTSPECNODE_ANY) {
int uri = fElemMap[i].uri;
if (uri == -1 || uri == element.uri) {
break;
}
} else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) {
if (element.uri == -1) {
break;
}
} else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) {
if (fElemMap[i].uri != element.uri) {
break;
}
} else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_SKIP) {
int uri = fElemMap[i].uri;
if (uri == -1 || uri == element.uri) {
skipThisOne = true;
break;
}
} else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL_SKIP) {
if (element.uri == -1) {
skipThisOne = true;
break;
}
} else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER_SKIP) {
if (fElemMap[i].uri != element.uri) {
skipThisOne = true;
break;
}
} else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_LAX) {
int uri = fElemMap[i].uri;
if (uri == -1 || uri == element.uri) {
laxThisOne = true;
break;
}
} else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL_LAX) {
if (element.uri == -1) {
laxThisOne = true;
break;
}
} else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER_LAX) {
if (fElemMap[i].uri != element.uri) {
laxThisOne = true;
break;
}
}
}
}
if (skipThisOne) {
fNeedValidationOff = true;
} else {
//REVISIT: is this the right place to check on if the Schema has changed?
if ( fNamespacesEnabled && fValidating && element.uri != fGrammarNameSpaceIndex && element.uri != -1 ) {
fGrammarNameSpaceIndex = element.uri;
boolean success = switchGrammar(fGrammarNameSpaceIndex);
if (!success && !laxThisOne) {
reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR, XMLMessages.SCHEMA_GENERIC_ERROR,
"Grammar with uri : " + fStringPool.toString(fGrammarNameSpaceIndex)
+ " , can not found");
}
}
if ( fGrammar != null ) {
if (DEBUG_SCHEMA_VALIDATION) {
System.out.println("*******Lookup element: uri: " + fStringPool.toString(element.uri)+
"localpart: '" + fStringPool.toString(element.localpart)
+"' and scope : " + fCurrentScope+"\n");
}
elementIndex = fGrammar.getElementDeclIndex(element,fCurrentScope);
if (elementIndex == -1 ) {
elementIndex = fGrammar.getElementDeclIndex(element, TOP_LEVEL_SCOPE);
}
if (elementIndex == -1) {
// if validating based on a Schema, try to resolve the element again by look it up in its ancestor types
if (fGrammarIsSchemaGrammar && fCurrentElementIndex != -1) {
TraverseSchema.ComplexTypeInfo baseTypeInfo = null;
baseTypeInfo = ((SchemaGrammar)fGrammar).getElementComplexTypeInfo(fCurrentElementIndex);
//TO DO:
// should check if baseTypeInfo is from the same Schema.
while (baseTypeInfo != null) {
elementIndex = fGrammar.getElementDeclIndex(element, baseTypeInfo.scopeDefined);
if (elementIndex > -1 ) {
break;
}
baseTypeInfo = baseTypeInfo.baseComplexTypeInfo;
}
}
//if still can't resolve it, try TOP_LEVEL_SCOPE AGAIN
/****
if ( element.uri == -1 && elementIndex == -1
&& fNamespacesScope != null
&& fNamespacesScope.getNamespaceForPrefix(StringPool.EMPTY_STRING) != -1 ) {
elementIndex = fGrammar.getElementDeclIndex(element.localpart, TOP_LEVEL_SCOPE);
// REVISIT:
// this is a hack to handle the situation where namespace prefix "" is bound to nothing, and there
// is a "noNamespaceSchemaLocation" specified, and element
element.uri = StringPool.EMPTY_STRING;
}
/****/
/****/
if (elementIndex == -1) {
if (laxThisOne) {
fNeedValidationOff = true;
} else
if (DEBUG_SCHEMA_VALIDATION)
System.out.println("!!! can not find elementDecl in the grammar, " +
" the element localpart: " + element.localpart +
"["+fStringPool.toString(element.localpart) +"]" +
" the element uri: " + element.uri +
"["+fStringPool.toString(element.uri) +"]" +
" and the current enclosing scope: " + fCurrentScope );
}
/****/
}
if (DEBUG_SCHEMA_VALIDATION) {
fGrammar.getElementDecl(elementIndex, fTempElementDecl);
System.out.println("elementIndex: " + elementIndex+" \n and itsName : '"
+ fStringPool.toString(fTempElementDecl.name.localpart)
+"' \n its ContentType:" + fTempElementDecl.type
+"\n its ContentSpecIndex : " + fTempElementDecl.contentSpecIndex +"\n"+
" and the current enclosing scope: " + fCurrentScope);
}
}
contentSpecType = getContentSpecType(elementIndex);
if (fGrammarIsSchemaGrammar && elementIndex != -1) {
// handle "xsi:type" right here
if (fXsiTypeAttValue > -1) {
String xsiType = fStringPool.toString(fXsiTypeAttValue);
int colonP = xsiType.indexOf(":");
String prefix = "";
String localpart = xsiType;
if (colonP > -1) {
prefix = xsiType.substring(0,colonP);
localpart = xsiType.substring(colonP+1);
}
String uri = "";
int uriIndex = -1;
if (fNamespacesScope != null) {
uriIndex = fNamespacesScope.getNamespaceForPrefix(fStringPool.addSymbol(prefix));
if (uriIndex > -1) {
uri = fStringPool.toString(uriIndex);
if (uriIndex != fGrammarNameSpaceIndex) {
fGrammarNameSpaceIndex = fCurrentSchemaURI = uriIndex;
boolean success = switchGrammar(fCurrentSchemaURI);
if (!success && !fNeedValidationOff) {
reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
XMLMessages.SCHEMA_GENERIC_ERROR,
"Grammar with uri : "
+ fStringPool.toString(fCurrentSchemaURI)
+ " , can not found");
}
}
}
}
Hashtable complexRegistry = ((SchemaGrammar)fGrammar).getComplexTypeRegistry();
DatatypeValidatorFactoryImpl dataTypeReg = ((SchemaGrammar)fGrammar).getDatatypeRegistry();
if (complexRegistry==null || dataTypeReg == null) {
reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
XMLMessages.SCHEMA_GENERIC_ERROR,
fErrorReporter.getLocator().getSystemId()
+" line"+fErrorReporter.getLocator().getLineNumber()
+", canot resolve xsi:type = " + xsiType+" ---2");
} else {
TraverseSchema.ComplexTypeInfo typeInfo =
(TraverseSchema.ComplexTypeInfo) complexRegistry.get(uri+","+localpart);
//TO DO:
// here need to check if this substitution is legal based on the current active grammar,
// this should be easy, cause we already saved final, block and base type information in
// the SchemaGrammar.
if (typeInfo==null) {
if (uri.length() == 0 || uri.equals(SchemaSymbols.URI_SCHEMAFORSCHEMA) ) {
fXsiTypeValidator = dataTypeReg.getDatatypeValidator(localpart);
} else
fXsiTypeValidator = dataTypeReg.getDatatypeValidator(uri+","+localpart);
if ( fXsiTypeValidator == null )
reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
XMLMessages.SCHEMA_GENERIC_ERROR,
"unresolved type : "+uri+","+localpart
+" found in xsi:type handling");
} else
elementIndex = typeInfo.templateElementIndex;
}
fXsiTypeAttValue = -1;
}
//Change the current scope to be the one defined by this element.
fCurrentScope = ((SchemaGrammar) fGrammar).getElementDefinedScope(elementIndex);
// here need to check if we need to switch Grammar by asking SchemaGrammar whether
// this element actually is of a type in another Schema.
String anotherSchemaURI = ((SchemaGrammar)fGrammar).getElementFromAnotherSchemaURI(elementIndex);
if (anotherSchemaURI != null) {
//before switch Grammar, set the elementIndex to be the template elementIndex of its type
if (contentSpecType != -1
&& contentSpecType != XMLElementDecl.TYPE_EMPTY ) {
TraverseSchema.ComplexTypeInfo typeInfo = ((SchemaGrammar) fGrammar).getElementComplexTypeInfo(elementIndex);
if (typeInfo != null) {
elementIndex = typeInfo.templateElementIndex;
}
}
// now switch the grammar
fGrammarNameSpaceIndex = fCurrentSchemaURI = fStringPool.addSymbol(anotherSchemaURI);
boolean success = switchGrammar(fCurrentSchemaURI);
if (!success && !fNeedValidationOff) {
reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
XMLMessages.SCHEMA_GENERIC_ERROR,
"Grammar with uri : "
+ fStringPool.toString(fCurrentSchemaURI)
+ " , can not found");
}
}
}
if (contentSpecType == -1 && fValidating && !fNeedValidationOff ) {
reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED,
XMLMessages.VC_ELEMENT_VALID,
element.rawname);
}
if (fGrammar != null && fGrammarIsSchemaGrammar && elementIndex != -1) {
fAttrListHandle = addDefaultAttributes(elementIndex, attrList, fAttrListHandle, fValidating, fStandaloneReader != -1);
}
if (fAttrListHandle != -1) {
fAttrList.endAttrList();
}
if (DEBUG_PRINT_ATTRIBUTES) {
String elementStr = fStringPool.toString(element.rawname);
System.out.print("startElement: <" + elementStr);
if (fAttrListHandle != -1) {
int index = attrList.getFirstAttr(fAttrListHandle);
while (index != -1) {
System.out.print(" " + fStringPool.toString(attrList.getAttrName(index)) + "=\"" +
fStringPool.toString(attrList.getAttValue(index)) + "\"");
index = attrList.getNextAttr(index);
}
}
System.out.println(">");
}
// REVISIT: Validation. Do we need to recheck for the xml:lang
// attribute? It was already checked above -- perhaps
// this is to check values that are defaulted in? If
// so, this check could move to the attribute decl
// callback so we can check the default value before
// it is used.
if (fAttrListHandle != -1 && !fNeedValidationOff ) {
int index = fAttrList.getFirstAttr(fAttrListHandle);
while (index != -1) {
int attrNameIndex = attrList.getAttrName(index);
if (fStringPool.equalNames(attrNameIndex, fXMLLang)) {
fDocumentScanner.checkXMLLangAttributeValue(attrList.getAttValue(index));
// break;
}
// here, we validate every "user-defined" attributes
int _xmlns = fStringPool.addSymbol("xmlns");
if (attrNameIndex != _xmlns && attrList.getAttrPrefix(index) != _xmlns)
if (fGrammar != null) {
fAttrNameLocator = getLocatorImpl(fAttrNameLocator);
fTempQName.setValues(attrList.getAttrPrefix(index),
attrList.getAttrLocalpart(index),
attrList.getAttrName(index),
attrList.getAttrURI(index) );
int attDefIndex = getAttDefByElementIndex(elementIndex, fTempQName);
if (fTempQName.uri != fXsiURI)
if (attDefIndex == -1 ) {
if (fValidating) {
// REVISIT - cache the elem/attr tuple so that we only give
// this error once for each unique occurrence
Object[] args = { fStringPool.toString(element.rawname),
fStringPool.toString(attrList.getAttrName(index))};
/*****/
fErrorReporter.reportError(fAttrNameLocator,
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_ATTRIBUTE_NOT_DECLARED,
XMLMessages.VC_ATTRIBUTE_VALUE_TYPE,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
/******/
}
} else {
fGrammar.getAttributeDecl(attDefIndex, fTempAttDecl);
int attributeType = attributeTypeName(fTempAttDecl);
attrList.setAttType(index, attributeType);
if (fValidating) {
if (fGrammarIsDTDGrammar &&
(fTempAttDecl.type == XMLAttributeDecl.TYPE_ENTITY ||
fTempAttDecl.type == XMLAttributeDecl.TYPE_ENUMERATION ||
fTempAttDecl.type == XMLAttributeDecl.TYPE_ID ||
fTempAttDecl.type == XMLAttributeDecl.TYPE_IDREF ||
fTempAttDecl.type == XMLAttributeDecl.TYPE_NMTOKEN ||
fTempAttDecl.type == XMLAttributeDecl.TYPE_NOTATION)
) {
validateDTDattribute(element, attrList.getAttValue(index), fTempAttDecl);
}
// check to see if this attribute matched an attribute wildcard
else if ( fGrammarIsSchemaGrammar &&
(fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_ANY
||fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_LIST
||fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_LOCAL
||fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_OTHER) ) {
if (fTempAttDecl.defaultType == XMLAttributeDecl.PROCESSCONTENTS_SKIP) {
// attribute should just be bypassed,
} else if ( fTempAttDecl.defaultType == XMLAttributeDecl.PROCESSCONTENTS_STRICT
|| fTempAttDecl.defaultType == XMLAttributeDecl.PROCESSCONTENTS_LAX) {
boolean reportError = false;
boolean processContentStrict =
fTempAttDecl.defaultType == XMLAttributeDecl.PROCESSCONTENTS_STRICT;
if (fTempQName.uri == -1) {
if (processContentStrict) {
reportError = true;
}
} else {
Grammar aGrammar =
fGrammarResolver.getGrammar(fStringPool.toString(fTempQName.uri));
if (aGrammar == null || !(aGrammar instanceof SchemaGrammar) ) {
if (processContentStrict) {
reportError = true;
}
} else {
SchemaGrammar sGrammar = (SchemaGrammar) aGrammar;
Hashtable attRegistry = sGrammar.getAttirubteDeclRegistry();
if (attRegistry == null) {
if (processContentStrict) {
reportError = true;
}
} else {
XMLAttributeDecl attDecl = (XMLAttributeDecl) attRegistry.get(fStringPool.toString(fTempQName.localpart));
if (attDecl == null) {
if (processContentStrict) {
reportError = true;
}
} else {
DatatypeValidator attDV = attDecl.datatypeValidator;
if (attDV == null) {
if (processContentStrict) {
reportError = true;
}
} else {
try {
String unTrimValue = fStringPool.toString(attrList.getAttValue(index));
String value = unTrimValue.trim();
if (attDecl.type == XMLAttributeDecl.TYPE_ID ) {
this.fStoreIDRef.setDatatypeObject( fValID.validate( value, null ) );
}
if (attDecl.type == XMLAttributeDecl.TYPE_IDREF ) {
attDV.validate(value, this.fStoreIDRef );
} else
attDV.validate(unTrimValue, null );
} catch (InvalidDatatypeValueException idve) {
fErrorReporter.reportError(fErrorReporter.getLocator(),
SchemaMessageProvider.SCHEMA_DOMAIN,
SchemaMessageProvider.DatatypeError,
SchemaMessageProvider.MSG_NONE,
new Object [] { idve.getMessage()},
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
}
}
}
}
}
if (reportError) {
Object[] args = { fStringPool.toString(element.rawname),
"ANY---"+fStringPool.toString(attrList.getAttrName(index))};
fErrorReporter.reportError(fAttrNameLocator,
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_ATTRIBUTE_NOT_DECLARED,
XMLMessages.VC_ATTRIBUTE_VALUE_TYPE,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
}
} else if (fTempAttDecl.datatypeValidator == null) {
Object[] args = { fStringPool.toString(element.rawname),
fStringPool.toString(attrList.getAttrName(index))};
System.out.println("[Error] Datatypevalidator for attribute " + fStringPool.toString(attrList.getAttrName(index))
+ " not found in element type " + fStringPool.toString(element.rawname));
//REVISIT : is this the right message?
/****/
fErrorReporter.reportError(fAttrNameLocator,
XMLMessages.XML_DOMAIN,
XMLMessages.MSG_ATTRIBUTE_NOT_DECLARED,
XMLMessages.VC_ATTRIBUTE_VALUE_TYPE,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
/****/
} else {
try {
String unTrimValue = fStringPool.toString(attrList.getAttValue(index));
String value = unTrimValue.trim();
if (fTempAttDecl.type == XMLAttributeDecl.TYPE_ID ) {
this.fStoreIDRef.setDatatypeObject( fValID.validate( value, null ) );
} else if (fTempAttDecl.type == XMLAttributeDecl.TYPE_IDREF ) {
fTempAttDecl.datatypeValidator.validate(value, this.fStoreIDRef );
} else {
fTempAttDecl.datatypeValidator.validate(unTrimValue, null );
}
} catch (InvalidDatatypeValueException idve) {
fErrorReporter.reportError(fErrorReporter.getLocator(),
SchemaMessageProvider.SCHEMA_DOMAIN,
SchemaMessageProvider.DatatypeError,
SchemaMessageProvider.MSG_NONE,
new Object [] { idve.getMessage()},
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
}
} // end of if (fValidating)
} // end of if (attDefIndex == -1) else
}// end of if (fGrammar != null)
index = fAttrList.getNextAttr(index);
}
}
}
if (fAttrListHandle != -1) {
int index = attrList.getFirstAttr(fAttrListHandle);
while (index != -1) {
int attName = attrList.getAttrName(index);
if (!fStringPool.equalNames(attName, fNamespacesPrefix)) {
int attPrefix = attrList.getAttrPrefix(index);
if (attPrefix != fNamespacesPrefix) {
if (attPrefix != -1) {
int uri = fNamespacesScope.getNamespaceForPrefix(attPrefix);
if (uri == -1) {
Object[] args = { fStringPool.toString(attPrefix)};
fErrorReporter.reportError(fErrorReporter.getLocator(),
XMLMessages.XMLNS_DOMAIN,
XMLMessages.MSG_PREFIX_DECLARED,
XMLMessages.NC_PREFIX_DECLARED,
args,
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
attrList.setAttrURI(index, uri);
}
}
}
index = attrList.getNextAttr(index);
}
}
fCurrentElementIndex = elementIndex;
fCurrentContentSpecType = contentSpecType;
if (fValidating && contentSpecType == XMLElementDecl.TYPE_SIMPLE) {
fBufferDatatype = true;
fDatatypeBuffer.setLength(0);
}
fInElementContent = (contentSpecType == XMLElementDecl.TYPE_CHILDREN);
} // validateElementAndAttributes(QName,XMLAttrList)
//validate attributes in DTD fashion
private void validateDTDattribute(QName element, int attValue,
XMLAttributeDecl attributeDecl) throws Exception{
AttributeValidator av = null;
switch (attributeDecl.type) {
case XMLAttributeDecl.TYPE_ENTITY:
{
boolean isAlistAttribute = attributeDecl.list;//Caveat - Save this information because invalidStandaloneAttDef
String unTrimValue = fStringPool.toString(attValue);
String value = unTrimValue.trim();
//System.out.println("value = " + value );
//changes fTempAttDef
if (fValidationEnabled) {
if (value != unTrimValue) {
if (invalidStandaloneAttDef(element, attributeDecl.name)) {
reportRecoverableXMLError(XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
fStringPool.toString(attributeDecl.name.rawname), unTrimValue, value);
}
}
}
try {
if ( isAlistAttribute ) {
fValENTITIES.validate( value, null );
} else {
fValENTITY.validate( value, null );
}
} catch ( InvalidDatatypeValueException ex ) {
if ( ex.getMajorCode() != 1 && ex.getMinorCode() != -1 ) {
reportRecoverableXMLError(ex.getMajorCode(),
ex.getMinorCode(),
fStringPool.toString( attributeDecl.name.rawname), value );
} else {
System.err.println("Error: " + ex.getLocalizedMessage() );//Should not happen
}
}
/*if (attributeDecl.list) {
av = fAttValidatorENTITIES;
}
else {
av = fAttValidatorENTITY;
}*/
}
break;
case XMLAttributeDecl.TYPE_ENUMERATION:
av = fAttValidatorENUMERATION;
break;
case XMLAttributeDecl.TYPE_ID:
{
String unTrimValue = fStringPool.toString(attValue);
String value = unTrimValue.trim();
if (fValidationEnabled) {
if (value != unTrimValue) {
if (invalidStandaloneAttDef(element, attributeDecl.name)) {
reportRecoverableXMLError(XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
fStringPool.toString(attributeDecl.name.rawname), unTrimValue, value);
}
}
}
try {
//this.fIdDefs = (Hashtable) fValID.validate( value, null );
//System.out.println("this.fIdDefs = " + this.fIdDefs );
this.fStoreIDRef.setDatatypeObject( fValID.validate( value, null ) );
fValIDRef.validate( value, this.fStoreIDRef ); //just in case we called id after IDREF
} catch ( InvalidDatatypeValueException ex ) {
reportRecoverableXMLError(ex.getMajorCode(),
ex.getMinorCode(),
fStringPool.toString( attributeDecl.name.rawname), value );
}
}
break;
case XMLAttributeDecl.TYPE_IDREF:
{
String unTrimValue = fStringPool.toString(attValue);
String value = unTrimValue.trim();
boolean isAlistAttribute = attributeDecl.list;//Caveat - Save this information because invalidStandaloneAttDef
//changes fTempAttDef
if (fValidationEnabled) {
if (value != unTrimValue) {
if (invalidStandaloneAttDef(element, attributeDecl.name)) {
reportRecoverableXMLError(XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
fStringPool.toString(attributeDecl.name.rawname), unTrimValue, value);
}
}
}
try {
if ( isAlistAttribute ) {
fValIDRefs.validate( value, this.fStoreIDRef );
} else {
fValIDRef.validate( value, this.fStoreIDRef );
}
} catch ( InvalidDatatypeValueException ex ) {
if ( ex.getMajorCode() != 1 && ex.getMinorCode() != -1 ) {
reportRecoverableXMLError(ex.getMajorCode(),
ex.getMinorCode(),
fStringPool.toString( attributeDecl.name.rawname), value );
} else {
System.err.println("Error: " + ex.getLocalizedMessage() );//Should not happen
}
}
}
break;
case XMLAttributeDecl.TYPE_NOTATION:
{
/* WIP
String unTrimValue = fStringPool.toString(attValue);
String value = unTrimValue.trim();
if (fValidationEnabled) {
if (value != unTrimValue) {
if (invalidStandaloneAttDef(element, attributeDecl.name)) {
reportRecoverableXMLError(XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
fStringPool.toString(attributeDecl.name.rawname), unTrimValue, value);
}
}
}
try {
//this.fIdDefs = (Hashtable) fValID.validate( value, null );
//System.out.println("this.fIdDefs = " + this.fIdDefs );
this.fStoreIDRef.setDatatypeObject( fValID.validate( value, null ) );
} catch ( InvalidDatatypeValueException ex ) {
reportRecoverableXMLError(ex.getMajorCode(),
ex.getMinorCode(),
fStringPool.toString( attributeDecl.name.rawname), value );
}
}
*/
av = fAttValidatorNOTATION;
}
break;
case XMLAttributeDecl.TYPE_NMTOKEN:
{
String unTrimValue = fStringPool.toString(attValue);
String value = unTrimValue.trim();
boolean isAlistAttribute = attributeDecl.list;//Caveat - Save this information because invalidStandaloneAttDef
//changes fTempAttDef
if (fValidationEnabled) {
if (value != unTrimValue) {
if (invalidStandaloneAttDef(element, attributeDecl.name)) {
reportRecoverableXMLError(XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
fStringPool.toString(attributeDecl.name.rawname), unTrimValue, value);
}
}
}
try {
if ( isAlistAttribute ) {
fValNMTOKENS.validate( value, null );
} else {
fValNMTOKEN.validate( value, null );
}
} catch ( InvalidDatatypeValueException ex ) {
reportRecoverableXMLError(XMLMessages.MSG_NMTOKEN_INVALID,
XMLMessages.VC_NAME_TOKEN,
fStringPool.toString(attributeDecl.name.rawname), value);//TODO NMTOKENS messge
}
}
break;
}
if ( av != null )
av.normalize(element, attributeDecl.name, attValue,
attributeDecl.type, attributeDecl.enumeration);
}
/** Character data in content. */
private void charDataInContent() {
if (DEBUG_ELEMENT_CHILDREN) {
System.out.println("charDataInContent()");
}
if (fElementChildren.length <= fElementChildrenLength) {
QName[] newarray = new QName[fElementChildren.length * 2];
System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length);
fElementChildren = newarray;
}
QName qname = fElementChildren[fElementChildrenLength];
if (qname == null) {
for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
fElementChildren[i] = new QName();
}
qname = fElementChildren[fElementChildrenLength];
}
qname.clear();
fElementChildrenLength++;
} // charDataInCount()
/**
* Check that the content of an element is valid.
* <p>
* This is the method of primary concern to the validator. This method is called
* upon the scanner reaching the end tag of an element. At that time, the
* element's children must be structurally validated, so it calls this method.
* The index of the element being checked (in the decl pool), is provided as
* well as an array of element name indexes of the children. The validator must
* confirm that this element can have these children in this order.
* <p>
* This can also be called to do 'what if' testing of content models just to see
* if they would be valid.
* <p>
* Note that the element index is an index into the element decl pool, whereas
* the children indexes are name indexes, i.e. into the string pool.
* <p>
* A value of -1 in the children array indicates a PCDATA node. All other
* indexes will be positive and represent child elements. The count can be
* zero, since some elements have the EMPTY content model and that must be
* confirmed.
*
* @param elementIndex The index within the <code>ElementDeclPool</code> of this
* element.
* @param childCount The number of entries in the <code>children</code> array.
* @param children The children of this element. Each integer is an index within
* the <code>StringPool</code> of the child element name. An index
* of -1 is used to indicate an occurrence of non-whitespace character
* data.
*
* @return The value -1 if fully valid, else the 0 based index of the child
* that first failed. If the value returned is equal to the number
* of children, then additional content is required to reach a valid
* ending state.
*
* @exception Exception Thrown on error.
*/
private int checkContent(int elementIndex,
QName[] children,
int childOffset,
int childCount) throws Exception {
// Get the element name index from the element
// REVISIT: Validation
final int elementType = fCurrentElement.rawname;
if (DEBUG_PRINT_CONTENT) {
String strTmp = fStringPool.toString(elementType);
System.out.println("Name: "+strTmp+", "+
"Count: "+childCount+", "+
"ContentSpecType: " +fCurrentContentSpecType); //+getContentSpecAsString(elementIndex));
for (int index = childOffset; index < (childOffset+childCount) && index < 10; index++) {
if (index == 0) {
System.out.print(" (");
}
String childName = (children[index].localpart == -1) ? "#PCDATA" : fStringPool.toString(children[index].localpart);
if (index + 1 == childCount) {
System.out.println(childName + ")");
} else if (index + 1 == 10) {
System.out.println(childName + ",...)");
} else {
System.out.print(childName + ",");
}
}
}
// Get out the content spec for this element
final int contentType = fCurrentContentSpecType;
// debugging
//System.out.println("~~~~~~in checkContent, fCurrentContentSpecType : " + fCurrentContentSpecType);
//
// Deal with the possible types of content. We try to optimized here
// by dealing specially with content models that don't require the
// full DFA treatment.
//
if (contentType == XMLElementDecl.TYPE_EMPTY) {
//
// If the child count is greater than zero, then this is
// an error right off the bat at index 0.
//
if (childCount != 0) {
return 0;
}
} else if (contentType == XMLElementDecl.TYPE_ANY) {
//
// This one is open game so we don't pass any judgement on it
// at all. Its assumed to fine since it can hold anything.
//
} else if (contentType == XMLElementDecl.TYPE_MIXED ||
contentType == XMLElementDecl.TYPE_CHILDREN) {
// Get the content model for this element, faulting it in if needed
XMLContentModel cmElem = null;
try {
cmElem = getElementContentModel(elementIndex);
int result = cmElem.validateContent(children, childOffset, childCount);
if (result != -1 && fGrammarIsSchemaGrammar) {
// REVISIT: not optimized for performance,
EquivClassComparator comparator = new EquivClassComparator(fGrammarResolver, fStringPool);
cmElem.setEquivClassComparator(comparator);
result = cmElem.validateContentSpecial(children, childOffset, childCount);
}
return result;
} catch (CMException excToCatch) {
// REVISIT - Translate the caught exception to the protected error API
int majorCode = excToCatch.getErrorCode();
fErrorReporter.reportError(fErrorReporter.getLocator(),
ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
majorCode,
0,
null,
XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
}
} else if (contentType == -1) {
reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED,
XMLMessages.VC_ELEMENT_VALID,
elementType);
} else if (contentType == XMLElementDecl.TYPE_SIMPLE ) {
XMLContentModel cmElem = null;
if (childCount > 0) {
fErrorReporter.reportError(fErrorReporter.getLocator(),
SchemaMessageProvider.SCHEMA_DOMAIN,
SchemaMessageProvider.DatatypeError,
SchemaMessageProvider.MSG_NONE,
new Object [] { "In element '"+fStringPool.toString(elementType)+"' : "+
"Can not have element children within a simple type content"},
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
} else {
try {
fGrammar.getElementDecl(elementIndex, fTempElementDecl);
DatatypeValidator dv = fTempElementDecl.datatypeValidator;
// If there is xsi:type validator, substitute it.
if ( fXsiTypeValidator != null ) {
dv = fXsiTypeValidator;
fXsiTypeValidator = null;
}
if (dv == null) {
System.out.println("Internal Error: this element have a simpletype "+
"but no datatypevalidator was found, element "+fTempElementDecl.name
+",locapart: "+fStringPool.toString(fTempElementDecl.name.localpart));
} else {
dv.validate(fDatatypeBuffer.toString(), null);
}
} catch (InvalidDatatypeValueException idve) {
fErrorReporter.reportError(fErrorReporter.getLocator(),
SchemaMessageProvider.SCHEMA_DOMAIN,
SchemaMessageProvider.DatatypeError,
SchemaMessageProvider.MSG_NONE,
new Object [] { idve.getMessage()},
XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
}
}
} else {
fErrorReporter.reportError(fErrorReporter.getLocator(),
ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
ImplementationMessages.VAL_CST,
0,
null,
XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
}
// We succeeded
return -1;
} // checkContent(int,int,int[]):int
/**
* Checks that all declared elements refer to declared elements
* in their content models. This method calls out to the error
* handler to indicate warnings.
*/
/*private void checkDeclaredElements() throws Exception {
//****DEBUG****
if (DEBUG) print("(???) XMLValidator.checkDeclaredElements\n");
//****DEBUG****
for (int i = 0; i < fElementCount; i++) {
int type = fGrammar.getContentSpecType(i);
if (type == XMLElementDecl.TYPE_MIXED || type == XMLElementDecl.TYPE_CHILDREN) {
int chunk = i >> CHUNK_SHIFT;
int index = i & CHUNK_MASK;
int contentSpecIndex = fContentSpec[chunk][index];
checkDeclaredElements(i, contentSpecIndex);
}
}
}
*/
private void printChildren() {
if (DEBUG_ELEMENT_CHILDREN) {
System.out.print('[');
for (int i = 0; i < fElementChildrenLength; i++) {
System.out.print(' ');
QName qname = fElementChildren[i];
if (qname != null) {
System.out.print(fStringPool.toString(qname.rawname));
} else {
System.out.print("null");
}
if (i < fElementChildrenLength - 1) {
System.out.print(", ");
}
System.out.flush();
}
System.out.print(" ]");
System.out.println();
}
}
private void printStack() {
if (DEBUG_ELEMENT_CHILDREN) {
System.out.print('{');
for (int i = 0; i <= fElementDepth; i++) {
System.out.print(' ');
System.out.print(fElementChildrenOffsetStack[i]);
if (i < fElementDepth) {
System.out.print(", ");
}
System.out.flush();
}
System.out.print(" }");
System.out.println();
}
}
//
// Interfaces
//
/**
* AttributeValidator.
*/
public interface AttributeValidator {
//
// AttributeValidator methods
//
/** Normalize. */
public int normalize(QName element, QName attribute,
int attValue, int attType, int enumHandle)
throws Exception;
} // interface AttributeValidator
/** Returns true if invalid standalone attribute definition. */
boolean invalidStandaloneAttDef(QName element, QName attribute) {
if (fStandaloneReader == -1) {
return false;
}
// we are normalizing a default att value... this ok?
if (element.rawname == -1) {
return false;
}
return getAttDefIsExternal(element, attribute);
}
//
// Classes
//
/**
* AttValidatorNOTATION.
*/
final class AttValidatorNOTATION
implements AttributeValidator {
//
// AttributeValidator methods
//
/** Normalize. */
public int normalize(QName element, QName attribute,
int attValueHandle, int attType,
int enumHandle) throws Exception {
//
// Normalize attribute based upon attribute type...
//
String attValue = fStringPool.toString(attValueHandle);
String newAttValue = attValue.trim();
if (fValidating) {
// REVISIT - can we release the old string?
if (newAttValue != attValue) {
if (invalidStandaloneAttDef(element, attribute)) {
reportRecoverableXMLError(XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
fStringPool.toString(attribute.rawname), attValue, newAttValue);
}
attValueHandle = fStringPool.addSymbol(newAttValue);
} else {
attValueHandle = fStringPool.addSymbol(attValueHandle);
}
//
// NOTATION - check that the value is in the AttDef enumeration (V_TAGo)
//
if (!fStringPool.stringInList(enumHandle, attValueHandle)) {
reportRecoverableXMLError(XMLMessages.MSG_ATTRIBUTE_VALUE_NOT_IN_LIST,
XMLMessages.VC_NOTATION_ATTRIBUTES,
fStringPool.toString(attribute.rawname),
newAttValue, fStringPool.stringListAsString(enumHandle));
}
} else if (newAttValue != attValue) {
// REVISIT - can we release the old string?
attValueHandle = fStringPool.addSymbol(newAttValue);
}
return attValueHandle;
} // normalize(QName,QName,int,int,int):int
//
// Package methods
//
/** Returns true if invalid standalone attribute definition. */
boolean invalidStandaloneAttDef(QName element, QName attribute) {
if (fStandaloneReader == -1) {
return false;
}
// we are normalizing a default att value... this ok?
if (element.rawname == -1) {
return false;
}
return getAttDefIsExternal(element, attribute);
}
} // class AttValidatorNOTATION
/**
* AttValidatorENUMERATION.
*/
final class AttValidatorENUMERATION
implements AttributeValidator {
//
// AttributeValidator methods
//
/** Normalize. */
public int normalize(QName element, QName attribute,
int attValueHandle, int attType,
int enumHandle) throws Exception {
//
// Normalize attribute based upon attribute type...
//
String attValue = fStringPool.toString(attValueHandle);
String newAttValue = attValue.trim();
if (fValidating) {
// REVISIT - can we release the old string?
if (newAttValue != attValue) {
if (invalidStandaloneAttDef(element, attribute)) {
reportRecoverableXMLError(XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
fStringPool.toString(attribute.rawname), attValue, newAttValue);
}
attValueHandle = fStringPool.addSymbol(newAttValue);
} else {
attValueHandle = fStringPool.addSymbol(attValueHandle);
}
//
// ENUMERATION - check that value is in the AttDef enumeration (V_TAG9)
//
if (!fStringPool.stringInList(enumHandle, attValueHandle)) {
reportRecoverableXMLError(XMLMessages.MSG_ATTRIBUTE_VALUE_NOT_IN_LIST,
XMLMessages.VC_ENUMERATION,
fStringPool.toString(attribute.rawname),
newAttValue, fStringPool.stringListAsString(enumHandle));
}
} else if (newAttValue != attValue) {
// REVISIT - can we release the old string?
attValueHandle = fStringPool.addSymbol(newAttValue);
}
return attValueHandle;
} // normalize(QName,QName,int,int,int):int
//
// Package methods
//
/** Returns true if invalid standalone attribute definition. */
boolean invalidStandaloneAttDef(QName element, QName attribute) {
if (fStandaloneReader == -1) {
return false;
}
// we are normalizing a default att value... this ok?
if (element.rawname == -1) {
return false;
}
return getAttDefIsExternal(element, attribute);
}
} // class AttValidatorENUMERATION
} // class XMLValidator