| /* |
| * 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 |