0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: *
0005: * Copyright (c) 1999,2000,2001 The Apache Software Foundation.
0006: * All rights reserved.
0007: *
0008: * Redistribution and use in source and binary forms, with or without
0009: * modification, are permitted provided that the following conditions
0010: * are met:
0011: *
0012: * 1. Redistributions of source code must retain the above copyright
0013: * notice, this list of conditions and the following disclaimer.
0014: *
0015: * 2. Redistributions in binary form must reproduce the above copyright
0016: * notice, this list of conditions and the following disclaimer in
0017: * the documentation and/or other materials provided with the
0018: * distribution.
0019: *
0020: * 3. The end-user documentation included with the redistribution,
0021: * if any, must include the following acknowledgment:
0022: * "This product includes software developed by the
0023: * Apache Software Foundation (http://www.apache.org/)."
0024: * Alternately, this acknowledgment may appear in the software itself,
0025: * if and wherever such third-party acknowledgments normally appear.
0026: *
0027: * 4. The names "Xerces" and "Apache Software Foundation" must
0028: * not be used to endorse or promote products derived from this
0029: * software without prior written permission. For written
0030: * permission, please contact apache@apache.org.
0031: *
0032: * 5. Products derived from this software may not be called "Apache",
0033: * nor may "Apache" appear in their name, without prior written
0034: * permission of the Apache Software Foundation.
0035: *
0036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047: * SUCH DAMAGE.
0048: * ====================================================================
0049: *
0050: * This software consists of voluntary contributions made by many
0051: * individuals on behalf of the Apache Software Foundation and was
0052: * originally based on software copyright (c) 1999, International
0053: * Business Machines, Inc., http://www.apache.org. For more
0054: * information on the Apache Software Foundation, please see
0055: * <http://www.apache.org/>.
0056: */
0057:
0058: package org.apache.xerces.validators.common;
0059:
0060: import org.apache.xerces.framework.XMLAttrList;
0061: import org.apache.xerces.framework.XMLContentSpec;
0062: import org.apache.xerces.framework.XMLDocumentHandler;
0063: import org.apache.xerces.framework.XMLDocumentScanner;
0064: import org.apache.xerces.framework.XMLErrorReporter;
0065: import org.apache.xerces.readers.DefaultEntityHandler;
0066: import org.apache.xerces.readers.XMLEntityHandler;
0067: import org.apache.xerces.utils.ChunkyCharArray;
0068: import org.apache.xerces.utils.Hash2intTable;
0069: import org.apache.xerces.utils.IntStack;
0070: import org.apache.xerces.utils.NamespacesScope;
0071: import org.apache.xerces.utils.QName;
0072: import org.apache.xerces.utils.StringPool;
0073: import org.apache.xerces.utils.XMLCharacterProperties;
0074: import org.apache.xerces.utils.XMLMessages;
0075: import org.apache.xerces.utils.ImplementationMessages;
0076:
0077: import org.apache.xerces.parsers.DOMParser;
0078:
0079: import org.w3c.dom.Document;
0080: import org.w3c.dom.Element;
0081:
0082: import org.xml.sax.InputSource;
0083: import org.xml.sax.EntityResolver;
0084: import org.xml.sax.Locator;
0085: import org.xml.sax.helpers.LocatorImpl;
0086: import org.xml.sax.SAXException;
0087: import org.xml.sax.SAXParseException;
0088:
0089: import java.io.IOException;
0090:
0091: import java.util.Enumeration;
0092: import java.util.Hashtable;
0093: import java.util.Stack;
0094: import java.util.StringTokenizer;
0095: import java.util.Vector;
0096:
0097: import org.apache.xerces.validators.dtd.DTDGrammar;
0098:
0099: import org.apache.xerces.validators.schema.GeneralAttrCheck;
0100: import org.apache.xerces.validators.schema.SubstitutionGroupComparator;
0101: import org.apache.xerces.validators.schema.SchemaGrammar;
0102: import org.apache.xerces.validators.schema.SchemaMessageProvider;
0103: import org.apache.xerces.validators.schema.SchemaSymbols;
0104: import org.apache.xerces.validators.schema.TraverseSchema;
0105: import org.apache.xerces.validators.schema.identity.Field;
0106: import org.apache.xerces.validators.schema.identity.FieldActivator;
0107: import org.apache.xerces.validators.schema.identity.IdentityConstraint;
0108: import org.apache.xerces.validators.schema.identity.IDValue;
0109: import org.apache.xerces.validators.schema.identity.Key;
0110: import org.apache.xerces.validators.schema.identity.KeyRef;
0111: import org.apache.xerces.validators.schema.identity.Selector;
0112: import org.apache.xerces.validators.schema.identity.Unique;
0113: import org.apache.xerces.validators.schema.identity.ValueStore;
0114: import org.apache.xerces.validators.schema.identity.XPathMatcher;
0115:
0116: import org.apache.xerces.validators.datatype.DatatypeValidatorFactoryImpl;
0117: import org.apache.xerces.validators.datatype.DatatypeValidator;
0118: import org.apache.xerces.validators.datatype.InvalidDatatypeValueException;
0119: import org.apache.xerces.validators.datatype.StateMessageDatatype;
0120: import org.apache.xerces.validators.datatype.IDREFDatatypeValidator;
0121: import org.apache.xerces.validators.datatype.IDDatatypeValidator;
0122: import org.apache.xerces.validators.datatype.ENTITYDatatypeValidator;
0123: import org.apache.xerces.validators.datatype.NOTATIONDatatypeValidator;
0124: import org.apache.xerces.validators.datatype.UnionDatatypeValidator;
0125: import org.apache.xerces.validators.datatype.AnySimpleType;
0126:
0127: /**
0128: * This class is the super all-in-one validator used by the parser.
0129: *
0130: * @version $Id: XMLValidator.java,v 1.186.2.8 2001/11/07 20:08:48 neilg Exp $
0131: */
0132: public final class XMLValidator implements
0133: DefaultEntityHandler.EventHandler,
0134: XMLEntityHandler.CharDataHandler,
0135: XMLDocumentScanner.EventHandler,
0136: NamespacesScope.NamespacesHandler, FieldActivator // for identity constraints
0137: {
0138:
0139: //
0140: // Constants
0141: //
0142:
0143: // debugging
0144:
0145: private static final boolean PRINT_EXCEPTION_STACK_TRACE = false;
0146: private static final boolean DEBUG_PRINT_ATTRIBUTES = false;
0147: private static final boolean DEBUG_PRINT_CONTENT = false;
0148: private static final boolean DEBUG_SCHEMA_VALIDATION = false;
0149: private static final boolean DEBUG_ELEMENT_CHILDREN = false;
0150:
0151: /** Compile to true to debug identity constraints. */
0152: protected static final boolean DEBUG_IDENTITY_CONSTRAINTS = false;
0153:
0154: /** Compile to true to debug value stores. */
0155: protected static final boolean DEBUG_VALUE_STORES = false;
0156:
0157: // Chunk size constants
0158:
0159: private static final int CHUNK_SHIFT = 8; // 2^8 = 256
0160: private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
0161: private static final int CHUNK_MASK = CHUNK_SIZE - 1;
0162: private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k
0163:
0164: private Hashtable fIdDefs = new Hashtable();
0165: private Hashtable fIdREFDefs = new Hashtable();
0166:
0167: private StateMessageDatatype fValidateIDRef = new StateMessageDatatype() {
0168: private Hashtable fIdDefs;
0169:
0170: public Object getDatatypeObject() {
0171: return (Object) fIdDefs;
0172: }
0173:
0174: public int getDatatypeState() {
0175: return IDREFDatatypeValidator.IDREF_VALIDATE;
0176: }
0177:
0178: public void setDatatypeObject(Object data) {
0179: fIdDefs = (Hashtable) data;
0180: }
0181: };
0182:
0183: private StateMessageDatatype fCheckIDRef = new StateMessageDatatype() {
0184: private Object[] fLists;
0185:
0186: public Object getDatatypeObject() {
0187: return (Object) fLists;
0188: }
0189:
0190: public int getDatatypeState() {
0191: return IDREFDatatypeValidator.IDREF_CHECKID;
0192: }
0193:
0194: public void setDatatypeObject(Object data) {
0195: fLists = (Object[]) data;
0196: }
0197: };
0198:
0199: private StateMessageDatatype fValidateEntity = new StateMessageDatatype() {
0200: private Object fData;
0201:
0202: public Object getDatatypeObject() {
0203: return fData;
0204: }
0205:
0206: public int getDatatypeState() {
0207: return ENTITYDatatypeValidator.ENTITY_VALIDATE;
0208: }
0209:
0210: public void setDatatypeObject(Object data) {
0211: fData = data;
0212: }
0213: };
0214:
0215: //
0216: // Data
0217: //
0218:
0219: // REVISIT: The data should be regrouped and re-organized so that
0220: // it's easier to find a meaningful field.
0221:
0222: // attribute validators
0223:
0224: private AttributeValidator fAttValidatorNOTATION = new AttValidatorNOTATION();
0225: private AttributeValidator fAttValidatorENUMERATION = new AttValidatorENUMERATION();
0226: private AttributeValidator fAttValidatorDATATYPE = null;
0227:
0228: // Package access for use by AttributeValidator classes.
0229:
0230: StringPool fStringPool = null;
0231: boolean fValidating = false;
0232: boolean fInElementContent = false;
0233: int fStandaloneReader = -1;
0234:
0235: // settings
0236:
0237: private boolean fValidationEnabled = false;
0238: private boolean fDynamicValidation = false;
0239: private boolean fSchemaValidation = true;
0240: private boolean fSchemaValidationFullChecking = false;
0241: private boolean fValidationEnabledByDynamic = false;
0242: private boolean fDynamicDisabledByValidation = false;
0243: private boolean fWarningOnDuplicateAttDef = false;
0244: private boolean fWarningOnUndeclaredElements = false;
0245: private boolean fNormalizeAttributeValues = true;
0246: private boolean fLoadDTDGrammar = true;
0247: // expose normalized values for element/attribute content
0248: // default: expose Infoset
0249: private boolean fNormalizeContents = false;
0250:
0251: // REVISIT: normalization
0252: // would not work properly for UNION types since we don't have
0253: // correct whiteSpace facet to normalize values.
0254: //
0255:
0256: // Private temporary variables
0257:
0258: private Hashtable fLocationUriPairs = new Hashtable(10);
0259:
0260: // declarations
0261:
0262: private String fExternalSchemas = null;
0263: private String fExternalNoNamespaceSchema = null;
0264: private DOMParser fSchemaGrammarParser = null;
0265: private int fDeclaration[];
0266: private XMLErrorReporter fErrorReporter = null;
0267: private DefaultEntityHandler fEntityHandler = null;
0268: private QName fCurrentElement = new QName();
0269:
0270: private ContentLeafNameTypeVector[] fContentLeafStack = new ContentLeafNameTypeVector[8];
0271:
0272: //OTWI: on-the-way-in
0273: // store the content model
0274: private XMLContentModel[] fContentModelStack = new XMLContentModel[8];
0275: // >= 0 normal state; -1: error; -2: on-the-way-out
0276: private int[] fContentModelStateStack = new int[8];
0277: // how many child elements have succefully validated
0278: private int[] fContentModelEleCount = new int[8];
0279:
0280: private int[] fValidationFlagStack = new int[8];
0281:
0282: private int[] fScopeStack = new int[8];
0283: private int[] fGrammarNameSpaceIndexStack = new int[8];
0284:
0285: private int[] fElementEntityStack = new int[8];
0286: private int[] fElementIndexStack = new int[8];
0287: private int[] fContentSpecTypeStack = new int[8];
0288:
0289: private static final int sizeQNameParts = 8;
0290: private QName[] fElementQNamePartsStack = new QName[sizeQNameParts];
0291:
0292: private QName[] fElementChildren = new QName[32];
0293: private int fElementChildrenLength = 0;
0294: private int[] fElementChildrenOffsetStack = new int[32];
0295: private int fElementDepth = -1;
0296:
0297: private boolean fNamespacesEnabled = false;
0298: private NamespacesScope fNamespacesScope = null;
0299: private int fNamespacesPrefix = -1;
0300: private QName fRootElement = new QName();
0301: private int fAttrListHandle = -1;
0302: private int fCurrentElementEntity = -1;
0303: private int fCurrentElementIndex = -1;
0304: private int fCurrentContentSpecType = -1;
0305: private boolean fSeenDoctypeDecl = false;
0306:
0307: private final int TOP_LEVEL_SCOPE = -1;
0308: private int fCurrentScope = TOP_LEVEL_SCOPE;
0309: private int fCurrentSchemaURI = StringPool.EMPTY_STRING;
0310: private int fEmptyURI = StringPool.EMPTY_STRING;
0311: private int fXsiPrefix = -1;
0312: private int fXsiURI = -2;
0313: private int fXsiTypeAttValue = -1;
0314: private DatatypeValidator fXsiTypeValidator = null;
0315:
0316: private boolean fNil = false;
0317:
0318: private Grammar fGrammar = null;
0319: private int fGrammarNameSpaceIndex = StringPool.EMPTY_STRING;
0320: private GrammarResolver fGrammarResolver = null;
0321:
0322: // state and stuff
0323:
0324: private boolean fScanningDTD = false;
0325: private XMLDocumentScanner fDocumentScanner = null;
0326: private boolean fCalledStartDocument = false;
0327: private XMLDocumentHandler fDocumentHandler = null;
0328: private XMLDocumentHandler.DTDHandler fDTDHandler = null;
0329: private boolean fSeenRootElement = false;
0330: private XMLAttrList fAttrList = null;
0331: private int fXMLLang = -1;
0332: private LocatorImpl fAttrNameLocator = null;
0333: private boolean fCheckedForSchema = false;
0334: private boolean fDeclsAreExternal = false;
0335: private StringPool.CharArrayRange fCurrentElementCharArrayRange = null;
0336: private char[] fCharRefData = null;
0337: private boolean fSendCharDataAsCharArray = false;
0338: private boolean fBufferDatatype = false;
0339: // holds normalized or unnormalized string element value,
0340: private StringBuffer fDatatypeBuffer = new StringBuffer();
0341:
0342: private QName fTempQName = new QName();
0343: private XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl();
0344: private XMLAttributeDecl fTempAttributeDecl = new XMLAttributeDecl();
0345: private XMLElementDecl fTempElementDecl = new XMLElementDecl();
0346:
0347: private boolean fGrammarIsDTDGrammar = false;
0348: private boolean fGrammarIsSchemaGrammar = false;
0349:
0350: private boolean fNeedValidationOff = false;
0351:
0352: //Schema Normalization
0353: private static final boolean DEBUG_NORMALIZATION = false;
0354: private DatatypeValidator fCurrentDV = null; //current datatype validator
0355: private boolean fFirstChunk = true; // got first chunk in characters() (SAX)
0356: private boolean fTrailing = false; // Previous chunk had a trailing space
0357: private short fWhiteSpace = DatatypeValidator.COLLAPSE; //whiteSpace: preserve/replace/collapse
0358: private StringBuffer fNormalizedStr = new StringBuffer(CHUNK_SIZE); //holds normalized str value
0359: private StringBuffer fUnnormalizedStr = new StringBuffer(CHUNK_SIZE); //holds unnormalized str value
0360:
0361: // symbols
0362:
0363: private int fEMPTYSymbol = -1;
0364: private int fANYSymbol = -1;
0365: private int fMIXEDSymbol = -1;
0366: private int fCHILDRENSymbol = -1;
0367: private int fCDATASymbol = -1;
0368: private int fIDSymbol = -1;
0369: private int fIDREFSymbol = -1;
0370: private int fIDREFSSymbol = -1;
0371: private int fENTITYSymbol = -1;
0372: private int fENTITIESSymbol = -1;
0373: private int fNMTOKENSymbol = -1;
0374: private int fNMTOKENSSymbol = -1;
0375: private int fNOTATIONSymbol = -1;
0376: private int fENUMERATIONSymbol = -1;
0377: private int fREQUIREDSymbol = -1;
0378: private int fFIXEDSymbol = -1;
0379: private int fDATATYPESymbol = -1;
0380: private int fEpsilonIndex = -1;
0381:
0382: //Datatype Registry
0383:
0384: private DatatypeValidatorFactoryImpl fDataTypeReg = null;
0385: private DatatypeValidator fValID = null;
0386: private DatatypeValidator fValIDRef = null;
0387: private DatatypeValidator fValIDRefs = null;
0388: private DatatypeValidator fValENTITY = null;
0389: private DatatypeValidator fValENTITIES = null;
0390: private DatatypeValidator fValNMTOKEN = null;
0391: private DatatypeValidator fValNMTOKENS = null;
0392: private DatatypeValidator fValNOTATION = null;
0393:
0394: // identity constraint information
0395:
0396: /**
0397: * Stack of active XPath matchers for identity constraints. All
0398: * active XPath matchers are notified of startElement, characters
0399: * and endElement callbacks in order to perform their matches.
0400: * <p>
0401: * For each element with identity constraints, the selector of
0402: * each identity constraint is activated. When the selector matches
0403: * its XPath, then all the fields of the identity constraint are
0404: * activated.
0405: * <p>
0406: * <strong>Note:</strong> Once the activation scope is left, the
0407: * XPath matchers are automatically removed from the stack of
0408: * active matchers and no longer receive callbacks.
0409: */
0410: protected XPathMatcherStack fMatcherStack = new XPathMatcherStack();
0411:
0412: /** Cache of value stores for identity constraint fields. */
0413: protected ValueStoreCache fValueStoreCache = new ValueStoreCache();
0414:
0415: // store the substitution group comparator
0416: protected SubstitutionGroupComparator fSGComparator = null;
0417:
0418: // on which grammars we have checked UPA
0419: protected Hashtable UPACheckedGrammarURIs = new Hashtable();
0420: protected static Object fgNullObject = new Object();
0421:
0422: //
0423: // Constructors
0424: //
0425:
0426: /** Constructs an XML validator. */
0427: public XMLValidator(StringPool stringPool,
0428: XMLErrorReporter errorReporter,
0429: DefaultEntityHandler entityHandler,
0430: XMLDocumentScanner documentScanner) {
0431:
0432: // keep references
0433: fStringPool = stringPool;
0434: fErrorReporter = errorReporter;
0435: fEntityHandler = entityHandler;
0436: fDocumentScanner = documentScanner;
0437:
0438: fValidateEntity.setDatatypeObject(new Object[] { entityHandler,
0439: stringPool });
0440: fValidateIDRef.setDatatypeObject(fIdREFDefs);
0441: fCheckIDRef.setDatatypeObject(new Object[] { fIdDefs,
0442: fIdREFDefs });
0443:
0444: fEmptyURI = fStringPool.addSymbol("");
0445: fXsiURI = fStringPool.addSymbol(SchemaSymbols.URI_XSI);
0446: // initialize
0447: fAttrList = new XMLAttrList(fStringPool);
0448: entityHandler.setEventHandler(this );
0449: entityHandler.setCharDataHandler(this );
0450: fDocumentScanner.setEventHandler(this );
0451:
0452: for (int i = 0; i < sizeQNameParts; i++) {
0453: fElementQNamePartsStack[i] = new QName();
0454: }
0455: init();
0456:
0457: } // <init>(StringPool,XMLErrorReporter,DefaultEntityHandler,XMLDocumentScanner)
0458:
0459: public void setGrammarResolver(GrammarResolver grammarResolver) {
0460: fGrammarResolver = grammarResolver;
0461: }
0462:
0463: //
0464: // Public methods
0465: //
0466:
0467: // initialization
0468:
0469: /** Set char data processing preference and handlers. */
0470: public void initHandlers(boolean sendCharDataAsCharArray,
0471: XMLDocumentHandler docHandler,
0472: XMLDocumentHandler.DTDHandler dtdHandler) {
0473:
0474: fSendCharDataAsCharArray = sendCharDataAsCharArray;
0475: fEntityHandler
0476: .setSendCharDataAsCharArray(fSendCharDataAsCharArray);
0477: fDocumentHandler = docHandler;
0478: fDTDHandler = dtdHandler;
0479:
0480: } // initHandlers(boolean,XMLDocumentHandler,XMLDocumentHandler.DTDHandler)
0481:
0482: /** Reset or copy. */
0483: public void resetOrCopy(StringPool stringPool) throws Exception {
0484: fAttrList = new XMLAttrList(stringPool);
0485: resetCommon(stringPool);
0486: }
0487:
0488: /** Reset. */
0489: public void reset(StringPool stringPool) throws Exception {
0490: fAttrList.reset(stringPool);
0491: resetCommon(stringPool);
0492: }
0493:
0494: // settings
0495:
0496: /**
0497: * Turning on validation/dynamic turns on validation if it is off, and
0498: * this is remembered. Turning off validation DISABLES validation/dynamic
0499: * if it is on. Turning off validation/dynamic DOES NOT turn off
0500: * validation if it was explicitly turned on, only if it was turned on
0501: * BECAUSE OF the call to turn validation/dynamic on. Turning on
0502: * validation will REENABLE and turn validation/dynamic back on if it
0503: * was disabled by a call that turned off validation while
0504: * validation/dynamic was enabled.
0505: */
0506: public void setValidationEnabled(boolean flag) throws Exception {
0507: fValidationEnabled = flag;
0508: fValidationEnabledByDynamic = false;
0509: if (fValidationEnabled) {
0510: if (fDynamicDisabledByValidation) {
0511: fDynamicValidation = true;
0512: fDynamicDisabledByValidation = false;
0513: }
0514: } else if (fDynamicValidation) {
0515: fDynamicValidation = false;
0516: fDynamicDisabledByValidation = true;
0517: }
0518: fValidating = fValidationEnabled;
0519: if (fValidating) {
0520: initDataTypeValidators();
0521: }
0522: }
0523:
0524: /** Returns true if validation is enabled. */
0525: public boolean getValidationEnabled() {
0526: return fValidationEnabled;
0527: }
0528:
0529: /** Sets whether Schema support is on/off. */
0530: public void setSchemaValidationEnabled(boolean flag) {
0531: fSchemaValidation = flag;
0532: }
0533:
0534: /** Returns true if Schema support is on. */
0535: public boolean getSchemaValidationEnabled() {
0536: return fSchemaValidation;
0537: }
0538:
0539: /** Sets whether full Schema error checking is on/off */
0540: public void setSchemaFullCheckingEnabled(boolean flag) {
0541: fSchemaValidationFullChecking = flag;
0542: }
0543:
0544: //Properties on the parser to allow the user to specify
0545: //XML schemas externaly
0546: //
0547: public void setExternalSchemas(Object value) {
0548: fExternalSchemas = (String) value;
0549: }
0550:
0551: public void setExternalNoNamespaceSchema(Object value) {
0552: fExternalNoNamespaceSchema = (String) value;
0553: }
0554:
0555: public String getExternalSchemas() {
0556: return fExternalSchemas;
0557: }
0558:
0559: public String getExternalNoNamespaceSchema() {
0560: return fExternalNoNamespaceSchema;
0561: }
0562:
0563: /** Returns true if full Schema checking is on. */
0564: public boolean getSchemaFullCheckingEnabled() {
0565: return fSchemaValidationFullChecking;
0566: }
0567:
0568: /** Sets whether validation is dynamic. */
0569: public void setDynamicValidationEnabled(boolean flag)
0570: throws Exception {
0571: fDynamicValidation = flag;
0572: fDynamicDisabledByValidation = false;
0573: if (!fDynamicValidation) {
0574: if (fValidationEnabledByDynamic) {
0575: fValidationEnabled = false;
0576: fValidationEnabledByDynamic = false;
0577: }
0578: } else if (!fValidationEnabled) {
0579: fValidationEnabled = true;
0580: fValidationEnabledByDynamic = true;
0581: }
0582: fValidating = fValidationEnabled;
0583: if (fValidating) {
0584: initDataTypeValidators();
0585: }
0586: }
0587:
0588: /** Returns true if validation is dynamic. */
0589: public boolean getDynamicValidationEnabled() {
0590: return fDynamicValidation;
0591: }
0592:
0593: /** Sets fNormalizeAttributeValues **/
0594: public void setNormalizeAttributeValues(boolean normalize) {
0595: fNormalizeAttributeValues = normalize;
0596: }
0597:
0598: /** Sets fLoadDTDGrammar when validation is off **/
0599: public void setLoadDTDGrammar(boolean loadDG) {
0600: if (fValidating) {
0601: fLoadDTDGrammar = true;
0602: } else {
0603: fLoadDTDGrammar = loadDG;
0604: }
0605: }
0606:
0607: /** Returns fLoadDTDGrammar **/
0608: public boolean getLoadDTDGrammar() {
0609: return fLoadDTDGrammar;
0610: }
0611:
0612: /** Sets whether namespaces are enabled. */
0613: public void setNamespacesEnabled(boolean flag) {
0614: fNamespacesEnabled = flag;
0615: }
0616:
0617: /** Returns true if namespaces are enabled. */
0618: public boolean getNamespacesEnabled() {
0619: return fNamespacesEnabled;
0620: }
0621:
0622: /** Sets whether duplicate attribute definitions signal a warning. */
0623: public void setWarningOnDuplicateAttDef(boolean flag) {
0624: fWarningOnDuplicateAttDef = flag;
0625: }
0626:
0627: /** Returns true if duplicate attribute definitions signal a warning. */
0628: public boolean getWarningOnDuplicateAttDef() {
0629: return fWarningOnDuplicateAttDef;
0630: }
0631:
0632: /** Sets whether undeclared elements signal a warning. */
0633: public void setWarningOnUndeclaredElements(boolean flag) {
0634: fWarningOnUndeclaredElements = flag;
0635: }
0636:
0637: /** Returns true if undeclared elements signal a warning. */
0638: public boolean getWarningOnUndeclaredElements() {
0639: return fWarningOnUndeclaredElements;
0640: }
0641:
0642: /** Sets fNormalizeContents **/
0643: public void setNormalizeContents(boolean normalize) {
0644: fNormalizeContents = normalize;
0645: }
0646:
0647: public boolean getNormalizeConents() {
0648: return fNormalizeContents;
0649: }
0650:
0651: //
0652: // FieldActivator methods
0653: //
0654:
0655: /**
0656: * Start the value scope for the specified identity constraint. This
0657: * method is called when the selector matches in order to initialize
0658: * the value store.
0659: *
0660: * @param identityConstraint The identity constraint.
0661: */
0662: public void startValueScopeFor(IdentityConstraint identityConstraint)
0663: throws Exception {
0664:
0665: for (int i = 0; i < identityConstraint.getFieldCount(); i++) {
0666: Field field = identityConstraint.getFieldAt(i);
0667: ValueStoreBase valueStore = fValueStoreCache
0668: .getValueStoreFor(field);
0669: valueStore.startValueScope();
0670: }
0671:
0672: } // startValueScopeFor(IdentityConstraint identityConstraint)
0673:
0674: /**
0675: * Request to activate the specified field. This method returns the
0676: * matcher for the field.
0677: *
0678: * @param field The field to activate.
0679: */
0680: public XPathMatcher activateField(Field field) throws Exception {
0681: if (DEBUG_IDENTITY_CONSTRAINTS) {
0682: System.out
0683: .println("<IC>: activateField(\"" + field + "\")");
0684: }
0685: ValueStore valueStore = fValueStoreCache
0686: .getValueStoreFor(field);
0687: field.setMayMatch(true);
0688: XPathMatcher matcher = field.createMatcher(valueStore);
0689: fMatcherStack.addMatcher(matcher);
0690: matcher.startDocumentFragment(fStringPool);
0691: return matcher;
0692: } // activateField(Field):XPathMatcher
0693:
0694: /**
0695: * Ends the value scope for the specified identity constraint.
0696: *
0697: * @param identityConstraint The identity constraint.
0698: */
0699: public void endValueScopeFor(IdentityConstraint identityConstraint)
0700: throws Exception {
0701:
0702: ValueStoreBase valueStore = fValueStoreCache
0703: .getValueStoreFor(identityConstraint);
0704: valueStore.endValueScope();
0705:
0706: } // endValueScopeFor(IdentityConstraint)
0707:
0708: //
0709: // DefaultEntityHandler.EventHandler methods
0710: //
0711:
0712: /** Start entity reference. */
0713: public void startEntityReference(int entityName, int entityType,
0714: int entityContext) throws Exception {
0715: fDocumentHandler.startEntityReference(entityName, entityType,
0716: entityContext);
0717: }
0718:
0719: /** End entity reference. */
0720: public void endEntityReference(int entityName, int entityType,
0721: int entityContext) throws Exception {
0722: fDocumentHandler.endEntityReference(entityName, entityType,
0723: entityContext);
0724: }
0725:
0726: /** Send end of input notification. */
0727: public void sendEndOfInputNotifications(int entityName,
0728: boolean moreToFollow) throws Exception {
0729: fDocumentScanner.endOfInput(entityName, moreToFollow);
0730: /***
0731: if (fScanningDTD) {
0732: fDTDImporter.sendEndOfInputNotifications(entityName, moreToFollow);
0733: }
0734: /***/
0735: }
0736:
0737: /** Send reader change notifications. */
0738: public void sendReaderChangeNotifications(
0739: XMLEntityHandler.EntityReader reader, int readerId)
0740: throws Exception {
0741: fDocumentScanner.readerChange(reader, readerId);
0742: /***
0743: if (fScanningDTD) {
0744: fDTDImporter.sendReaderChangeNotifications(reader, readerId);
0745: }
0746: /***/
0747: }
0748:
0749: /** External entity standalone check. */
0750: public boolean externalEntityStandaloneCheck() {
0751: return (fStandaloneReader != -1 && fValidating);
0752: }
0753:
0754: /** Return true if validating. */
0755: public boolean getValidating() {
0756: return fValidating;
0757: }
0758:
0759: //
0760: // XMLEntityHandler.CharDataHandler methods
0761: //
0762:
0763: private String normalizeValue(String unNormalizedValue) {
0764: fUnnormalizedStr.setLength(0);
0765: fUnnormalizedStr.append(unNormalizedValue);
0766: normalizeWhitespace(fUnnormalizedStr,
0767: (fWhiteSpace == DatatypeValidator.COLLAPSE));
0768: return fNormalizedStr.toString();
0769: }
0770:
0771: /**
0772: * Normalize whitespace in an XMLString according to the rules of attribute
0773: * value normalization - converting all whitespace characters to space
0774: * characters.
0775: * In addition for attributes of type other than CDATA: trim leading and
0776: * trailing spaces and collapse spaces (0x20 only).
0777: *
0778: * @param value The string to normalize.
0779: * @returns 0 if no triming is done or if there is neither leading nor
0780: * trailing whitespace,
0781: * 1 if there is only leading whitespace,
0782: * 2 if there is only trailing whitespace,
0783: * 3 if there is both leading and trailing whitespace.
0784: */
0785:
0786: private int normalizeWhitespace(StringBuffer chars, boolean collapse) {
0787: int length = fUnnormalizedStr.length();
0788: fNormalizedStr.setLength(0);
0789: boolean skipSpace = collapse;
0790: boolean sawNonWS = false;
0791: int leading = 0;
0792: int trailing = 0;
0793: int c;
0794: for (int i = 0; i < length; i++) {
0795: c = chars.charAt(i);
0796: if (c == 0x20 || c == 0x0D || c == 0x0A || c == 0x09) {
0797: if (!skipSpace) {
0798: // take the first whitespace as a space and skip the others
0799: fNormalizedStr.append(' ');
0800: skipSpace = collapse;
0801: }
0802: if (!sawNonWS) {
0803: // this is a leading whitespace, record it
0804: leading = 1;
0805: }
0806: } else {
0807: fNormalizedStr.append((char) c);
0808: skipSpace = false;
0809: sawNonWS = true;
0810: }
0811: }
0812: if (skipSpace) {
0813: c = fNormalizedStr.length();
0814: if (c != 0) {
0815: // if we finished on a space trim it but also record it
0816: fNormalizedStr.setLength(--c);
0817: trailing = 2;
0818: } else if (leading != 0 && !sawNonWS) {
0819: // if all we had was whitespace we skipped record it as
0820: // trailing whitespace as well
0821: trailing = 2;
0822: }
0823: }
0824: //value.setValues(fNormalizedStr);
0825: return collapse ? leading + trailing : 0;
0826: }
0827:
0828: /** Process characters. Schema Normalization*/
0829: public void processCharacters(char[] chars, int offset, int length)
0830: throws Exception {
0831: if (DEBUG_NORMALIZATION) {
0832: System.out
0833: .println("==>processCharacters(char[] chars, int offset, int length");
0834: }
0835: if (fValidating) {
0836: if (fInElementContent
0837: || fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
0838: if (DEBUG_NORMALIZATION) {
0839: System.out.println("==>charDataInContent()");
0840: }
0841: charDataInContent();
0842: }
0843: if (fBufferDatatype) {
0844: if (fFirstChunk && fGrammar != null) {
0845: fGrammar.getElementDecl(fCurrentElementIndex,
0846: fTempElementDecl);
0847: fCurrentDV = fTempElementDecl.datatypeValidator;
0848: if (fXsiTypeValidator != null) {
0849: fCurrentDV = fXsiTypeValidator;
0850: fXsiTypeValidator = null;
0851: }
0852: if (fCurrentDV != null) {
0853: fWhiteSpace = fCurrentDV.getWSFacet();
0854: }
0855: }
0856: if (DEBUG_NORMALIZATION) {
0857: System.out
0858: .println("Start schema datatype normalization <whiteSpace value="
0859: + fWhiteSpace + ">");
0860: }
0861: if (!fNormalizeContents
0862: || fWhiteSpace == DatatypeValidator.PRESERVE) { //do not normalize
0863: fDatatypeBuffer.append(chars, offset, length);
0864: } else {
0865: fUnnormalizedStr.setLength(0);
0866: fUnnormalizedStr.append(chars, offset, length);
0867: int spaces = normalizeWhitespace(fUnnormalizedStr,
0868: (fWhiteSpace == DatatypeValidator.COLLAPSE));
0869: int nLength = fNormalizedStr.length();
0870: if (nLength > 0) {
0871: if (!fFirstChunk
0872: && (fWhiteSpace == DatatypeValidator.COLLAPSE)
0873: && fTrailing) {
0874: fNormalizedStr.insert(0, ' ');
0875: nLength++;
0876: }
0877: if ((length - offset) != nLength) {
0878: char[] newChars = new char[nLength];
0879: fNormalizedStr.getChars(0, nLength,
0880: newChars, 0);
0881: chars = newChars;
0882: offset = 0;
0883: length = nLength;
0884: } else {
0885: fNormalizedStr.getChars(0, nLength, chars,
0886: 0);
0887: }
0888: fDatatypeBuffer.append(chars, offset, length);
0889:
0890: // call all active identity constraints
0891: int count = fMatcherStack.getMatcherCount();
0892: for (int i = 0; i < count; i++) {
0893: XPathMatcher matcher = fMatcherStack
0894: .getMatcherAt(i);
0895: if (DEBUG_IDENTITY_CONSTRAINTS) {
0896: String text = new String(chars, offset,
0897: length);
0898: System.out.println("<IC>: "
0899: + matcher.toString()
0900: + "#characters(" + text + ")");
0901: }
0902: matcher.characters(chars, offset, length);
0903: }
0904:
0905: fDocumentHandler.characters(chars, offset,
0906: length);
0907: }
0908: fTrailing = (spaces > 1) ? true : false;
0909: fFirstChunk = false;
0910: return;
0911: }
0912: }
0913: }
0914:
0915: fFirstChunk = false;
0916:
0917: // call all active identity constraints
0918: int count = fMatcherStack.getMatcherCount();
0919: for (int i = 0; i < count; i++) {
0920: XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
0921: if (DEBUG_IDENTITY_CONSTRAINTS) {
0922: String text = new String(chars, offset, length);
0923: System.out.println("<IC>: " + matcher.toString()
0924: + "#characters(" + text + ")");
0925: }
0926: matcher.characters(chars, offset, length);
0927: }
0928:
0929: fDocumentHandler.characters(chars, offset, length);
0930: }
0931:
0932: /** Process characters. */
0933: public void processCharacters(int data) throws Exception {
0934: if (fValidating) {
0935: if (fInElementContent
0936: || fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
0937: charDataInContent();
0938: }
0939: if (fBufferDatatype) {
0940: fGrammar.getElementDecl(fCurrentElementIndex,
0941: fTempElementDecl);
0942: //REVISIT: add normalization according to datatypes
0943: fCurrentDV = fTempElementDecl.datatypeValidator;
0944: if (fXsiTypeValidator != null) {
0945: fCurrentDV = fXsiTypeValidator;
0946: fXsiTypeValidator = null;
0947: }
0948: if (fCurrentDV != null) {
0949: fWhiteSpace = fCurrentDV.getWSFacet();
0950: }
0951: if (!fNormalizeContents
0952: || fWhiteSpace == DatatypeValidator.PRESERVE) { //no normalization done
0953: fDatatypeBuffer.append(fStringPool.toString(data));
0954: } else {
0955: String str = fStringPool.toString(data);
0956: int length = str.length();
0957: fUnnormalizedStr.setLength(0);
0958: fUnnormalizedStr.append(str);
0959: int spaces = normalizeWhitespace(fUnnormalizedStr,
0960: (fWhiteSpace == DatatypeValidator.COLLAPSE));
0961: if (fWhiteSpace != DatatypeValidator.PRESERVE) {
0962: //normalization was done.
0963: fStringPool.releaseString(data);
0964: data = fStringPool.addString(fNormalizedStr
0965: .toString());
0966: }
0967: fDatatypeBuffer.append(fNormalizedStr.toString());
0968: }
0969: }
0970: }
0971:
0972: // call all active identity constraints
0973: int count = fMatcherStack.getMatcherCount();
0974: if (count > 0) {
0975: String text = fStringPool.toString(data);
0976: char[] chars = new char[text.length()];
0977: int offset = 0;
0978: int length = chars.length;
0979: text.getChars(offset, length, chars, offset);
0980: for (int i = 0; i < count; i++) {
0981: XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
0982: if (DEBUG_IDENTITY_CONSTRAINTS) {
0983: System.out.println("<IC>: " + matcher.toString()
0984: + "#characters(" + text + ")");
0985: }
0986: matcher.characters(chars, offset, length);
0987: }
0988: }
0989:
0990: fDocumentHandler.characters(data);
0991: }
0992:
0993: /** Process whitespace. */
0994: public void processWhitespace(char[] chars, int offset, int length)
0995: throws Exception {
0996:
0997: if (fInElementContent) {
0998: if (fStandaloneReader != -1 && fValidating
0999: && getElementDeclIsExternal(fCurrentElementIndex)) {
1000: reportRecoverableXMLError(
1001: XMLMessages.MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE,
1002: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION);
1003: }
1004: fDocumentHandler.ignorableWhitespace(chars, offset, length);
1005: } else {
1006: if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
1007: charDataInContent();
1008: }
1009:
1010: // call all active identity constraints
1011: int count = fMatcherStack.getMatcherCount();
1012: for (int i = 0; i < count; i++) {
1013: XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
1014: if (DEBUG_IDENTITY_CONSTRAINTS) {
1015: String text = new String(chars, offset, length);
1016: System.out.println("<IC>: " + matcher.toString()
1017: + "#characters(" + text + ")");
1018: }
1019: matcher.characters(chars, offset, length);
1020: }
1021: if (fGrammar != null && fValidating) {
1022:
1023: fGrammar.getElementDecl(fCurrentElementIndex,
1024: fTempElementDecl);
1025: fCurrentDV = fTempElementDecl.datatypeValidator;
1026: if (fXsiTypeValidator != null) {
1027: fCurrentDV = fXsiTypeValidator;
1028: fXsiTypeValidator = null;
1029: }
1030: if (fCurrentDV != null) {
1031: fWhiteSpace = fCurrentDV.getWSFacet();
1032: }
1033:
1034: if (fWhiteSpace == DatatypeValidator.PRESERVE) { //do not normalize
1035: fDatatypeBuffer.append(chars, offset, length);
1036: }
1037:
1038: }
1039:
1040: fDocumentHandler.characters(chars, offset, length);
1041: }
1042:
1043: } // processWhitespace(char[],int,int)
1044:
1045: /** Process whitespace. */
1046: public void processWhitespace(int data) throws Exception {
1047:
1048: if (fInElementContent) {
1049: if (fStandaloneReader != -1 && fValidating
1050: && getElementDeclIsExternal(fCurrentElementIndex)) {
1051: reportRecoverableXMLError(
1052: XMLMessages.MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE,
1053: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION);
1054: }
1055: fDocumentHandler.ignorableWhitespace(data);
1056: } else {
1057: if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
1058: charDataInContent();
1059: }
1060:
1061: // call all active identity constraints
1062: int count = fMatcherStack.getMatcherCount();
1063: if (count > 0) {
1064: String text = fStringPool.toString(data);
1065: char[] chars = new char[text.length()];
1066: int offset = 0;
1067: int length = chars.length;
1068: text.getChars(length, length, chars, offset);
1069: for (int i = 0; i < count; i++) {
1070: XPathMatcher matcher = fMatcherStack
1071: .getMatcherAt(i);
1072: if (DEBUG_IDENTITY_CONSTRAINTS) {
1073: System.out.println("<IC>: "
1074: + matcher.toString() + "#characters("
1075: + text + ")");
1076: }
1077: matcher.characters(chars, offset, length);
1078: }
1079: }
1080:
1081: if (fGrammar != null && fValidating) {
1082: fGrammar.getElementDecl(fCurrentElementIndex,
1083: fTempElementDecl);
1084: fCurrentDV = fTempElementDecl.datatypeValidator;
1085: if (fXsiTypeValidator != null) {
1086: fCurrentDV = fXsiTypeValidator;
1087: fXsiTypeValidator = null;
1088: }
1089: if (fCurrentDV != null) {
1090: fWhiteSpace = fCurrentDV.getWSFacet();
1091: }
1092: if (fWhiteSpace == DatatypeValidator.PRESERVE) { //no normalization done
1093: fDatatypeBuffer.append(fStringPool.toString(data));
1094: }
1095:
1096: }
1097: fDocumentHandler.characters(data);
1098: }
1099:
1100: } // processWhitespace(int)
1101:
1102: //
1103: // XMLDocumentScanner.EventHandler methods
1104: //
1105:
1106: /** Scans element type. */
1107: public void scanElementType(
1108: XMLEntityHandler.EntityReader entityReader, char fastchar,
1109: QName element) throws Exception {
1110:
1111: if (!fNamespacesEnabled) {
1112: element.clear();
1113: element.localpart = entityReader.scanName(fastchar);
1114: element.rawname = element.localpart;
1115: } else {
1116: entityReader.scanQName(fastchar, element);
1117: if (entityReader.lookingAtChar(':', false)) {
1118: fErrorReporter.reportError(fErrorReporter.getLocator(),
1119: XMLMessages.XML_DOMAIN,
1120: XMLMessages.MSG_TWO_COLONS_IN_QNAME,
1121: XMLMessages.P5_INVALID_CHARACTER, null,
1122: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
1123: entityReader.skipPastNmtoken(' ');
1124: }
1125: }
1126:
1127: } // scanElementType(XMLEntityHandler.EntityReader,char,QName)
1128:
1129: /** Scans expected element type. */
1130: public boolean scanExpectedElementType(
1131: XMLEntityHandler.EntityReader entityReader, char fastchar,
1132: QName element) throws Exception {
1133:
1134: if (fCurrentElementCharArrayRange == null) {
1135: fCurrentElementCharArrayRange = fStringPool
1136: .createCharArrayRange();
1137: }
1138: fStringPool.getCharArrayRange(fCurrentElement.rawname,
1139: fCurrentElementCharArrayRange);
1140: return entityReader.scanExpectedName(fastchar,
1141: fCurrentElementCharArrayRange);
1142:
1143: } // scanExpectedElementType(XMLEntityHandler.EntityReader,char,QName)
1144:
1145: /** Scans attribute name. */
1146: public void scanAttributeName(
1147: XMLEntityHandler.EntityReader entityReader, QName element,
1148: QName attribute) throws Exception {
1149:
1150: if (!fSeenRootElement) {
1151: fSeenRootElement = true;
1152: rootElementSpecified(element);
1153: fStringPool.resetShuffleCount();
1154: }
1155:
1156: if (!fNamespacesEnabled) {
1157: attribute.clear();
1158: attribute.localpart = entityReader.scanName('=');
1159: attribute.rawname = attribute.localpart;
1160: } else {
1161: entityReader.scanQName('=', attribute);
1162: if (entityReader.lookingAtChar(':', false)) {
1163: fErrorReporter.reportError(fErrorReporter.getLocator(),
1164: XMLMessages.XML_DOMAIN,
1165: XMLMessages.MSG_TWO_COLONS_IN_QNAME,
1166: XMLMessages.P5_INVALID_CHARACTER, null,
1167: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
1168: entityReader.skipPastNmtoken(' ');
1169: }
1170: }
1171:
1172: } // scanAttributeName(XMLEntityHandler.EntityReader,QName,QName)
1173:
1174: /** Call start document. */
1175: public void callStartDocument() throws Exception {
1176:
1177: if (!fCalledStartDocument) {
1178: fDocumentHandler.startDocument();
1179: fCalledStartDocument = true;
1180: if (fValidating) {
1181: fValueStoreCache.startDocument();
1182: }
1183: }
1184: }
1185:
1186: /** Call end document. */
1187: public void callEndDocument() throws Exception {
1188:
1189: if (fCalledStartDocument) {
1190: if (fValidating) {
1191: if (DEBUG_IDENTITY_CONSTRAINTS) {
1192: System.out
1193: .println("<IC>: ValueStoreCache#endDocument()");
1194: }
1195: fValueStoreCache.endDocument();
1196: }
1197: fDocumentHandler.endDocument();
1198: }
1199: }
1200:
1201: /** Call XML declaration. */
1202: public void callXMLDecl(int version, int encoding, int standalone)
1203: throws Exception {
1204: fDocumentHandler.xmlDecl(version, encoding, standalone);
1205: }
1206:
1207: public void callStandaloneIsYes() throws Exception {
1208: // standalone = "yes". said XMLDocumentScanner.
1209: fStandaloneReader = fEntityHandler.getReaderId();
1210:
1211: }
1212:
1213: /** Call text declaration. */
1214: public void callTextDecl(int version, int encoding)
1215: throws Exception {
1216: fDocumentHandler.textDecl(version, encoding);
1217: }
1218:
1219: /**
1220: * Signal the scanning of an element name in a start element tag.
1221: *
1222: * @param element Element name scanned.
1223: */
1224: public void element(QName element) throws Exception {
1225: fAttrListHandle = -1;
1226: }
1227:
1228: /**
1229: * Signal the scanning of an attribute associated to the previous
1230: * start element tag.
1231: *
1232: * @param element Element name scanned.
1233: * @param attrName Attribute name scanned.
1234: * @param attrValue The string pool index of the attribute value.
1235: */
1236: public boolean attribute(QName element, QName attrName,
1237: int attrValue) throws Exception {
1238: if (fAttrListHandle == -1) {
1239: fAttrListHandle = fAttrList.startAttrList();
1240: }
1241:
1242: // if fAttrList.addAttr returns -1, indicates duplicate att in start tag of an element.
1243: // specified: true, search : true
1244: return fAttrList.addAttr(attrName, attrValue, fCDATASymbol,
1245: true, true) == -1;
1246: }
1247:
1248: /** Call start element. */
1249: public void callStartElement(QName element) throws Exception {
1250:
1251: if (DEBUG_SCHEMA_VALIDATION)
1252: System.out.println("\n=======StartElement : "
1253: + fStringPool.toString(element.localpart));
1254:
1255: //
1256: // Check after all specified attrs are scanned
1257: // (1) report error for REQUIRED attrs that are missing (V_TAGc)
1258: // (2) report error for PROHIBITED attrs that are present (V_TAGc)
1259: // (3) add default attrs (FIXED and NOT_FIXED)
1260: //
1261:
1262: if (!fSeenRootElement) {
1263: rootElementSpecified(element);
1264: fStringPool.resetShuffleCount();
1265: }
1266:
1267: if (fGrammar != null && fGrammarIsDTDGrammar) {
1268: fAttrListHandle = addDTDDefaultAttributes(element,
1269: fAttrList, fAttrListHandle, fValidating,
1270: fStandaloneReader != -1);
1271: }
1272:
1273: fCheckedForSchema = true;
1274: if (fNamespacesEnabled) {
1275: bindNamespacesToElementAndAttributes(element, fAttrList);
1276: }
1277:
1278: if (fDynamicValidation && fGrammar == null) {
1279: fValidating = false;
1280: }
1281:
1282: if (!fSeenRootElement) {
1283: fSeenRootElement = true;
1284: }
1285:
1286: validateElementAndAttributes(element, fAttrList);
1287: if (fAttrListHandle != -1) {
1288: //fAttrList.endAttrList();
1289: int dupAttrs[];
1290: if ((dupAttrs = fAttrList.endAttrList()) != null) {
1291: Object[] args = {
1292: fStringPool.toString(element.rawname), null };
1293: for (int i = 0; i < dupAttrs.length; i++) {
1294: args[1] = fStringPool.toString(dupAttrs[i]);
1295: fErrorReporter
1296: .reportError(
1297: fErrorReporter.getLocator(),
1298: XMLMessages.XMLNS_DOMAIN,
1299: XMLMessages.MSG_ATTRIBUTE_NOT_UNIQUE,
1300: XMLMessages.WFC_UNIQUE_ATT_SPEC,
1301: args,
1302: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1303: }
1304: }
1305: }
1306:
1307: // activate identity constraints
1308: if (fValidating && fGrammar != null && fGrammarIsSchemaGrammar) {
1309: if (DEBUG_IDENTITY_CONSTRAINTS) {
1310: System.out.println("<IC>: pushing context - element: "
1311: + fStringPool.toString(element.rawname));
1312: }
1313: fValueStoreCache.startElement();
1314: fMatcherStack.pushContext();
1315: int eindex = fGrammar.getElementDeclIndex(element, -1);
1316: if (eindex != -1) {
1317: fGrammar.getElementDecl(eindex, fTempElementDecl);
1318: fValueStoreCache.initValueStoresFor(fTempElementDecl);
1319: int uCount = fTempElementDecl.unique.size();
1320: for (int i = 0; i < uCount; i++) {
1321: activateSelectorFor((IdentityConstraint) fTempElementDecl.unique
1322: .elementAt(i));
1323: }
1324: int kCount = fTempElementDecl.key.size();
1325: for (int i = 0; i < kCount; i++) {
1326: activateSelectorFor((IdentityConstraint) fTempElementDecl.key
1327: .elementAt(i));
1328: }
1329: int krCount = fTempElementDecl.keyRef.size();
1330: for (int i = 0; i < krCount; i++) {
1331: activateSelectorFor((IdentityConstraint) fTempElementDecl.keyRef
1332: .elementAt(i));
1333: }
1334: }
1335:
1336: // call all active identity constraints
1337: int count = fMatcherStack.getMatcherCount();
1338: for (int i = 0; i < count; i++) {
1339: XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
1340: if (DEBUG_IDENTITY_CONSTRAINTS) {
1341: System.out.println("<IC>: " + matcher.toString()
1342: + "#startElement("
1343: + fStringPool.toString(element.rawname)
1344: + ")");
1345: }
1346: matcher.startElement(element, fAttrList,
1347: fAttrListHandle, fCurrentElementIndex,
1348: (SchemaGrammar) fGrammar);
1349: }
1350: }
1351:
1352: // call handler
1353: fDocumentHandler.startElement(element, fAttrList,
1354: fAttrListHandle);
1355: fElementDepth++;
1356: fAttrListHandle = -1;
1357:
1358: //if (fElementDepth >= 0) {
1359: // REVISIT: Why are doing anything if the grammar is null? -Ac
1360: if (fValidating) {
1361: // push current length onto stack
1362: if (fElementChildrenOffsetStack.length <= fElementDepth) {
1363: int newarray[] = new int[fElementChildrenOffsetStack.length * 2];
1364: System
1365: .arraycopy(fElementChildrenOffsetStack, 0,
1366: newarray, 0,
1367: fElementChildrenOffsetStack.length);
1368: fElementChildrenOffsetStack = newarray;
1369: }
1370: fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength;
1371:
1372: // add this element to children
1373: if (fElementChildren.length <= fElementChildrenLength) {
1374: QName[] newarray = new QName[fElementChildrenLength * 2];
1375: System.arraycopy(fElementChildren, 0, newarray, 0,
1376: fElementChildren.length);
1377: fElementChildren = newarray;
1378: }
1379: QName qname = fElementChildren[fElementChildrenLength];
1380: if (qname == null) {
1381: for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
1382: fElementChildren[i] = new QName();
1383: }
1384: qname = fElementChildren[fElementChildrenLength];
1385: }
1386: qname.setValues(element);
1387: fElementChildrenLength++;
1388:
1389: if (DEBUG_ELEMENT_CHILDREN) {
1390: printChildren();
1391: printStack();
1392: }
1393:
1394: }
1395:
1396: ensureStackCapacity(fElementDepth);
1397: fCurrentElement.setValues(element);
1398: fCurrentElementEntity = fEntityHandler.getReaderId();
1399:
1400: fElementQNamePartsStack[fElementDepth]
1401: .setValues(fCurrentElement);
1402:
1403: fElementEntityStack[fElementDepth] = fCurrentElementEntity;
1404: fElementIndexStack[fElementDepth] = fCurrentElementIndex;
1405: fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType;
1406:
1407: if (fNeedValidationOff) {
1408: fValidating = false;
1409: fNeedValidationOff = false;
1410: }
1411:
1412: if (fValidating && fGrammarIsSchemaGrammar) {
1413: pushContentLeafStack();
1414: } else {
1415: fContentModelStateStack[fElementDepth] = -2;
1416: }
1417:
1418: fValidationFlagStack[fElementDepth] = fValidating ? 0 : -1;
1419:
1420: fScopeStack[fElementDepth] = fCurrentScope;
1421: fGrammarNameSpaceIndexStack[fElementDepth] = fGrammarNameSpaceIndex;
1422:
1423: } // callStartElement(QName)
1424:
1425: private void activateSelectorFor(IdentityConstraint ic)
1426: throws Exception {
1427: Selector selector = ic.getSelector();
1428: if (DEBUG_IDENTITY_CONSTRAINTS) {
1429: System.out
1430: .println("<IC>: XMLValidator#activateSelectorFor("
1431: + selector + ')');
1432: }
1433: FieldActivator activator = this ;
1434: if (selector == null)
1435: return;
1436: XPathMatcher matcher = selector.createMatcher(activator);
1437: fMatcherStack.addMatcher(matcher);
1438: if (DEBUG_IDENTITY_CONSTRAINTS) {
1439: System.out.println("<IC>: " + matcher
1440: + "#startDocumentFragment()");
1441: }
1442: matcher.startDocumentFragment(fStringPool);
1443: }
1444:
1445: private void pushContentLeafStack() throws Exception {
1446: int contentType = getContentSpecType(fCurrentElementIndex);
1447: if (contentType == XMLElementDecl.TYPE_CHILDREN
1448: || contentType == XMLElementDecl.TYPE_MIXED_COMPLEX) {
1449: XMLContentModel cm = getElementContentModel(fCurrentElementIndex);
1450: ContentLeafNameTypeVector cv = cm
1451: .getContentLeafNameTypeVector();
1452: if (cm != null) {
1453: fContentLeafStack[fElementDepth] = cv;
1454: //OTWI: on-the-way-in
1455: fContentModelStack[fElementDepth] = cm;
1456: // for DFA with wildcard, we validate on-the-way-in
1457: // for other content models, we do it on-the-way-out
1458: if (cm instanceof DFAContentModel && cv != null)
1459: fContentModelStateStack[fElementDepth] = 0;
1460: else
1461: fContentModelStateStack[fElementDepth] = -2;
1462: fContentModelEleCount[fElementDepth] = 0;
1463: }
1464: } else {
1465: fContentModelStateStack[fElementDepth] = -2;
1466: }
1467: }
1468:
1469: private void ensureStackCapacity(int newElementDepth) {
1470:
1471: if (newElementDepth == fElementQNamePartsStack.length) {
1472: int[] newStack = new int[newElementDepth * 2];
1473: System.arraycopy(fScopeStack, 0, newStack, 0,
1474: newElementDepth);
1475: fScopeStack = newStack;
1476:
1477: newStack = new int[newElementDepth * 2];
1478: System.arraycopy(fGrammarNameSpaceIndexStack, 0, newStack,
1479: 0, newElementDepth);
1480: fGrammarNameSpaceIndexStack = newStack;
1481:
1482: QName[] newStackOfQueue = new QName[newElementDepth * 2];
1483: System.arraycopy(this .fElementQNamePartsStack, 0,
1484: newStackOfQueue, 0, newElementDepth);
1485: fElementQNamePartsStack = newStackOfQueue;
1486:
1487: QName qname = fElementQNamePartsStack[newElementDepth];
1488: if (qname == null) {
1489: for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) {
1490: fElementQNamePartsStack[i] = new QName();
1491: }
1492: }
1493:
1494: newStack = new int[newElementDepth * 2];
1495: System.arraycopy(fElementEntityStack, 0, newStack, 0,
1496: newElementDepth);
1497: fElementEntityStack = newStack;
1498:
1499: newStack = new int[newElementDepth * 2];
1500: System.arraycopy(fElementIndexStack, 0, newStack, 0,
1501: newElementDepth);
1502: fElementIndexStack = newStack;
1503:
1504: newStack = new int[newElementDepth * 2];
1505: System.arraycopy(fContentSpecTypeStack, 0, newStack, 0,
1506: newElementDepth);
1507: fContentSpecTypeStack = newStack;
1508:
1509: newStack = new int[newElementDepth * 2];
1510: System.arraycopy(fValidationFlagStack, 0, newStack, 0,
1511: newElementDepth);
1512: fValidationFlagStack = newStack;
1513:
1514: ContentLeafNameTypeVector[] newStackV = new ContentLeafNameTypeVector[newElementDepth * 2];
1515: System.arraycopy(fContentLeafStack, 0, newStackV, 0,
1516: newElementDepth);
1517: fContentLeafStack = newStackV;
1518:
1519: //OTWI: on-the-way-in
1520: XMLContentModel[] newStackCM = new XMLContentModel[newElementDepth * 2];
1521: System.arraycopy(fContentModelStack, 0, newStackCM, 0,
1522: newElementDepth);
1523: fContentModelStack = newStackCM;
1524: newStack = new int[newElementDepth * 2];
1525: System.arraycopy(fContentModelStateStack, 0, newStack, 0,
1526: newElementDepth);
1527: fContentModelStateStack = newStack;
1528: newStack = new int[newElementDepth * 2];
1529: System.arraycopy(fContentModelEleCount, 0, newStack, 0,
1530: newElementDepth);
1531: fContentModelEleCount = newStack;
1532: }
1533: }
1534:
1535: /** Call end element. */
1536: public void callEndElement(int readerId) throws Exception {
1537: if (DEBUG_SCHEMA_VALIDATION)
1538: System.out.println("=======EndElement : "
1539: + fStringPool.toString(fCurrentElement.localpart)
1540: + "\n");
1541:
1542: int prefixIndex = fCurrentElement.prefix;
1543: int elementType = fCurrentElement.rawname;
1544:
1545: if (fCurrentElementEntity != readerId) {
1546: fErrorReporter.reportError(fErrorReporter.getLocator(),
1547: XMLMessages.XML_DOMAIN,
1548: XMLMessages.MSG_ELEMENT_ENTITY_MISMATCH,
1549: XMLMessages.P78_NOT_WELLFORMED,
1550: new Object[] { fStringPool.toString(elementType) },
1551: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
1552: }
1553:
1554: fElementDepth--;
1555: if (fValidating) {
1556: int elementIndex = fCurrentElementIndex;
1557: if (elementIndex != -1 && fCurrentContentSpecType != -1) {
1558: QName children[] = fElementChildren;
1559: int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
1560: int childrenLength = fElementChildrenLength
1561: - childrenOffset;
1562: if (DEBUG_ELEMENT_CHILDREN) {
1563: System.out.println("endElement("
1564: + fStringPool
1565: .toString(fCurrentElement.rawname)
1566: + ')');
1567: System.out.println("fCurrentContentSpecType : "
1568: + fCurrentContentSpecType);
1569: System.out.print("offset: ");
1570: System.out.print(childrenOffset);
1571: System.out.print(", length: ");
1572: System.out.print(childrenLength);
1573: System.out.println();
1574: printChildren();
1575: printStack();
1576: }
1577: int result = checkContent(elementIndex, children,
1578: childrenOffset, childrenLength);
1579: fCurrentDV = null;
1580:
1581: if (DEBUG_SCHEMA_VALIDATION)
1582: System.out
1583: .println("!!!!!!!!In XMLValidator, the return value from checkContent : "
1584: + result);
1585:
1586: if (result != -1) {
1587: int majorCode = result != childrenLength ? XMLMessages.MSG_CONTENT_INVALID
1588: : XMLMessages.MSG_CONTENT_INCOMPLETE;
1589: fGrammar.getElementDecl(elementIndex,
1590: fTempElementDecl);
1591: if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
1592: reportRecoverableXMLError(majorCode, 0,
1593: fStringPool.toString(elementType),
1594: "EMPTY");
1595: } else
1596: reportRecoverableXMLError(
1597: majorCode,
1598: 0,
1599: fStringPool.toString(elementType),
1600: XMLContentSpec
1601: .toString(
1602: fGrammar,
1603: fStringPool,
1604: fTempElementDecl.contentSpecIndex));
1605: }
1606: }
1607: fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
1608:
1609: // call matchers and de-activate context
1610: if (fGrammarIsSchemaGrammar) {
1611: int oldCount = fMatcherStack.getMatcherCount();
1612: for (int i = oldCount - 1; i >= 0; i--) {
1613: XPathMatcher matcher = fMatcherStack
1614: .getMatcherAt(i);
1615: if (DEBUG_IDENTITY_CONSTRAINTS) {
1616: System.out
1617: .println("<IC>: "
1618: + matcher
1619: + "#endElement("
1620: + fStringPool
1621: .toString(fCurrentElement.rawname)
1622: + ")");
1623: }
1624: matcher.endElement(fCurrentElement,
1625: fCurrentElementIndex,
1626: (SchemaGrammar) fGrammar);
1627: }
1628: if (DEBUG_IDENTITY_CONSTRAINTS) {
1629: System.out
1630: .println("<IC>: popping context - element: "
1631: + fStringPool
1632: .toString(fCurrentElement.rawname));
1633: }
1634: if (fMatcherStack.size() > 0) {
1635: fMatcherStack.popContext();
1636: }
1637: int newCount = fMatcherStack.getMatcherCount();
1638: // handle everything *but* keyref's.
1639: for (int i = oldCount - 1; i >= newCount; i--) {
1640: XPathMatcher matcher = fMatcherStack
1641: .getMatcherAt(i);
1642: IdentityConstraint id;
1643: if ((id = matcher.getIDConstraint()) != null
1644: && id.getType() != IdentityConstraint.KEYREF) {
1645: if (DEBUG_IDENTITY_CONSTRAINTS) {
1646: System.out.println("<IC>: " + matcher
1647: + "#endDocumentFragment()");
1648: }
1649: matcher.endDocumentFragment();
1650: fValueStoreCache.transplant(id);
1651: } else if (id == null)
1652: matcher.endDocumentFragment();
1653: }
1654: // now handle keyref's/...
1655: for (int i = oldCount - 1; i >= newCount; i--) {
1656: XPathMatcher matcher = fMatcherStack
1657: .getMatcherAt(i);
1658: IdentityConstraint id;
1659: if ((id = matcher.getIDConstraint()) != null
1660: && id.getType() == IdentityConstraint.KEYREF) {
1661: if (DEBUG_IDENTITY_CONSTRAINTS) {
1662: System.out.println("<IC>: " + matcher
1663: + "#endDocumentFragment()");
1664: }
1665: ValueStoreBase values = fValueStoreCache
1666: .getValueStoreFor(id);
1667: if (values != null) // nothing to do if nothing matched!
1668: values.endDocumentFragment();
1669: matcher.endDocumentFragment();
1670: }
1671: }
1672: fValueStoreCache.endElement();
1673: }
1674: }
1675: fDocumentHandler.endElement(fCurrentElement);
1676: if (fNamespacesEnabled) {
1677: fNamespacesScope.decreaseDepth();
1678: }
1679:
1680: // now pop this element off the top of the element stack
1681: //if (fElementDepth-- < 0) {
1682: if (fElementDepth < -1) {
1683: throw new RuntimeException("FWK008 Element stack underflow");
1684: }
1685: if (fElementDepth < 0) {
1686: fCurrentElement.clear();
1687: fCurrentElementEntity = -1;
1688: fCurrentElementIndex = -1;
1689: fCurrentContentSpecType = -1;
1690: fInElementContent = false;
1691: //
1692: // Check after document is fully parsed
1693: // (1) check that there was an element with a matching id for every
1694: // IDREF and IDREFS attr (V_IDREF0)
1695: //
1696: if (fValidating) {
1697: try {
1698: this .fValIDRef.validate(null, this .fCheckIDRef); //Do final IDREF validation round
1699: this .fIdDefs.clear();
1700: this .fIdREFDefs.clear();
1701: } catch (InvalidDatatypeValueException ex) {
1702: reportRecoverableXMLError(ex.getMajorCode(), ex
1703: .getMinorCode(), ex.getMessage());
1704: }
1705: }
1706: return;
1707: }
1708:
1709: //restore enclosing element to all the "current" variables
1710: // REVISIT: Validation. This information needs to be stored.
1711: fCurrentElement.prefix = -1;
1712:
1713: if (fNamespacesEnabled) { //If Namespace enable then localName != rawName
1714: fCurrentElement.localpart = fElementQNamePartsStack[fElementDepth].localpart;
1715: } else {//REVISIT - jeffreyr - This is so we still do old behavior when namespace is off
1716: fCurrentElement.localpart = fElementQNamePartsStack[fElementDepth].rawname;
1717: }
1718: fCurrentElement.rawname = fElementQNamePartsStack[fElementDepth].rawname;
1719: fCurrentElement.uri = fElementQNamePartsStack[fElementDepth].uri;
1720: fCurrentElement.prefix = fElementQNamePartsStack[fElementDepth].prefix;
1721:
1722: fCurrentElementEntity = fElementEntityStack[fElementDepth];
1723: fCurrentElementIndex = fElementIndexStack[fElementDepth];
1724: fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth];
1725:
1726: fValidating = fValidationFlagStack[fElementDepth] == 0 ? true
1727: : false;
1728:
1729: fCurrentScope = fScopeStack[fElementDepth];
1730:
1731: if (DEBUG_SCHEMA_VALIDATION) {
1732:
1733: System.out
1734: .println("+++++ currentElement : "
1735: + fStringPool.toString(elementType)
1736: + "\n fCurrentElementIndex : "
1737: + fCurrentElementIndex
1738: + "\n fCurrentScope : "
1739: + fCurrentScope
1740: + "\n fCurrentContentSpecType : "
1741: + fCurrentContentSpecType
1742: + "\n++++++++++++++++++++++++++++++++++++++++++++++++");
1743: }
1744:
1745: // if enclosing element's Schema is different, need to switch "context"
1746: if (fGrammarNameSpaceIndex != fGrammarNameSpaceIndexStack[fElementDepth]) {
1747:
1748: fGrammarNameSpaceIndex = fGrammarNameSpaceIndexStack[fElementDepth];
1749: if (fValidating && fGrammarIsSchemaGrammar)
1750: if (fGrammarNameSpaceIndex < StringPool.EMPTY_STRING) {
1751: fGrammar = null;
1752: fGrammarIsSchemaGrammar = false;
1753: fGrammarIsDTDGrammar = false;
1754: } else if (!switchGrammar(fGrammarNameSpaceIndex)) {
1755: reportRecoverableXMLError(
1756: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
1757: XMLMessages.SCHEMA_GENERIC_ERROR,
1758: "Grammar with uri: "
1759: + fStringPool
1760: .toString(fGrammarNameSpaceIndex)
1761: + " , can not be found; possible mismatch between instance document's namespace and that of schema");
1762: }
1763: }
1764:
1765: if (fValidating) {
1766: fBufferDatatype = false;
1767: }
1768: fInElementContent = (fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN);
1769:
1770: } // callEndElement(int)
1771:
1772: /** Call start CDATA section. */
1773: public void callStartCDATA() throws Exception {
1774: if (fValidating && fInElementContent) {
1775: charDataInContent();
1776: }
1777: fDocumentHandler.startCDATA();
1778: }
1779:
1780: /** Call end CDATA section. */
1781: public void callEndCDATA() throws Exception {
1782: fDocumentHandler.endCDATA();
1783: }
1784:
1785: /** Call characters. */
1786: public void callCharacters(int ch) throws Exception {
1787:
1788: if (fCharRefData == null) {
1789: fCharRefData = new char[2];
1790: }
1791: int count = (ch < 0x10000) ? 1 : 2;
1792: if (count == 1) {
1793: fCharRefData[0] = (char) ch;
1794: } else {
1795: fCharRefData[0] = (char) (((ch - 0x00010000) >> 10) + 0xd800);
1796: fCharRefData[1] = (char) (((ch - 0x00010000) & 0x3ff) + 0xdc00);
1797: }
1798: if (fValidating
1799: && (fInElementContent || fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY)) {
1800: charDataInContent();
1801: }
1802: if (fValidating) {
1803: if (fBufferDatatype) {
1804: fDatatypeBuffer.append(fCharRefData, 0, 1);
1805: }
1806: }
1807:
1808: // call all active identity constraints
1809: int matcherCount = fMatcherStack.getMatcherCount();
1810: for (int i = 0; i < matcherCount; i++) {
1811: XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
1812: if (DEBUG_IDENTITY_CONSTRAINTS) {
1813: String text = new String(fCharRefData, 0, count);
1814: System.out.println("<IC>: " + matcher.toString()
1815: + "#characters(" + text + ")");
1816: }
1817: matcher.characters(fCharRefData, 0, count);
1818: }
1819:
1820: if (fSendCharDataAsCharArray) {
1821: fDocumentHandler.characters(fCharRefData, 0, count);
1822: } else {
1823: int index = fStringPool.addString(new String(fCharRefData,
1824: 0, count));
1825: fDocumentHandler.characters(index);
1826: }
1827: } // callCharacters(int)
1828:
1829: /** Call processing instruction. */
1830: public void callProcessingInstruction(int target, int data)
1831: throws Exception {
1832: fDocumentHandler.processingInstruction(target, data);
1833: }
1834:
1835: /** Call comment. */
1836: public void callComment(int comment) throws Exception {
1837: fDocumentHandler.comment(comment);
1838: }
1839:
1840: //
1841: // NamespacesScope.NamespacesHandler methods
1842: //
1843:
1844: /** Start a new namespace declaration scope. */
1845: public void startNamespaceDeclScope(int prefix, int uri)
1846: throws Exception {
1847: fDocumentHandler.startNamespaceDeclScope(prefix, uri);
1848: }
1849:
1850: /** End a namespace declaration scope. */
1851: public void endNamespaceDeclScope(int prefix) throws Exception {
1852: fDocumentHandler.endNamespaceDeclScope(prefix);
1853: }
1854:
1855: // attributes
1856:
1857: // other
1858:
1859: /** Sets the root element. */
1860: public void setRootElementType(QName rootElement) {
1861: fRootElement.setValues(rootElement);
1862: }
1863:
1864: /**
1865: * Returns true if the element declaration is external.
1866: * <p>
1867: * <strong>Note:</strong> This method is primarilly useful for
1868: * DTDs with internal and external subsets.
1869: */
1870: private boolean getElementDeclIsExternal(int elementIndex) {
1871: /*if (elementIndex < 0 || elementIndex >= fElementCount) {
1872: return false;
1873: }
1874: int chunk = elementIndex >> CHUNK_SHIFT;
1875: int index = elementIndex & CHUNK_MASK;
1876: return (fElementDeclIsExternal[chunk][index] != 0);
1877: */
1878:
1879: if (fGrammarIsDTDGrammar) {
1880: return ((DTDGrammar) fGrammar)
1881: .getElementDeclIsExternal(elementIndex);
1882: }
1883: return false;
1884: }
1885:
1886: /** Returns the content spec type for an element index. */
1887: public int getContentSpecType(int elementIndex) {
1888:
1889: int contentSpecType = -1;
1890: if (elementIndex > -1) {
1891: if (fGrammar.getElementDecl(elementIndex, fTempElementDecl)) {
1892: contentSpecType = fTempElementDecl.type;
1893: }
1894: }
1895: return contentSpecType;
1896: }
1897:
1898: /** Returns the content spec handle for an element index. */
1899: public int getContentSpecHandle(int elementIndex) {
1900: int contentSpecHandle = -1;
1901: if (elementIndex > -1) {
1902: if (fGrammar.getElementDecl(elementIndex, fTempElementDecl)) {
1903: contentSpecHandle = fTempElementDecl.contentSpecIndex;
1904: }
1905: }
1906: return contentSpecHandle;
1907: }
1908:
1909: //
1910: // Protected methods
1911: //
1912:
1913: // error reporting
1914:
1915: /** Report a recoverable schema error. */
1916: private void reportSchemaError(int code, Object[] args)
1917: throws Exception {
1918: fErrorReporter.reportError(fErrorReporter.getLocator(),
1919: SchemaMessageProvider.SCHEMA_DOMAIN, code,
1920: SchemaMessageProvider.MSG_NONE, args,
1921: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1922: } // reportSchemaError(int,Object)
1923:
1924: /** Report a recoverable xml error. */
1925: protected void reportRecoverableXMLError(int majorCode,
1926: int minorCode) throws Exception {
1927:
1928: fErrorReporter.reportError(fErrorReporter.getLocator(),
1929: XMLMessages.XML_DOMAIN, majorCode, minorCode, null,
1930: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1931:
1932: } // reportRecoverableXMLError(int,int)
1933:
1934: /** Report a recoverable xml error. */
1935: protected void reportRecoverableXMLError(int majorCode,
1936: int minorCode, int stringIndex1) throws Exception {
1937:
1938: Object[] args = { fStringPool.toString(stringIndex1) };
1939: fErrorReporter.reportError(fErrorReporter.getLocator(),
1940: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
1941: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1942:
1943: } // reportRecoverableXMLError(int,int,int)
1944:
1945: /** Report a recoverable xml error. */
1946: protected void reportRecoverableXMLError(int majorCode,
1947: int minorCode, String string1) throws Exception {
1948:
1949: Object[] args = { string1 };
1950: fErrorReporter.reportError(fErrorReporter.getLocator(),
1951: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
1952: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1953:
1954: } // reportRecoverableXMLError(int,int,String)
1955:
1956: /** Report a recoverable xml error. */
1957: protected void reportRecoverableXMLError(int majorCode,
1958: int minorCode, int stringIndex1, int stringIndex2)
1959: throws Exception {
1960:
1961: Object[] args = { fStringPool.toString(stringIndex1),
1962: fStringPool.toString(stringIndex2) };
1963: fErrorReporter.reportError(fErrorReporter.getLocator(),
1964: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
1965: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1966:
1967: } // reportRecoverableXMLError(int,int,int,int)
1968:
1969: /** Report a recoverable xml error. */
1970: protected void reportRecoverableXMLError(int majorCode,
1971: int minorCode, String string1, String string2)
1972: throws Exception {
1973:
1974: Object[] args = { string1, string2 };
1975: fErrorReporter.reportError(fErrorReporter.getLocator(),
1976: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
1977: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1978:
1979: } // reportRecoverableXMLError(int,int,String,String)
1980:
1981: /** Report a recoverable xml error. */
1982: protected void reportRecoverableXMLError(int majorCode,
1983: int minorCode, String string1, String string2,
1984: String string3) throws Exception {
1985:
1986: Object[] args = { string1, string2, string3 };
1987: fErrorReporter.reportError(fErrorReporter.getLocator(),
1988: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
1989: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1990:
1991: } // reportRecoverableXMLError(int,int,String,String,String)
1992:
1993: // content spec
1994:
1995: /**
1996: * Returns information about which elements can be placed at a particular point
1997: * in the passed element's content model.
1998: * <p>
1999: * Note that the incoming content model to test must be valid at least up to
2000: * the insertion point. If not, then -1 will be returned and the info object
2001: * will not have been filled in.
2002: * <p>
2003: * If, on return, the info.isValidEOC flag is set, then the 'insert after'
2004: * elemement is a valid end of content, i.e. nothing needs to be inserted
2005: * after it to make the parent element's content model valid.
2006: *
2007: * @param elementIndex The index within the <code>ElementDeclPool</code> of the
2008: * element which is being querying.
2009: * @param fullyValid Only return elements that can be inserted and still
2010: * maintain the validity of subsequent elements past the
2011: * insertion point (if any). If the insertion point is at
2012: * the end, and this is true, then only elements that can
2013: * be legal final states will be returned.
2014: * @param info An object that contains the required input data for the method,
2015: * and which will contain the output information if successful.
2016: *
2017: * @return The value -1 if fully valid, else the 0 based index of the child
2018: * that first failed before the insertion point. If the value
2019: * returned is equal to the number of children, then the specified
2020: * children are valid but additional content is required to reach a
2021: * valid ending state.
2022: *
2023: * @exception Exception Thrown on error.
2024: *
2025: * @see InsertableElementsInfo
2026: */
2027: protected int whatCanGoHere(int elementIndex, boolean fullyValid,
2028: InsertableElementsInfo info) throws Exception {
2029:
2030: //
2031: // Do some basic sanity checking on the info packet. First, make sure
2032: // that insertAt is not greater than the child count. It can be equal,
2033: // which means to get appendable elements, but not greater. Or, if
2034: // the current children array is null, that's bad too.
2035: //
2036: // Since the current children array must have a blank spot for where
2037: // the insert is going to be, the child count must always be at least
2038: // one.
2039: //
2040: // Make sure that the child count is not larger than the current children
2041: // array. It can be equal, which means get appendable elements, but not
2042: // greater.
2043: //
2044: if (info.insertAt > info.childCount || info.curChildren == null
2045: || info.childCount < 1
2046: || info.childCount > info.curChildren.length) {
2047: fErrorReporter
2048: .reportError(
2049: fErrorReporter.getLocator(),
2050: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
2051: ImplementationMessages.VAL_WCGHI, 0, null,
2052: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
2053: }
2054:
2055: int retVal = 0;
2056: try {
2057: // Get the content model for this element
2058: final XMLContentModel cmElem = getElementContentModel(elementIndex);
2059:
2060: // And delegate this call to it
2061: retVal = cmElem.whatCanGoHere(fullyValid, info);
2062: } catch (CMException excToCatch) {
2063: // REVISIT - Translate caught error to the protected error handler interface
2064: int majorCode = excToCatch.getErrorCode();
2065: fErrorReporter
2066: .reportError(
2067: fErrorReporter.getLocator(),
2068: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
2069: majorCode, 0, null,
2070: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
2071: throw excToCatch;
2072: }
2073: return retVal;
2074:
2075: } // whatCanGoHere(int,boolean,InsertableElementsInfo):int
2076:
2077: // attribute information
2078:
2079: /** Protected for use by AttributeValidator classes. */
2080: protected boolean getAttDefIsExternal(QName element, QName attribute) {
2081: int attDefIndex = getAttDef(element, attribute);
2082: if (fGrammarIsDTDGrammar) {
2083: return ((DTDGrammar) fGrammar)
2084: .getAttributeDeclIsExternal(attDefIndex);
2085: }
2086: return false;
2087: }
2088:
2089: //
2090: // Private methods
2091: //
2092:
2093: // other
2094:
2095: /** Returns true if using a standalone reader. */
2096: private boolean usingStandaloneReader() {
2097: return fStandaloneReader == -1
2098: || fEntityHandler.getReaderId() == fStandaloneReader;
2099: }
2100:
2101: /** Returns a locator implementation. */
2102: private LocatorImpl getLocatorImpl(LocatorImpl fillin) {
2103:
2104: Locator here = fErrorReporter.getLocator();
2105: if (fillin == null)
2106: return new LocatorImpl(here);
2107: fillin.setPublicId(here.getPublicId());
2108: fillin.setSystemId(here.getSystemId());
2109: fillin.setLineNumber(here.getLineNumber());
2110: fillin.setColumnNumber(here.getColumnNumber());
2111: return fillin;
2112:
2113: } // getLocatorImpl(LocatorImpl):LocatorImpl
2114:
2115: // initialization
2116:
2117: /** Reset pool. */
2118: private void poolReset() {
2119: if (fValidating) { // - el
2120: this .fIdDefs.clear();
2121: this .fIdREFDefs.clear();
2122: }
2123: } // poolReset()
2124:
2125: /** Reset common. */
2126: private void resetCommon(StringPool stringPool) throws Exception {
2127:
2128: fStringPool = stringPool;
2129: fValidateEntity.setDatatypeObject(new Object[] {
2130: fEntityHandler, stringPool });
2131: fValidating = fValidationEnabled;
2132: fValidationEnabledByDynamic = false;
2133: fDynamicDisabledByValidation = false;
2134: fNormalizeContents = false;
2135: poolReset();
2136: fCalledStartDocument = false;
2137: fStandaloneReader = -1;
2138: fElementChildrenLength = 0;
2139: fElementDepth = -1;
2140: fSeenRootElement = false;
2141: fSeenDoctypeDecl = false;
2142: fNamespacesScope = null;
2143: fNamespacesPrefix = -1;
2144: fRootElement.clear();
2145: fAttrListHandle = -1;
2146: fCheckedForSchema = false;
2147:
2148: fCurrentScope = TOP_LEVEL_SCOPE;
2149: fCurrentSchemaURI = StringPool.EMPTY_STRING;
2150: fEmptyURI = StringPool.EMPTY_STRING;
2151: fXsiPrefix = -1;
2152: fXsiTypeValidator = null;
2153:
2154: // xsi:nill
2155: fNil = false;
2156:
2157: fGrammar = null;
2158: fGrammarNameSpaceIndex = StringPool.EMPTY_STRING;
2159:
2160: // we reset fGrammarResolver in XMLParser before passing it to Validator
2161: fSGComparator = null;
2162: fGrammarIsDTDGrammar = false;
2163: fGrammarIsSchemaGrammar = false;
2164:
2165: //Normalization
2166: fCurrentDV = null;
2167: fFirstChunk = true;
2168: fTrailing = false;
2169: fWhiteSpace = DatatypeValidator.COLLAPSE;
2170:
2171: fMatcherStack.clear();
2172:
2173: UPACheckedGrammarURIs.clear();
2174: //REVISIT: fExternalSchemas/fExternalNoNamespaceSchema is not reset 'cause we don't have grammar cashing in Xerces-J
2175: // reconsider implementation when we have grammar chashing
2176: //
2177: init();
2178:
2179: } // resetCommon(StringPool)
2180:
2181: /** Initialize. */
2182: private void init() {
2183:
2184: fEmptyURI = fStringPool.addSymbol("");
2185: fXsiURI = fStringPool.addSymbol(SchemaSymbols.URI_XSI);
2186:
2187: fEMPTYSymbol = fStringPool.addSymbol("EMPTY");
2188: fANYSymbol = fStringPool.addSymbol("ANY");
2189: fMIXEDSymbol = fStringPool.addSymbol("MIXED");
2190: fCHILDRENSymbol = fStringPool.addSymbol("CHILDREN");
2191:
2192: fCDATASymbol = fStringPool.addSymbol("CDATA");
2193: fIDSymbol = fStringPool.addSymbol("ID");
2194: fIDREFSymbol = fStringPool.addSymbol("IDREF");
2195: fIDREFSSymbol = fStringPool.addSymbol("IDREFS");
2196: fENTITYSymbol = fStringPool.addSymbol("ENTITY");
2197: fENTITIESSymbol = fStringPool.addSymbol("ENTITIES");
2198: fNMTOKENSymbol = fStringPool.addSymbol("NMTOKEN");
2199: fNMTOKENSSymbol = fStringPool.addSymbol("NMTOKENS");
2200: fNOTATIONSymbol = fStringPool.addSymbol("NOTATION");
2201: fENUMERATIONSymbol = fStringPool.addSymbol("ENUMERATION");
2202: fREQUIREDSymbol = fStringPool.addSymbol("#REQUIRED");
2203: fFIXEDSymbol = fStringPool.addSymbol("#FIXED");
2204: fDATATYPESymbol = fStringPool.addSymbol("<<datatype>>");
2205: fEpsilonIndex = fStringPool.addSymbol("<<CMNODE_EPSILON>>");
2206: fXMLLang = fStringPool.addSymbol("xml:lang");
2207:
2208: } // init()
2209:
2210: /**
2211: * This method should only be invoked when validation
2212: * is turn on.
2213: * fDataTypeReg object of type DatatypeValidatorFactoryImpl
2214: * needs to be initialized.
2215: * In the XMLValidator the table will be by default
2216: * first initialized to 9 validators used by DTD
2217: * validation.
2218: * These Validators are known.
2219: * Later on if we ever find a Schema and need to do
2220: * Schema validation then we will expand this
2221: * registry table of fDataTypeReg.
2222: */
2223: private void initDataTypeValidators() {
2224:
2225: if (fGrammarResolver != null) {
2226: fDataTypeReg = (DatatypeValidatorFactoryImpl) fGrammarResolver
2227: .getDatatypeRegistry();
2228: fDataTypeReg.initializeDTDRegistry();
2229: }
2230: if (fDataTypeReg != null) {
2231: fValID = fDataTypeReg.getDatatypeValidator("ID");
2232: fValIDRef = fDataTypeReg.getDatatypeValidator("IDREF");
2233: fValIDRefs = fDataTypeReg.getDatatypeValidator("IDREFS");
2234: fValENTITY = fDataTypeReg.getDatatypeValidator("ENTITY");
2235: fValENTITIES = fDataTypeReg
2236: .getDatatypeValidator("ENTITIES");
2237: fValNMTOKEN = fDataTypeReg.getDatatypeValidator("NMTOKEN");
2238: fValNMTOKENS = fDataTypeReg
2239: .getDatatypeValidator("NMTOKENS");
2240: fValNOTATION = fDataTypeReg
2241: .getDatatypeValidator("NOTATION");
2242: }
2243: }
2244:
2245: // other
2246:
2247: // default attribute
2248:
2249: /** addDefaultAttributes. */
2250: private int addDefaultAttributes(int elementIndex,
2251: XMLAttrList attrList, int attrIndex,
2252: boolean validationEnabled, boolean standalone)
2253: throws Exception {
2254:
2255: //System.out.println("XMLValidator#addDefaultAttributes");
2256: //System.out.print(" ");
2257: //fGrammar.printAttributes(elementIndex);
2258:
2259: //
2260: // Check after all specified attrs are scanned
2261: // (1) report error for REQUIRED attrs that are missing (V_TAGc)
2262: // (2) report error for PROHIBITED attrs that are present (V_TAGc)
2263: // (3) check that FIXED attrs have matching value (V_TAGd)
2264: // (4) add default attrs (FIXED and NOT_FIXED)
2265: //
2266: fGrammar.getElementDecl(elementIndex, fTempElementDecl);
2267:
2268: int elementNameIndex = fTempElementDecl.name.localpart;
2269: int attlistIndex = fGrammar
2270: .getFirstAttributeDeclIndex(elementIndex);
2271: int firstCheck = attrIndex;
2272: int lastCheck = -1;
2273: while (attlistIndex != -1) {
2274: fGrammar.getAttributeDecl(attlistIndex, fTempAttDecl);
2275:
2276: int attPrefix = fTempAttDecl.name.prefix;
2277: int attName = fTempAttDecl.name.localpart;
2278: int attType = attributeTypeName(fTempAttDecl);
2279: int attDefType = fTempAttDecl.defaultType;
2280: int attValue = -1;
2281: if (fTempAttDecl.defaultValue != null) {
2282: attValue = fStringPool
2283: .addSymbol(fTempAttDecl.defaultValue);
2284: }
2285:
2286: boolean specified = false;
2287: boolean required = (attDefType & XMLAttributeDecl.DEFAULT_TYPE_REQUIRED) > 0;
2288: boolean prohibited = (attDefType & XMLAttributeDecl.DEFAULT_TYPE_PROHIBITED) > 0;
2289: boolean fixed = (attDefType & XMLAttributeDecl.DEFAULT_TYPE_FIXED) > 0;
2290:
2291: if (firstCheck != -1) {
2292: boolean cdata = attType == fCDATASymbol;
2293: if (!cdata || required || prohibited || attValue != -1) {
2294: int i = attrList.getFirstAttr(firstCheck);
2295: while (i != -1
2296: && (lastCheck == -1 || i <= lastCheck)) {
2297:
2298: if ((fGrammarIsDTDGrammar && (attrList
2299: .getAttrName(i) == fTempAttDecl.name.rawname))
2300: || (fStringPool.equalNames(attrList
2301: .getAttrLocalpart(i), attName) && fStringPool
2302: .equalNames(attrList
2303: .getAttrURI(i),
2304: fTempAttDecl.name.uri))) {
2305:
2306: if (prohibited && validationEnabled) {
2307: Object[] args = {
2308: fStringPool
2309: .toString(elementNameIndex),
2310: fStringPool.toString(attName) };
2311: fErrorReporter
2312: .reportError(
2313: fErrorReporter
2314: .getLocator(),
2315: SchemaMessageProvider.SCHEMA_DOMAIN,
2316: SchemaMessageProvider.ProhibitedAttributePresent,
2317: SchemaMessageProvider.MSG_NONE,
2318: args,
2319: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2320: }
2321: specified = true;
2322: break;
2323: }
2324: i = attrList.getNextAttr(i);
2325: }
2326: }
2327: }
2328:
2329: if (!specified) {
2330: if (required) {
2331: if (validationEnabled) {
2332: Object[] args = {
2333: fStringPool.toString(elementNameIndex),
2334: fStringPool.toString(attName) };
2335: fErrorReporter
2336: .reportError(
2337: fErrorReporter.getLocator(),
2338: XMLMessages.XML_DOMAIN,
2339: XMLMessages.MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED,
2340: XMLMessages.VC_REQUIRED_ATTRIBUTE,
2341: args,
2342: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2343: }
2344: } else if (attValue != -1) {
2345: if (validationEnabled && standalone) {
2346: if (fGrammarIsDTDGrammar
2347: && ((DTDGrammar) fGrammar)
2348: .getAttributeDeclIsExternal(attlistIndex)) {
2349:
2350: Object[] args = {
2351: fStringPool
2352: .toString(elementNameIndex),
2353: fStringPool.toString(attName) };
2354: fErrorReporter
2355: .reportError(
2356: fErrorReporter.getLocator(),
2357: XMLMessages.XML_DOMAIN,
2358: XMLMessages.MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED,
2359: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
2360: args,
2361: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2362: }
2363: }
2364: if (validationEnabled) {
2365: // default value should have been already normalized
2366: validateUsingDV(fTempAttDecl.datatypeValidator,
2367: fStringPool.toString(attValue), true);
2368: }
2369: if (attrIndex == -1) {
2370: attrIndex = attrList.startAttrList();
2371: }
2372: // REVISIT: Validation. What should the prefix be?
2373: fTempQName.setValues(attPrefix, attName, attName,
2374: fTempAttDecl.name.uri);
2375: int newAttr = attrList.addAttr(fTempQName,
2376: attValue, attType, false, false);
2377: if (lastCheck == -1) {
2378: lastCheck = newAttr;
2379: }
2380: }
2381: }
2382: attlistIndex = fGrammar
2383: .getNextAttributeDeclIndex(attlistIndex);
2384: }
2385: return attrIndex;
2386:
2387: } // addDefaultAttributes(int,XMLAttrList,int,boolean,boolean):int
2388:
2389: /** addDTDDefaultAttributes. */
2390: private int addDTDDefaultAttributes(QName element,
2391: XMLAttrList attrList, int attrIndex,
2392: boolean validationEnabled, boolean standalone)
2393: throws Exception {
2394:
2395: //
2396: // Check after all specified attrs are scanned
2397: // (1) report error for REQUIRED attrs that are missing (V_TAGc)
2398: // (2) check that FIXED attrs have matching value (V_TAGd)
2399: // (3) add default attrs (FIXED and NOT_FIXED)
2400: //
2401:
2402: int elementIndex = fGrammar.getElementDeclIndex(element, -1);
2403:
2404: if (elementIndex == -1) {
2405: return attrIndex;
2406: }
2407:
2408: fGrammar.getElementDecl(elementIndex, fTempElementDecl);
2409:
2410: int elementNameIndex = fTempElementDecl.name.rawname;
2411: int attlistIndex = fGrammar
2412: .getFirstAttributeDeclIndex(elementIndex);
2413: int firstCheck = attrIndex;
2414: int lastCheck = -1;
2415: while (attlistIndex != -1) {
2416:
2417: fGrammar.getAttributeDecl(attlistIndex, fTempAttDecl);
2418:
2419: // TO DO: For ericye Debug only
2420: /***
2421: if (fTempAttDecl != null) {
2422: XMLElementDecl element = new XMLElementDecl();
2423: fGrammar.getElementDecl(elementIndex, element);
2424: System.out.println("element: "+fStringPool.toString(element.name.localpart));
2425: System.out.println("attlistIndex " + attlistIndex + "\n"+
2426: "attName : '"+fStringPool.toString(fTempAttDecl.name.localpart) + "'\n"
2427: + "attType : "+fTempAttDecl.type + "\n"
2428: + "attDefaultType : "+fTempAttDecl.defaultType + "\n"
2429: + "attDefaultValue : '"+fTempAttDecl.defaultValue + "'\n"
2430: + attrList.getLength() +"\n"
2431: );
2432: }
2433: /***/
2434:
2435: int attPrefix = fTempAttDecl.name.prefix;
2436: int attName = fTempAttDecl.name.rawname;
2437: int attLocalpart = fTempAttDecl.name.localpart;
2438: int attType = attributeTypeName(fTempAttDecl);
2439: int attDefType = fTempAttDecl.defaultType;
2440: int attValue = -1;
2441: if (fTempAttDecl.defaultValue != null) {
2442: attValue = fStringPool
2443: .addSymbol(fTempAttDecl.defaultValue);
2444: }
2445: boolean specified = false;
2446: boolean required = (attDefType & XMLAttributeDecl.DEFAULT_TYPE_REQUIRED) > 0;
2447:
2448: /****
2449: if (fValidating && fGrammar != null && fGrammarIsDTDGrammar && attValue != -1) {
2450: normalizeAttValue(null, fTempAttDecl.name,
2451: attValue,attType,fTempAttDecl.list,
2452: fTempAttDecl.enumeration);
2453: }
2454: /****/
2455:
2456: if (firstCheck != -1) {
2457: boolean cdata = attType == fCDATASymbol;
2458: if (!cdata || required || attValue != -1) {
2459: int i = attrList.getFirstAttr(firstCheck);
2460: while (i != -1
2461: && (lastCheck == -1 || i <= lastCheck)) {
2462:
2463: if (attrList.getAttrName(i) == fTempAttDecl.name.rawname) {
2464:
2465: if (validationEnabled
2466: && (attDefType & XMLAttributeDecl.DEFAULT_TYPE_FIXED) > 0) {
2467: int alistValue = attrList
2468: .getAttValue(i);
2469: if (alistValue != attValue
2470: && !fStringPool
2471: .toString(alistValue)
2472: .equals(
2473: fStringPool
2474: .toString(attValue))) {
2475: Object[] args = {
2476: fStringPool
2477: .toString(elementNameIndex),
2478: fStringPool
2479: .toString(attName),
2480: fStringPool
2481: .toString(alistValue),
2482: fStringPool
2483: .toString(attValue) };
2484: fErrorReporter
2485: .reportError(
2486: fErrorReporter
2487: .getLocator(),
2488: XMLMessages.XML_DOMAIN,
2489: XMLMessages.MSG_FIXED_ATTVALUE_INVALID,
2490: XMLMessages.VC_FIXED_ATTRIBUTE_DEFAULT,
2491: args,
2492: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2493: }
2494: }
2495: specified = true;
2496: break;
2497: }
2498: i = attrList.getNextAttr(i);
2499: }
2500: }
2501: }
2502:
2503: if (!specified) {
2504: if (required) {
2505: if (validationEnabled) {
2506: Object[] args = {
2507: fStringPool.toString(elementNameIndex),
2508: fStringPool.toString(attName) };
2509: fErrorReporter
2510: .reportError(
2511: fErrorReporter.getLocator(),
2512: XMLMessages.XML_DOMAIN,
2513: XMLMessages.MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED,
2514: XMLMessages.VC_REQUIRED_ATTRIBUTE,
2515: args,
2516: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2517: }
2518: } else if (attValue != -1) {
2519: if (validationEnabled && standalone) {
2520: if (fGrammarIsDTDGrammar
2521: && ((DTDGrammar) fGrammar)
2522: .getAttributeDeclIsExternal(attlistIndex)) {
2523:
2524: Object[] args = {
2525: fStringPool
2526: .toString(elementNameIndex),
2527: fStringPool.toString(attName) };
2528: fErrorReporter
2529: .reportError(
2530: fErrorReporter.getLocator(),
2531: XMLMessages.XML_DOMAIN,
2532: XMLMessages.MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED,
2533: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
2534: args,
2535: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2536: }
2537: }
2538: if (validationEnabled) {
2539: validateUsingDV(fTempAttDecl.datatypeValidator,
2540: fStringPool.toString(attValue), true);
2541: }
2542: if (attrIndex == -1) {
2543: attrIndex = attrList.startAttrList();
2544: }
2545:
2546: fTempQName.setValues(attPrefix, attLocalpart,
2547: attName, fTempAttDecl.name.uri);
2548: int newAttr = attrList.addAttr(fTempQName,
2549: attValue, attType, false, false);
2550: if (lastCheck == -1) {
2551: lastCheck = newAttr;
2552: }
2553: }
2554: }
2555: attlistIndex = fGrammar
2556: .getNextAttributeDeclIndex(attlistIndex);
2557: }
2558: return attrIndex;
2559:
2560: } // addDTDDefaultAttributes(int,XMLAttrList,int,boolean,boolean):int
2561:
2562: // content models
2563:
2564: /** Queries the content model for the specified element index. */
2565: private XMLContentModel getElementContentModel(int elementIndex)
2566: throws Exception {
2567: XMLContentModel contentModel = null;
2568: if (elementIndex > -1) {
2569: if (fGrammar.getElementDecl(elementIndex, fTempElementDecl)) {
2570: if (fSGComparator == null) {
2571: fSGComparator = new SubstitutionGroupComparator(
2572: fGrammarResolver, fStringPool,
2573: fErrorReporter);
2574: }
2575: contentModel = fGrammar.getElementContentModel(
2576: elementIndex, fSGComparator);
2577: }
2578: }
2579: //return fGrammar.getElementContentModel(elementIndex);
2580: return contentModel;
2581: }
2582:
2583: // query attribute information
2584:
2585: /** Returns an attribute definition for an element type. */
2586: // this is only used by DTD validation.
2587: private int getAttDef(QName element, QName attribute) {
2588: if (fGrammar != null) {
2589: int scope = fCurrentScope;
2590: if (element.uri > -1) {
2591: scope = TOP_LEVEL_SCOPE;
2592: }
2593: int elementIndex = fGrammar.getElementDeclIndex(element,
2594: scope);
2595: if (elementIndex == -1) {
2596: return -1;
2597: }
2598: int attDefIndex = fGrammar
2599: .getFirstAttributeDeclIndex(elementIndex);
2600: while (attDefIndex != -1) {
2601: fGrammar.getAttributeDecl(attDefIndex,
2602: fTempAttributeDecl);
2603: if (fTempAttributeDecl.name.localpart == attribute.localpart
2604: && fTempAttributeDecl.name.uri == attribute.uri) {
2605: return attDefIndex;
2606: }
2607: attDefIndex = fGrammar
2608: .getNextAttributeDeclIndex(attDefIndex);
2609: }
2610: }
2611: return -1;
2612:
2613: } // getAttDef(QName,QName)
2614:
2615: /** Returns an attribute definition for an element type. */
2616: private int getAttDefByElementIndex(int elementIndex,
2617: QName attribute) {
2618: if (fGrammar != null && elementIndex > -1) {
2619: if (elementIndex == -1) {
2620: return -1;
2621: }
2622: int attDefIndex = fGrammar
2623: .getFirstAttributeDeclIndex(elementIndex);
2624: while (attDefIndex != -1) {
2625: fGrammar.getAttributeDecl(attDefIndex, fTempAttDecl);
2626:
2627: if (fGrammarIsDTDGrammar) {
2628: if (fTempAttDecl.name.rawname == attribute.rawname)
2629: return attDefIndex;
2630: } else if (fTempAttDecl.name.localpart == attribute.localpart
2631: && fTempAttDecl.name.uri == attribute.uri) {
2632: return attDefIndex;
2633: }
2634:
2635: if (fGrammarIsSchemaGrammar) {
2636: if (fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_ANY) {
2637: return attDefIndex;
2638: } else if (fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_OTHER) {
2639: if (attribute.uri != fTempAttDecl.name.uri) {
2640: return attDefIndex;
2641: }
2642: } else if (fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_LIST) {
2643: if (fStringPool
2644: .stringInList(fTempAttDecl.enumeration,
2645: attribute.uri)) {
2646: return attDefIndex;
2647: }
2648: }
2649: }
2650:
2651: attDefIndex = fGrammar
2652: .getNextAttributeDeclIndex(attDefIndex);
2653: }
2654: }
2655: return -1;
2656:
2657: } // getAttDef(QName,QName)
2658:
2659: // validation
2660:
2661: /** Root element specified. */
2662: private void rootElementSpecified(QName rootElement)
2663: throws Exception {
2664:
2665: if (fLoadDTDGrammar)
2666: // initialize the grammar to be the default one,
2667: // it definitely should be a DTD Grammar at this case;
2668: if (fGrammar == null) {
2669:
2670: fGrammar = fGrammarResolver.getGrammar("");
2671:
2672: if (fGrammar != null) {
2673: if (fGrammar instanceof DTDGrammar) {
2674: fGrammarIsDTDGrammar = true;
2675: fGrammarIsSchemaGrammar = false;
2676: } else if (fGrammar instanceof SchemaGrammar) {
2677: fGrammarIsSchemaGrammar = true;
2678: fGrammarIsDTDGrammar = false;
2679: }
2680:
2681: fGrammarNameSpaceIndex = fEmptyURI;
2682: }
2683: }
2684:
2685: if (fValidating) {
2686: if (fGrammarIsDTDGrammar
2687: && ((DTDGrammar) fGrammar)
2688: .getRootElementQName(fRootElement)) {
2689:
2690: String root1 = fStringPool
2691: .toString(fRootElement.rawname);
2692: String root2 = fStringPool
2693: .toString(rootElement.rawname);
2694: if (!root1.equals(root2)) {
2695: reportRecoverableXMLError(
2696: XMLMessages.MSG_ROOT_ELEMENT_TYPE,
2697: XMLMessages.VC_ROOT_ELEMENT_TYPE,
2698: fRootElement.rawname, rootElement.rawname);
2699: }
2700: }
2701: }
2702:
2703: if (fNamespacesEnabled) {
2704: if (fNamespacesScope == null) {
2705: fNamespacesScope = new NamespacesScope(this );
2706: fNamespacesPrefix = fStringPool.addSymbol("xmlns");
2707: //fNamespacesScope.setNamespaceForPrefix(fNamespacesPrefix, StringPool.EMPTY_STRING);
2708: // xxxxx
2709: fNamespacesScope.setNamespaceForPrefix(
2710: fNamespacesPrefix, -1);
2711: int xmlSymbol = fStringPool.addSymbol("xml");
2712: int xmlNamespace = fStringPool
2713: .addSymbol("http://www.w3.org/XML/1998/namespace");
2714: fNamespacesScope.setNamespaceForPrefix(xmlSymbol,
2715: xmlNamespace);
2716: }
2717: }
2718:
2719: } // rootElementSpecified(QName)
2720:
2721: /** Switchs to correct validating symbol tables when Schema changes.*/
2722:
2723: private boolean switchGrammar(int newGrammarNameSpaceIndex)
2724: throws Exception {
2725: Grammar tempGrammar = fGrammarResolver.getGrammar(fStringPool
2726: .toString(newGrammarNameSpaceIndex));
2727: if (tempGrammar == null) {
2728: // This is a case where namespaces is on with a DTD grammar.
2729: tempGrammar = fGrammarResolver.getGrammar("");
2730: }
2731: if (tempGrammar == null) {
2732: return false;
2733: } else {
2734: fGrammar = tempGrammar;
2735: if (fGrammar instanceof DTDGrammar) {
2736: fGrammarIsDTDGrammar = true;
2737: fGrammarIsSchemaGrammar = false;
2738: } else if (fGrammar instanceof SchemaGrammar) {
2739: fGrammarIsSchemaGrammar = true;
2740: fGrammarIsDTDGrammar = false;
2741: }
2742:
2743: return true;
2744: }
2745: }
2746:
2747: /** Binds namespaces to the element and attributes. */
2748: private void bindNamespacesToElementAndAttributes(QName element,
2749: XMLAttrList attrList) throws Exception {
2750:
2751: fNamespacesScope.increaseDepth();
2752:
2753: if (fAttrListHandle != -1 || !fSeenRootElement) {
2754: int index = attrList.getFirstAttr(fAttrListHandle);
2755: while (index != -1) {
2756: int attName = attrList.getAttrName(index);
2757: int attPrefix = attrList.getAttrPrefix(index);
2758: if (fStringPool.equalNames(attName, fXMLLang)) {
2759: /* No check: http://www.w3.org/XML/xml-19980210-errata#E73 and bug 2793 */
2760: } else if (fStringPool.equalNames(attName,
2761: fNamespacesPrefix)) {
2762: int uri = fStringPool.addSymbol(attrList
2763: .getAttValue(index));
2764: fNamespacesScope.setNamespaceForPrefix(
2765: StringPool.EMPTY_STRING, uri);
2766: } else {
2767: if (attPrefix == fNamespacesPrefix) {
2768: int nsPrefix = attrList.getAttrLocalpart(index);
2769: int uri = fStringPool.addSymbol(attrList
2770: .getAttValue(index));
2771: if (uri == StringPool.EMPTY_STRING) {
2772: Object[] args = { fStringPool
2773: .toString(nsPrefix) };
2774: fErrorReporter
2775: .reportError(
2776: fErrorReporter.getLocator(),
2777: XMLMessages.XMLNS_DOMAIN,
2778: XMLMessages.MSG_NAMESPACE_NAME_EMPTY,
2779: XMLMessages.NC_NAMESPACE_NAME_EMPTY,
2780: args,
2781: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2782: }
2783: fNamespacesScope.setNamespaceForPrefix(
2784: nsPrefix, uri);
2785:
2786: if (fValidating && fSchemaValidation) {
2787: boolean seeXsi = false;
2788: String attrValue = fStringPool
2789: .toString(attrList
2790: .getAttValue(index));
2791:
2792: if (attrValue.equals(SchemaSymbols.URI_XSI)) {
2793: fXsiPrefix = nsPrefix;
2794: seeXsi = true;
2795: }
2796: }
2797: }
2798: }
2799: index = attrList.getNextAttr(index);
2800: }
2801:
2802: String location = null;
2803: String uri = null;
2804:
2805: // if validating, walk through the list again to deal with "xsi:...."
2806: if (fValidating && fSchemaValidation) {
2807:
2808: fLocationUriPairs.clear();
2809: if (!fSeenRootElement) {
2810: // we are at the root element
2811: // and user set property on the parser to include external schemas
2812: //
2813: if (fExternalSchemas != null
2814: && fExternalSchemas.length() != 0) {
2815:
2816: parseSchemaLocation(fExternalSchemas);
2817: }
2818: if (fExternalNoNamespaceSchema != null
2819: && fExternalNoNamespaceSchema.length() != 0) {
2820:
2821: fLocationUriPairs.put(
2822: fExternalNoNamespaceSchema, "");
2823:
2824: //REVISIT: wrong solution (see AndyC note below)
2825: if (fNamespacesScope != null) {
2826: //bind prefix "" to URI "" in this case
2827: fNamespacesScope.setNamespaceForPrefix(
2828: fStringPool.addSymbol(""),
2829: fStringPool.addSymbol(""));
2830: }
2831: }
2832: parseSchemas();
2833: fLocationUriPairs.clear();
2834: }
2835:
2836: fXsiTypeAttValue = -1;
2837: fNil = false;
2838: index = attrList.getFirstAttr(fAttrListHandle);
2839: int attName;
2840: int attPrefix;
2841: while (index != -1) {
2842:
2843: attName = attrList.getAttrName(index);
2844: attPrefix = attrList.getAttrPrefix(index);
2845:
2846: if (fStringPool.equalNames(attName,
2847: fNamespacesPrefix)) {
2848: // REVISIT
2849: } else {
2850: if (DEBUG_SCHEMA_VALIDATION) {
2851: System.out.println("deal with XSI");
2852: System.out.println("before find XSI: "
2853: + fStringPool.toString(attPrefix)
2854: + ","
2855: + fStringPool.toString(fXsiPrefix));
2856: }
2857: if (fXsiPrefix != -1 && attPrefix == fXsiPrefix) {
2858:
2859: if (DEBUG_SCHEMA_VALIDATION) {
2860: System.out
2861: .println("find XSI: "
2862: + fStringPool
2863: .toString(attPrefix)
2864: + ","
2865: + fStringPool
2866: .toString(attName));
2867: }
2868:
2869: int localpart = attrList
2870: .getAttrLocalpart(index);
2871: if (localpart == fStringPool
2872: .addSymbol(SchemaSymbols.XSI_SCHEMALOCACTION)) {
2873: parseSchemaLocation(fStringPool
2874: .toString(attrList
2875: .getAttValue(index)));
2876: } else if (localpart == fStringPool
2877: .addSymbol(SchemaSymbols.XSI_NONAMESPACESCHEMALOCACTION)) {
2878: fLocationUriPairs.put(fStringPool
2879: .toString(attrList
2880: .getAttValue(index)),
2881: "");
2882:
2883: /***/
2884: // NOTE: This is the *wrong* solution to the problem
2885: // of finding the grammar associated to elements
2886: // when the grammar does *not* have a target
2887: // namespace!!! -Ac
2888: if (fNamespacesScope != null) {
2889: //bind prefix "" to URI "" in this case
2890: fNamespacesScope
2891: .setNamespaceForPrefix(
2892: fStringPool
2893: .addSymbol(""),
2894: fStringPool
2895: .addSymbol(""));
2896: }
2897: /***/
2898: } else if (localpart == fStringPool
2899: .addSymbol(SchemaSymbols.XSI_TYPE)) {
2900: fXsiTypeAttValue = attrList
2901: .getAttValue(index);
2902: } else if (localpart == fStringPool
2903: .addSymbol(SchemaSymbols.ATT_NIL)) {
2904: fNil = (fStringPool.toString(attrList
2905: .getAttValue(index))
2906: .equals("true")) ? true : false;
2907:
2908: }
2909: // REVISIT: should we break here?
2910: //break;
2911: }
2912: }
2913: index = attrList.getNextAttr(index);
2914: }
2915: parseSchemas();
2916: }
2917:
2918: }
2919:
2920: // bind element to URI
2921: int prefix = element.prefix != -1 ? element.prefix : 0;
2922: int uri = fNamespacesScope.getNamespaceForPrefix(prefix);
2923: if (element.prefix != -1 || uri != StringPool.EMPTY_STRING) {
2924: element.uri = uri;
2925: if (element.uri == StringPool.EMPTY_STRING) {
2926: Object[] args = { fStringPool.toString(element.prefix) };
2927: fErrorReporter.reportError(fErrorReporter.getLocator(),
2928: XMLMessages.XMLNS_DOMAIN,
2929: XMLMessages.MSG_PREFIX_DECLARED,
2930: XMLMessages.NC_PREFIX_DECLARED, args,
2931: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2932: }
2933: }
2934:
2935: if (fAttrListHandle != -1) {
2936: int index = attrList.getFirstAttr(fAttrListHandle);
2937: while (index != -1) {
2938: int attName = attrList.getAttrName(index);
2939: if (!fStringPool.equalNames(attName, fNamespacesPrefix)) {
2940: int attPrefix = attrList.getAttrPrefix(index);
2941: if (attPrefix != fNamespacesPrefix) {
2942: if (attPrefix != -1) {
2943: int attrUri = fNamespacesScope
2944: .getNamespaceForPrefix(attPrefix);
2945: if (attrUri == -1) {
2946: Object[] args = { fStringPool
2947: .toString(attPrefix) };
2948: fErrorReporter
2949: .reportError(
2950: fErrorReporter
2951: .getLocator(),
2952: XMLMessages.XMLNS_DOMAIN,
2953: XMLMessages.MSG_PREFIX_DECLARED,
2954: XMLMessages.NC_PREFIX_DECLARED,
2955: args,
2956: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2957: }
2958: attrList.setAttrURI(index, attrUri);
2959: }
2960: }
2961: }
2962: index = attrList.getNextAttr(index);
2963: }
2964: }
2965:
2966: } // bindNamespacesToElementAndAttributes(QName,XMLAttrList)
2967:
2968: private void parseSchemas() throws Exception {
2969:
2970: // try to resolve all the grammars here
2971: Enumeration locations = fLocationUriPairs.keys();
2972: String location = null;
2973: String uri = null;
2974: while (locations.hasMoreElements()) {
2975: location = (String) locations.nextElement();
2976: uri = (String) fLocationUriPairs.get(location);
2977: resolveSchemaGrammar(location, uri);
2978: }
2979: }
2980:
2981: private void parseSchemaLocation(String schemaLocationStr)
2982: throws Exception {
2983: StringTokenizer tokenizer = new StringTokenizer(
2984: schemaLocationStr, " \n\t\r", false);
2985: int tokenTotal = tokenizer.countTokens();
2986: if (tokenTotal % 2 != 0) {
2987: fErrorReporter.reportError(fErrorReporter.getLocator(),
2988: SchemaMessageProvider.SCHEMA_DOMAIN,
2989: SchemaMessageProvider.SchemaLocation,
2990: SchemaMessageProvider.MSG_NONE,
2991: new Object[] { schemaLocationStr },
2992: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2993:
2994: } else {
2995: String uri = null;
2996: String location = null;
2997: while (tokenizer.hasMoreTokens()) {
2998: uri = tokenizer.nextToken();
2999: location = tokenizer.nextToken();
3000: fLocationUriPairs.put(location, uri);
3001: }
3002: }
3003:
3004: }// parseSchemaLocation(String, Hashtable)
3005:
3006: private void resolveSchemaGrammar( String loc, String uri) throws Exception {
3007: Grammar grammar = null;
3008: if (uri!=null) {
3009: if (fGrammarIsDTDGrammar && uri.length()==0) {
3010: fErrorReporter.reportError(fErrorReporter.getLocator(),
3011: XMLMessages.XML_DOMAIN,
3012: XMLMessages.MSG_DTD_SCHEMA_ERROR,
3013: XMLMessages.MSG_DTD_SCHEMA_ERROR,
3014: null,
3015: fErrorReporter.ERRORTYPE_WARNING);
3016: } else {
3017: grammar = fGrammarResolver.getGrammar(uri);
3018: }
3019: }
3020:
3021: if (grammar == null) {
3022:
3023: if (fSchemaGrammarParser == null) {
3024: //
3025: // creating a parser for schema only once per parser instance
3026: // leads to less objects, but increases time we spend in reset()
3027: //
3028: fSchemaGrammarParser = new DOMParser();
3029: fSchemaGrammarParser.setEntityResolver( new Resolver(fEntityHandler) );
3030: fSchemaGrammarParser.setErrorHandler( new ErrorHandler() );
3031:
3032: try {
3033: fSchemaGrammarParser.setFeature("http://xml.org/sax/features/validation", false);
3034: fSchemaGrammarParser.setFeature("http://xml.org/sax/features/namespaces", true);
3035: fSchemaGrammarParser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
3036: } catch ( org.xml.sax.SAXNotRecognizedException e ) {
3037: e.printStackTrace();
3038: } catch ( org.xml.sax.SAXNotSupportedException e ) {
3039: e.printStackTrace();
3040: }
3041: }
3042: // expand it before passing it to the parser
3043: InputSource source = null;
3044: EntityResolver currentER = fSchemaGrammarParser.getEntityResolver();
3045: if (currentER != null) {
3046: source = currentER.resolveEntity("", loc);
3047: }
3048: if (source == null) {
3049: loc = fEntityHandler.expandSystemId(loc);
3050: source = new InputSource(loc);
3051: }
3052:
3053: try {
3054: fSchemaGrammarParser.parse( source );
3055: } catch ( IOException e ) {
3056: e.printStackTrace();
3057: } catch ( SAXException e ) {
3058: reportRecoverableXMLError( XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3059: XMLMessages.SCHEMA_GENERIC_ERROR, e.getMessage() );
3060: }
3061:
3062: Document document = fSchemaGrammarParser.getDocument(); //Our Grammar
3063:
3064: TraverseSchema tst = null;
3065: if (DEBUG_SCHEMA_VALIDATION) {
3066: System.out.println("I am geting the Schema Document");
3067: }
3068:
3069: Element root = null;
3070: if (document != null) {
3071: root = document.getDocumentElement();// This is what we pass to TraverserSchema
3072: }
3073: if (root == null) {
3074: reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR, XMLMessages.SCHEMA_GENERIC_ERROR, "Can't get back Schema document's root element :" + loc);
3075: } else {
3076: if (uri!=null && !uri.equals(root.getAttribute(SchemaSymbols.ATT_TARGETNAMESPACE)) ) {
3077: reportRecoverableXMLError(XMLMessages.MSG_GENERIC_SCHEMA_ERROR, XMLMessages.SCHEMA_GENERIC_ERROR, "Schema in " + loc + " has a different target namespace " +
3078: "from the one specified in the instance document :" + uri);
3079: }
3080:
3081: grammar = new SchemaGrammar();
3082: grammar.setGrammarDocument(document);
3083:
3084: // Since we've just constructed a schema grammar, we should make sure we know what we've done.
3085: fGrammarIsSchemaGrammar = true;
3086: fGrammarIsDTDGrammar = false;
3087:
3088: //At this point we should expand the registry table.
3089: // pass parser's entity resolver (local Resolver), which also has reference to user's
3090: // entity resolver, and also can fall-back to entityhandler's expandSystemId()
3091: GeneralAttrCheck generalAttrCheck = new GeneralAttrCheck(fErrorReporter, fDataTypeReg);
3092: tst = new TraverseSchema( root, fStringPool, (SchemaGrammar)grammar, fGrammarResolver, fErrorReporter, source.getSystemId(), currentER, getSchemaFullCheckingEnabled(), generalAttrCheck, fExternalSchemas, fExternalNoNamespaceSchema);
3093: generalAttrCheck.checkNonSchemaAttributes(fGrammarResolver);
3094:
3095: //allowing xsi:schemaLocation to appear on any element
3096:
3097: String targetNS = root.getAttribute("targetNamespace");
3098: fGrammarNameSpaceIndex = fStringPool.addSymbol(targetNS);
3099: fGrammarResolver.putGrammar(targetNS, grammar);
3100: fGrammar = (SchemaGrammar)grammar;
3101:
3102: // when in full checking, we need to do UPA stuff here
3103: // by constructing all content models
3104: if (fSchemaValidationFullChecking) {
3105: try {
3106: // get all grammar URIs
3107: Enumeration grammarURIs = fGrammarResolver.nameSpaceKeys();
3108: String grammarURI;
3109: Grammar gGrammar;
3110: SchemaGrammar sGrammar;
3111: // for each grammar
3112: while (grammarURIs.hasMoreElements()) {
3113: grammarURI = (String)grammarURIs.nextElement();
3114: // if we checked UPA on this grammar, just skip
3115: if (UPACheckedGrammarURIs.get(grammarURI) != null)
3116: continue;
3117: // otherwise, mark this one as checked
3118: UPACheckedGrammarURIs.put(grammarURI, fgNullObject);
3119: gGrammar = fGrammarResolver.getGrammar(grammarURI);
3120: if (!(gGrammar instanceof SchemaGrammar))
3121: continue;
3122: sGrammar = (SchemaGrammar)gGrammar;
3123:
3124: // get all registered complex type in this grammar
3125: Hashtable complexTypeRegistry = sGrammar.getComplexTypeRegistry();
3126: int count = complexTypeRegistry.size();
3127: Enumeration enum = complexTypeRegistry.elements();
3128:
3129: TraverseSchema.ComplexTypeInfo typeInfo;
3130: if (fSGComparator == null) {
3131: fSGComparator = new SubstitutionGroupComparator(fGrammarResolver, fStringPool, fErrorReporter);
3132: }
3133: while (enum.hasMoreElements ()) {
3134: typeInfo = (TraverseSchema.ComplexTypeInfo)enum.nextElement();
3135: // for each type, we construct a corresponding content model
3136: sGrammar.getContentModel(typeInfo.contentSpecHandle,
3137: typeInfo.contentType,
3138: fSGComparator);
3139: }
3140: }
3141: } catch (CMException excToCatch) {
3142: // REVISIT - Translate caught error to the protected error handler interface
3143: int majorCode = excToCatch.getErrorCode();
3144: fErrorReporter.reportError(fErrorReporter.getLocator(),
3145: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
3146: majorCode,
3147: 0,
3148: null,
3149: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
3150: }
3151: }
3152: }
3153: }
3154:
3155: }
3156:
3157: /*
3158: * for <notation> must resolve values "b:myNotation"
3159: *
3160: * @param value string value of element or attribute
3161: * @return
3162: * @exception Exception
3163: */
3164: private String bindNotationURI(String value) throws Exception {
3165: int colonP = value.indexOf(":");
3166: String prefix = "";
3167: String localpart = value;
3168: if (colonP > -1) {
3169: prefix = value.substring(0, colonP);
3170: localpart = value.substring(colonP + 1);
3171: }
3172:
3173: String uri = "";
3174: int uriIndex = StringPool.EMPTY_STRING;
3175: if (fNamespacesScope != null) {
3176: //if prefix.equals("") it would bing to xmlns URI
3177: uriIndex = fNamespacesScope
3178: .getNamespaceForPrefix(fStringPool
3179: .addSymbol(prefix));
3180: if (uriIndex > 0) {
3181: return fStringPool.toString(uriIndex) + ":" + localpart;
3182: } else if (fGrammarNameSpaceIndex != -1) {
3183: // REVISIT: try binding to current namespace
3184: // trying to solve the case:
3185: // <v01:root xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
3186: // xmlns:my ="http://www.schemaTest.org/my"
3187: // might not work in all cases (need clarification from schema?)
3188: return fStringPool.toString(fGrammarNameSpaceIndex)
3189: + ":" + localpart;
3190: }
3191:
3192: }
3193: return value;
3194: }
3195:
3196: static class Resolver implements EntityResolver {
3197:
3198: //
3199: // Constants
3200: //
3201:
3202: private static final String SYSTEM[] = {
3203: "http://www.w3.org/2001/XMLSchema.dtd",
3204: "http://www.w3.org/XMLSchema/datatypes.dtd",
3205: "http://www.w3.org/XMLSchema/versionInfo.ent", };
3206: private static final String PATH[] = { "structures.dtd",
3207: "datatypes.dtd", "versionInfo.ent", };
3208:
3209: //
3210: // Data
3211: //
3212:
3213: private DefaultEntityHandler fEntityHandler;
3214:
3215: //
3216: // Constructors
3217: //
3218:
3219: public Resolver(DefaultEntityHandler handler) {
3220: fEntityHandler = handler;
3221: }
3222:
3223: //
3224: // EntityResolver methods
3225: //
3226:
3227: public InputSource resolveEntity(String publicId,
3228: String systemId) throws IOException, SAXException {
3229:
3230: // looking for the schema DTDs?
3231: for (int i = 0; i < SYSTEM.length; i++) {
3232: if (systemId.equals(SYSTEM[i])) {
3233: InputSource source = new InputSource(getClass()
3234: .getResourceAsStream(PATH[i]));
3235: source.setPublicId(publicId);
3236: source.setSystemId(systemId);
3237: return source;
3238: }
3239: }
3240:
3241: // first try to resolve using user's entity resolver
3242: EntityResolver resolver = fEntityHandler
3243: .getEntityResolver();
3244: if (resolver != null) {
3245: InputSource source = resolver.resolveEntity(publicId,
3246: systemId);
3247: if (source != null) {
3248: return source;
3249: }
3250: }
3251:
3252: // use default resolution
3253: return new InputSource(fEntityHandler
3254: .expandSystemId(systemId));
3255:
3256: } // resolveEntity(String,String):InputSource
3257:
3258: } // class Resolver
3259:
3260: static class ErrorHandler implements org.xml.sax.ErrorHandler {
3261:
3262: /** Warning. */
3263: public void warning(SAXParseException ex) {
3264: System.err.println("[Warning] " + getLocationString(ex)
3265: + ": " + ex.getMessage());
3266: }
3267:
3268: /** Error. */
3269: public void error(SAXParseException ex) {
3270: System.err.println("[Error] " + getLocationString(ex)
3271: + ": " + ex.getMessage());
3272: }
3273:
3274: /** Fatal error. */
3275: public void fatalError(SAXParseException ex) {
3276: System.err.println("[Fatal Error] " + getLocationString(ex)
3277: + ": " + ex.getMessage());
3278: //throw ex;
3279: }
3280:
3281: //
3282: // Private methods
3283: //
3284:
3285: /** Returns a string of the location. */
3286: private String getLocationString(SAXParseException ex) {
3287: StringBuffer str = new StringBuffer();
3288:
3289: String systemId_ = ex.getSystemId();
3290: if (systemId_ != null) {
3291: int index = systemId_.lastIndexOf('/');
3292: if (index != -1)
3293: systemId_ = systemId_.substring(index + 1);
3294: str.append(systemId_);
3295: }
3296: str.append(':');
3297: str.append(ex.getLineNumber());
3298: str.append(':');
3299: str.append(ex.getColumnNumber());
3300:
3301: return str.toString();
3302:
3303: } // getLocationString(SAXParseException):String
3304: }
3305:
3306: private int attributeTypeName(XMLAttributeDecl attrDecl) {
3307: switch (attrDecl.type) {
3308: case XMLAttributeDecl.TYPE_ENTITY: {
3309: return attrDecl.list ? fENTITIESSymbol : fENTITYSymbol;
3310: }
3311: case XMLAttributeDecl.TYPE_ENUMERATION: {
3312: String enumeration = fStringPool
3313: .stringListAsString(attrDecl.enumeration);
3314: return fStringPool.addSymbol(enumeration);
3315: }
3316: case XMLAttributeDecl.TYPE_ID: {
3317: return fIDSymbol;
3318: }
3319: case XMLAttributeDecl.TYPE_IDREF: {
3320: return attrDecl.list ? fIDREFSSymbol : fIDREFSymbol;
3321: }
3322: case XMLAttributeDecl.TYPE_NMTOKEN: {
3323: return attrDecl.list ? fNMTOKENSSymbol : fNMTOKENSymbol;
3324: }
3325: case XMLAttributeDecl.TYPE_NOTATION: {
3326: return fNOTATIONSymbol;
3327: }
3328: }
3329: return fCDATASymbol;
3330: }
3331:
3332: /** Validates element and attributes. */
3333: private void validateElementAndAttributes(QName element,
3334: XMLAttrList attrList) throws Exception {
3335:
3336: if ((fGrammarIsSchemaGrammar && fElementDepth >= 0 && fValidationFlagStack[fElementDepth] != 0)
3337: || (fGrammar == null && !fValidating && !fNamespacesEnabled)) {
3338: fCurrentElementIndex = -1;
3339: fCurrentContentSpecType = -1;
3340: fInElementContent = false;
3341: if (fAttrListHandle != -1) {
3342: //fAttrList.endAttrList();
3343: int dupAttrs[];
3344: if ((dupAttrs = fAttrList.endAttrList()) != null) {
3345: Object[] args = {
3346: fStringPool.toString(element.rawname), null };
3347: for (int i = 0; i < dupAttrs.length; i++) {
3348: args[1] = fStringPool.toString(dupAttrs[i]);
3349: fErrorReporter
3350: .reportError(
3351: fErrorReporter.getLocator(),
3352: XMLMessages.XMLNS_DOMAIN,
3353: XMLMessages.MSG_ATTRIBUTE_NOT_UNIQUE,
3354: XMLMessages.WFC_UNIQUE_ATT_SPEC,
3355: args,
3356: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
3357: }
3358: }
3359: }
3360: return;
3361: }
3362:
3363: int elementIndex = -1;
3364: int contentSpecType = -1;
3365:
3366: boolean skipThisOne = false;
3367: boolean laxThisOne = false;
3368:
3369: if (fGrammarIsSchemaGrammar && fElementDepth > -1
3370: && fContentLeafStack[fElementDepth] != null) {
3371: ContentLeafNameTypeVector cv = fContentLeafStack[fElementDepth];
3372:
3373: //OTWI: on-the-way-in
3374: if (fContentModelStateStack[fElementDepth] >= 0) {
3375: // get the position of the current element in the content model
3376: int pos = ((DFAContentModel) fContentModelStack[fElementDepth])
3377: .oneTransition(element,
3378: fContentModelStateStack, fElementDepth);
3379: // if it's a valid child, increase succeful count
3380: // and check whether we need to lax or skip this one
3381: if (pos >= 0) {
3382: fContentModelEleCount[fElementDepth]++;
3383: switch (cv.leafTypes[pos]) {
3384: case XMLContentSpec.CONTENTSPECNODE_ANY_SKIP:
3385: case XMLContentSpec.CONTENTSPECNODE_ANY_NS_SKIP:
3386: case XMLContentSpec.CONTENTSPECNODE_ANY_OTHER_SKIP:
3387: skipThisOne = true;
3388: break;
3389: case XMLContentSpec.CONTENTSPECNODE_ANY_LAX:
3390: case XMLContentSpec.CONTENTSPECNODE_ANY_NS_LAX:
3391: case XMLContentSpec.CONTENTSPECNODE_ANY_OTHER_LAX:
3392: laxThisOne = true;
3393: break;
3394: }
3395: }
3396: }
3397: /*
3398: QName[] fElemMap = cv.leafNames;
3399: for (int i=0; i<cv.leafCount; i++) {
3400: int type = cv.leafTypes[i] ;
3401: //System.out.println("******* see a ANY_OTHER_SKIP, "+type+","+element+","+fElemMap[i]+"\n*******");
3402:
3403: if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
3404: if (fElemMap[i].uri==element.uri
3405: && fElemMap[i].localpart == element.localpart)
3406: break;
3407: } else if (type == XMLContentSpec.CONTENTSPECNODE_ANY) {
3408: break;
3409: } else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_NS) {
3410: if (element.uri == fElemMap[i].uri) {
3411: break;
3412: }
3413: } else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) {
3414: if (fElemMap[i].uri != element.uri) {
3415: break;
3416: }
3417: } else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_SKIP) {
3418: skipThisOne = true;
3419: break;
3420: } else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_NS_SKIP) {
3421: if (element.uri == fElemMap[i].uri) {
3422: skipThisOne = true;
3423: break;
3424: }
3425: } else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER_SKIP) {
3426: if (fElemMap[i].uri != element.uri) {
3427: skipThisOne = true;
3428: break;
3429: }
3430: } else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_LAX) {
3431: laxThisOne = true;
3432: break;
3433: } else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_NS_LAX) {
3434: if (element.uri == fElemMap[i].uri) {
3435: laxThisOne = true;
3436: break;
3437: }
3438: } else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER_LAX) {
3439: if (fElemMap[i].uri != element.uri) {
3440: laxThisOne = true;
3441: break;
3442: }
3443: }
3444:
3445: }
3446: */
3447: }
3448:
3449: if (skipThisOne) {
3450: fNeedValidationOff = true;
3451: } else {
3452: //REVISIT: is this the right place to check on if the Schema has changed?
3453: TraverseSchema.ComplexTypeInfo baseTypeInfo = null;
3454: if (fGrammarIsSchemaGrammar && fCurrentElementIndex != -1)
3455: baseTypeInfo = ((SchemaGrammar) fGrammar)
3456: .getElementComplexTypeInfo(fCurrentElementIndex);
3457:
3458: if (fNamespacesEnabled && fValidating
3459: && element.uri != fGrammarNameSpaceIndex
3460: && element.uri != StringPool.EMPTY_STRING) {
3461: fGrammarNameSpaceIndex = element.uri;
3462:
3463: boolean success = switchGrammar(fGrammarNameSpaceIndex);
3464:
3465: if (!success && !laxThisOne) {
3466: reportRecoverableXMLError(
3467: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3468: XMLMessages.SCHEMA_GENERIC_ERROR,
3469: "Grammar with uri: "
3470: + fStringPool
3471: .toString(fGrammarNameSpaceIndex)
3472: + " , can not be found; schema namespace may be wrong: Xerces supports schemas from the \"http://www.w3.org/2001/XMLSchema\" namespace"
3473: + " or the instance document's namespace may not match the targetNamespace of the schema");
3474: }
3475: }
3476:
3477: if (fGrammar != null) {
3478: if (DEBUG_SCHEMA_VALIDATION) {
3479: System.out.println("*******Lookup element: uri: "
3480: + fStringPool.toString(element.uri)
3481: + " localpart: '"
3482: + fStringPool.toString(element.localpart)
3483: + "' and scope : " + fCurrentScope + "\n");
3484: }
3485:
3486: elementIndex = fGrammar.getElementDeclIndex(element,
3487: fCurrentScope);
3488:
3489: if (elementIndex == -1) {
3490: elementIndex = fGrammar.getElementDeclIndex(
3491: element, TOP_LEVEL_SCOPE);
3492: }
3493:
3494: if (elementIndex == -1) {
3495: // if validating based on a Schema, try to resolve the element again by searching in its type's ancestor types
3496: if (fGrammarIsSchemaGrammar
3497: && fCurrentElementIndex != -1) {
3498: int aGrammarNSIndex = fGrammarNameSpaceIndex;
3499: while (baseTypeInfo != null) {
3500: String baseTName = baseTypeInfo.typeName;
3501: if (!baseTName.startsWith("#")) {
3502: int comma = baseTName.indexOf(',');
3503: aGrammarNSIndex = fStringPool
3504: .addSymbol(baseTName.substring(
3505: 0, comma).trim());
3506: if (aGrammarNSIndex != fGrammarNameSpaceIndex) {
3507: if (!switchGrammar(aGrammarNSIndex)) {
3508: break; //exit the loop in this case
3509: }
3510: fGrammarNameSpaceIndex = aGrammarNSIndex;
3511: }
3512: }
3513: elementIndex = fGrammar
3514: .getElementDeclIndex(element,
3515: baseTypeInfo.scopeDefined);
3516: if (elementIndex > -1) {
3517: //System.out.println("found element index for " + fStringPool.toString(element.localpart));
3518: // update the current Grammar NS index if resolving element succeed.
3519: break;
3520: }
3521: baseTypeInfo = baseTypeInfo.baseComplexTypeInfo;
3522: }
3523: // if *still* can't find it, try a grammar with no targetNamespace
3524: if (elementIndex == -1
3525: && element.uri == StringPool.EMPTY_STRING) {
3526: boolean success = switchGrammar(element.uri);
3527: if (success) {
3528: fGrammarNameSpaceIndex = element.uri;
3529: elementIndex = fGrammar
3530: .getElementDeclIndex(
3531: element.localpart,
3532: TOP_LEVEL_SCOPE);
3533: }
3534: }
3535: }
3536: //if still can't resolve it, try TOP_LEVEL_SCOPE AGAIN
3537: /****/
3538: if (element.uri == StringPool.EMPTY_STRING
3539: && elementIndex == -1
3540: && fNamespacesScope != null) {
3541: elementIndex = fGrammar.getElementDeclIndex(
3542: element.localpart, TOP_LEVEL_SCOPE);
3543: // REVISIT:
3544: // this is a hack to handle the situation where namespace prefix "" is bound to nothing, and there
3545: // is a "noNamespaceSchemaLocation" specified, and element
3546: element.uri = StringPool.EMPTY_STRING;
3547: }
3548: /****/
3549:
3550: /****/
3551: if (elementIndex == -1) {
3552: if (laxThisOne) {
3553: fNeedValidationOff = true;
3554: } else if (DEBUG_SCHEMA_VALIDATION)
3555: System.out
3556: .println("!!! can not find elementDecl in the grammar, "
3557: + " the element localpart: "
3558: + element.localpart
3559: + "["
3560: + fStringPool
3561: .toString(element.localpart)
3562: + "]"
3563: + " the element uri: "
3564: + element.uri
3565: + "["
3566: + fStringPool
3567: .toString(element.uri)
3568: + "]"
3569: + " and the current enclosing scope: "
3570: + fCurrentScope);
3571: }
3572: /****/
3573: }
3574:
3575: if (DEBUG_SCHEMA_VALIDATION) {
3576: fGrammar.getElementDecl(elementIndex,
3577: fTempElementDecl);
3578: System.out
3579: .println("elementIndex: "
3580: + elementIndex
3581: + " \n and itsName : '"
3582: + fStringPool
3583: .toString(fTempElementDecl.name.localpart)
3584: + "' \n its ContentType:"
3585: + fTempElementDecl.type
3586: + "\n its ContentSpecIndex : "
3587: + fTempElementDecl.contentSpecIndex
3588: + "\n"
3589: + " and the current enclosing scope: "
3590: + fCurrentScope);
3591: }
3592: }
3593:
3594: final int oldElementIndex = elementIndex;
3595:
3596: contentSpecType = getContentSpecType(elementIndex);
3597: int elementNameLocalPart = StringPool.NULL_STRING;
3598: DatatypeValidator elementDatatypeValidator = null;
3599:
3600: if (elementIndex != -1) {
3601: fGrammar.getElementDecl(elementIndex, fTempElementDecl);
3602: elementNameLocalPart = fTempElementDecl.name.localpart;
3603: elementDatatypeValidator = fTempElementDecl.datatypeValidator;
3604: }
3605:
3606: if (fGrammarIsSchemaGrammar) {
3607:
3608: // handle "xsi:type" right here
3609: if (fXsiTypeAttValue > -1) {
3610: String xsiType = fStringPool
3611: .toString(fXsiTypeAttValue);
3612: int colonP = xsiType.indexOf(":");
3613: String prefix = "";
3614: String localpart = xsiType;
3615: if (colonP > -1) {
3616: prefix = xsiType.substring(0, colonP);
3617: localpart = xsiType.substring(colonP + 1);
3618: }
3619:
3620: String uri = "";
3621: int uriIndex = StringPool.EMPTY_STRING;
3622: if (fNamespacesScope != null) {
3623: uriIndex = fNamespacesScope
3624: .getNamespaceForPrefix(fStringPool
3625: .addSymbol(prefix));
3626: if (uriIndex > 0) {
3627: uri = fStringPool.toString(uriIndex);
3628: if (uriIndex != fGrammarNameSpaceIndex) {
3629: fGrammarNameSpaceIndex = fCurrentSchemaURI = uriIndex;
3630: boolean success = switchGrammar(fCurrentSchemaURI);
3631: if (!success && !fNeedValidationOff) {
3632: // only report an error if the new namespace is not
3633: // the schema namespace
3634: if (!uri
3635: .equals(SchemaSymbols.URI_SCHEMAFORSCHEMA))
3636: reportRecoverableXMLError(
3637: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3638: XMLMessages.SCHEMA_GENERIC_ERROR,
3639: "Grammar with uri: "
3640: + fStringPool
3641: .toString(fCurrentSchemaURI)
3642: + " , can not be found");
3643: }
3644: }
3645: }
3646: }
3647:
3648: Hashtable complexRegistry = ((SchemaGrammar) fGrammar)
3649: .getComplexTypeRegistry();
3650: DatatypeValidatorFactoryImpl dataTypeReg = ((SchemaGrammar) fGrammar)
3651: .getDatatypeRegistry();
3652: if (complexRegistry == null || dataTypeReg == null) {
3653: reportRecoverableXMLError(
3654: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3655: XMLMessages.SCHEMA_GENERIC_ERROR,
3656: fErrorReporter.getLocator()
3657: .getSystemId()
3658: + " line"
3659: + fErrorReporter.getLocator()
3660: .getLineNumber()
3661: + ", canot resolve xsi:type = "
3662: + xsiType + " ---2");
3663: } else {
3664: TraverseSchema.ComplexTypeInfo typeInfo = (TraverseSchema.ComplexTypeInfo) complexRegistry
3665: .get(uri + "," + localpart);
3666:
3667: if (typeInfo == null) {
3668: if (uri
3669: .equals(SchemaSymbols.URI_SCHEMAFORSCHEMA)) {
3670: fXsiTypeValidator = dataTypeReg
3671: .getDatatypeValidator(localpart);
3672: } else
3673: fXsiTypeValidator = dataTypeReg
3674: .getDatatypeValidator(uri + ","
3675: + localpart);
3676: if (fXsiTypeValidator == null)
3677: reportRecoverableXMLError(
3678: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3679: XMLMessages.SCHEMA_GENERIC_ERROR,
3680: "unresolved type : "
3681: + uri
3682: + ","
3683: + localpart
3684: + " found in xsi:type handling");
3685: else if (elementIndex != -1) {
3686: // make sure the new type is related to the
3687: // type of the expected element
3688: DatatypeValidator ancestorValidator = elementDatatypeValidator;
3689: DatatypeValidator tempVal = fXsiTypeValidator;
3690: for (; tempVal != null; tempVal = tempVal
3691: .getBaseValidator())
3692: // WARNING!!! Comparison by reference.
3693: if (tempVal == ancestorValidator)
3694: break;
3695: if (tempVal == null) {
3696: // now if ancestorValidator is a union, then we must
3697: // look through its members to see whether we derive from any of them.
3698: if (ancestorValidator instanceof UnionDatatypeValidator) {
3699: // fXsiTypeValidator must derive from one of its members...
3700: Vector subUnionMemberDV = ((UnionDatatypeValidator) ancestorValidator)
3701: .getBaseValidators();
3702: int subUnionSize = subUnionMemberDV
3703: .size();
3704: boolean found = false;
3705: for (int i = 0; i < subUnionSize
3706: && !found; i++) {
3707: DatatypeValidator dTempSub = (DatatypeValidator) subUnionMemberDV
3708: .elementAt(i);
3709: DatatypeValidator dTemp = fXsiTypeValidator;
3710: for (; dTemp != null; dTemp = dTemp
3711: .getBaseValidator()) {
3712: // WARNING!!! This uses comparison by reference andTemp is thus inherently suspect!
3713: if (dTempSub == dTemp) {
3714: found = true;
3715: break;
3716: }
3717: }
3718: if (!found) {
3719: // if dTempSub is anySimpleType,
3720: // then the derivation is ok.
3721: if (dTempSub instanceof AnySimpleType) {
3722: found = true;
3723: }
3724: }
3725: }
3726: if (!found) {
3727: reportRecoverableXMLError(
3728: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3729: XMLMessages.SCHEMA_GENERIC_ERROR,
3730: "Type : "
3731: + uri
3732: + ","
3733: + localpart
3734: + " does not derive from the type of element "
3735: + fStringPool
3736: .toString(elementNameLocalPart));
3737: }
3738: } else if ((ancestorValidator == null && ((SchemaGrammar) fGrammar)
3739: .getElementComplexTypeInfo(elementIndex) == null)
3740: || (ancestorValidator instanceof AnySimpleType)) {
3741: // if ancestorValidator is anyType or anySimpleType,
3742: // then the derivation is ok.
3743: } else {
3744: reportRecoverableXMLError(
3745: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3746: XMLMessages.SCHEMA_GENERIC_ERROR,
3747: "Type : "
3748: + uri
3749: + ","
3750: + localpart
3751: + " does not derive from the type of element "
3752: + fStringPool
3753: .toString(elementNameLocalPart));
3754: }
3755: } else {
3756: // if we have an attribute but xsi:type's type is simple, we have a problem...
3757: if (tempVal != null
3758: && fXsiTypeValidator != null
3759: && (fGrammar
3760: .getFirstAttributeDeclIndex(elementIndex) != -1)) {
3761: reportRecoverableXMLError(
3762: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3763: XMLMessages.SCHEMA_GENERIC_ERROR,
3764: "Type : "
3765: + uri
3766: + ","
3767: + localpart
3768: + " does not derive from the type of element "
3769: + fStringPool
3770: .toString(elementNameLocalPart));
3771: }
3772: // check if element has block set
3773: if ((((SchemaGrammar) fGrammar)
3774: .getElementDeclBlockSet(elementIndex) & SchemaSymbols.RESTRICTION) != 0) {
3775: reportRecoverableXMLError(
3776: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3777: XMLMessages.SCHEMA_GENERIC_ERROR,
3778: "Element "
3779: + fStringPool
3780: .toString(elementNameLocalPart)
3781: + "does not permit substitution by a type such as "
3782: + uri + ","
3783: + localpart);
3784: }
3785: }
3786: }
3787: } else {
3788:
3789: //
3790: // The type must not be abstract
3791: //
3792: if (typeInfo.isAbstractType()) {
3793: reportRecoverableXMLError(
3794: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3795: XMLMessages.SCHEMA_GENERIC_ERROR,
3796: "Abstract type "
3797: + xsiType
3798: + " should not be used in xsi:type");
3799: }
3800: if (elementIndex != -1) {
3801: // now we look at whether there is a type
3802: // relation and whether the type (and element) allow themselves to be substituted for.
3803:
3804: TraverseSchema.ComplexTypeInfo tempType = typeInfo;
3805: TraverseSchema.ComplexTypeInfo destType = ((SchemaGrammar) fGrammar)
3806: .getElementComplexTypeInfo(elementIndex);
3807: for (; tempType != null
3808: && destType != null; tempType = tempType.baseComplexTypeInfo) {
3809: if (tempType.typeName
3810: .equals(destType.typeName))
3811: break;
3812: }
3813: if (tempType == null) {
3814: reportRecoverableXMLError(
3815: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3816: XMLMessages.SCHEMA_GENERIC_ERROR,
3817: "Type : "
3818: + uri
3819: + ","
3820: + localpart
3821: + " does not derive from the type "
3822: + destType.typeName);
3823: } else if (destType == null
3824: && elementDatatypeValidator != null) {
3825: // if the original type is a simple type, check derivation ok.
3826: DatatypeValidator ancestorValidator = elementDatatypeValidator;
3827: DatatypeValidator tempVal = fXsiTypeValidator;
3828: for (; tempVal != null; tempVal = tempVal
3829: .getBaseValidator())
3830: // WARNING!!! Comparison by reference.
3831: if (tempVal == ancestorValidator)
3832: break;
3833: if (tempVal == null) {
3834: // if ancestorValidator is anyType or anySimpleType,
3835: // then the derivation is ok.
3836: if (ancestorValidator instanceof AnySimpleType) {
3837: tempVal = fXsiTypeValidator;
3838: }
3839: }
3840: if (tempVal == null) {
3841: // now if ancestorValidator is a union, then we must
3842: // look through its members to see whether we derive from any of them.
3843: if (ancestorValidator instanceof UnionDatatypeValidator) {
3844: // fXsiTypeValidator must derive from one of its members...
3845: Vector subUnionMemberDV = ((UnionDatatypeValidator) ancestorValidator)
3846: .getBaseValidators();
3847: int subUnionSize = subUnionMemberDV
3848: .size();
3849: boolean found = false;
3850: for (int i = 0; i < subUnionSize
3851: && !found; i++) {
3852: DatatypeValidator dTempSub = (DatatypeValidator) subUnionMemberDV
3853: .elementAt(i);
3854: DatatypeValidator dTemp = fXsiTypeValidator;
3855: for (; dTemp != null; dTemp = dTemp
3856: .getBaseValidator()) {
3857: // WARNING!!! This uses comparison by reference andTemp is thus inherently suspect!
3858: if (dTempSub == dTemp) {
3859: found = true;
3860: break;
3861: }
3862: }
3863: if (!found) {
3864: // if dTempSub is anySimpleType,
3865: // then the derivation is ok.
3866: if (dTempSub instanceof AnySimpleType) {
3867: found = true;
3868: }
3869: }
3870: }
3871: if (!found) {
3872: reportRecoverableXMLError(
3873: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3874: XMLMessages.SCHEMA_GENERIC_ERROR,
3875: "Type : "
3876: + uri
3877: + ","
3878: + localpart
3879: + " does not derive from the type of element "
3880: + fStringPool
3881: .toString(elementNameLocalPart));
3882: }
3883: } else {
3884: reportRecoverableXMLError(
3885: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3886: XMLMessages.SCHEMA_GENERIC_ERROR,
3887: "Type : "
3888: + uri
3889: + ","
3890: + localpart
3891: + " does not derive from the type of element "
3892: + fStringPool
3893: .toString(elementNameLocalPart));
3894: }
3895: }
3896: } else if (typeInfo != destType) { // now check whether the element or typeInfo's baseType blocks us.
3897: int derivationMethod = typeInfo.derivedBy;
3898: if ((((SchemaGrammar) fGrammar)
3899: .getElementDeclBlockSet(elementIndex) & derivationMethod) != 0) {
3900: reportRecoverableXMLError(
3901: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3902: XMLMessages.SCHEMA_GENERIC_ERROR,
3903: "Element "
3904: + fStringPool
3905: .toString(elementNameLocalPart)
3906: + " does not permit xsi:type substitution in the manner required by type "
3907: + uri + ","
3908: + localpart);
3909: } else if (typeInfo.baseComplexTypeInfo != null
3910: && (typeInfo.baseComplexTypeInfo.blockSet & derivationMethod) != 0) {
3911: reportRecoverableXMLError(
3912: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3913: XMLMessages.SCHEMA_GENERIC_ERROR,
3914: "Type "
3915: + typeInfo.baseComplexTypeInfo.typeName
3916: + " does not permit other types, such as "
3917: + uri
3918: + ","
3919: + localpart
3920: + " to be substituted for itself using xsi:type");
3921: }
3922: }
3923: }
3924: elementIndex = typeInfo.templateElementIndex;
3925: }
3926: }
3927:
3928: fXsiTypeAttValue = -1;
3929: }
3930:
3931: else if (elementIndex != -1) {
3932: //
3933: // xsi:type was not specified...
3934: // If the corresponding type is abstract, detect an error
3935: //
3936: TraverseSchema.ComplexTypeInfo typeInfo = ((SchemaGrammar) fGrammar)
3937: .getElementComplexTypeInfo(elementIndex);
3938:
3939: if (typeInfo != null && typeInfo.isAbstractType()) {
3940: reportRecoverableXMLError(
3941: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3942: XMLMessages.SCHEMA_GENERIC_ERROR,
3943: "Element "
3944: + fStringPool
3945: .toString(element.rawname)
3946: + " is declared with a type that is abstract. Use xsi:type to specify a non-abstract type");
3947: }
3948: }
3949:
3950: if (elementIndex != -1) {
3951: //
3952: // Check whether this element is abstract. If so, an error
3953: //
3954: int miscFlags = ((SchemaGrammar) fGrammar)
3955: .getElementDeclMiscFlags(elementIndex);
3956: if ((miscFlags & SchemaSymbols.ABSTRACT) != 0) {
3957: reportRecoverableXMLError(
3958: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3959: XMLMessages.SCHEMA_GENERIC_ERROR,
3960: "A member of abstract element "
3961: + fStringPool
3962: .toString(element.rawname)
3963: + "'s substitution group must be specified");
3964: }
3965: if (fNil
3966: && (miscFlags & SchemaSymbols.NILLABLE) == 0) {
3967: fNil = false;
3968: reportRecoverableXMLError(
3969: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
3970: XMLMessages.SCHEMA_GENERIC_ERROR,
3971: "xsi:nil must not be specified for the element "
3972: + fStringPool
3973: .toString(element.rawname)
3974: + " with {nillable} equals 'false'");
3975: }
3976: //Change the current scope to be the one defined by this element.
3977: fCurrentScope = ((SchemaGrammar) fGrammar)
3978: .getElementDefinedScope(elementIndex);
3979:
3980: // here need to check if we need to switch Grammar by asking SchemaGrammar whether
3981: // this element actually is of a type in another Schema.
3982: String anotherSchemaURI = ((SchemaGrammar) fGrammar)
3983: .getElementFromAnotherSchemaURI(elementIndex);
3984: if (anotherSchemaURI != null) {
3985: //before switch Grammar, set the elementIndex to be the template elementIndex of its type
3986: if (contentSpecType != -1) {
3987: TraverseSchema.ComplexTypeInfo typeInfo = ((SchemaGrammar) fGrammar)
3988: .getElementComplexTypeInfo(elementIndex);
3989: if (typeInfo != null) {
3990: elementIndex = typeInfo.templateElementIndex;
3991: }
3992:
3993: // now switch the grammar
3994: fGrammarNameSpaceIndex = fCurrentSchemaURI = fStringPool
3995: .addSymbol(anotherSchemaURI);
3996: boolean success = switchGrammar(fCurrentSchemaURI);
3997: if (!success && !fNeedValidationOff) {
3998: reportRecoverableXMLError(
3999: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
4000: XMLMessages.SCHEMA_GENERIC_ERROR,
4001: "Grammar with uri: "
4002: + fStringPool
4003: .toString(fCurrentSchemaURI)
4004: + " , can not be found");
4005: }
4006: }
4007: }
4008:
4009: }
4010: }
4011: // If the elementIndex changed since last time
4012: // we queried the content type, query it again.
4013: if (elementIndex != oldElementIndex)
4014: contentSpecType = getContentSpecType(elementIndex);
4015:
4016: if (contentSpecType == -1 && fValidating
4017: && !fNeedValidationOff) {
4018: reportRecoverableXMLError(
4019: XMLMessages.MSG_ELEMENT_NOT_DECLARED,
4020: XMLMessages.VC_ELEMENT_VALID, element.rawname);
4021: }
4022: if (fGrammar != null && fGrammarIsSchemaGrammar
4023: && elementIndex != -1) {
4024: fAttrListHandle = addDefaultAttributes(elementIndex,
4025: attrList, fAttrListHandle, fValidating,
4026: fStandaloneReader != -1);
4027: }
4028: if (fAttrListHandle != -1) {
4029: //fAttrList.endAttrList();
4030: int dupAttrs[];
4031: if ((dupAttrs = fAttrList.endAttrList()) != null) {
4032: Object[] args = {
4033: fStringPool.toString(element.rawname), null };
4034: for (int i = 0; i < dupAttrs.length; i++) {
4035: args[1] = fStringPool.toString(dupAttrs[i]);
4036: fErrorReporter
4037: .reportError(
4038: fErrorReporter.getLocator(),
4039: XMLMessages.XMLNS_DOMAIN,
4040: XMLMessages.MSG_ATTRIBUTE_NOT_UNIQUE,
4041: XMLMessages.WFC_UNIQUE_ATT_SPEC,
4042: args,
4043: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4044: }
4045: }
4046: }
4047:
4048: if (DEBUG_PRINT_ATTRIBUTES) {
4049: String elementStr = fStringPool
4050: .toString(element.rawname);
4051: System.out.print("startElement: <" + elementStr);
4052: if (fAttrListHandle != -1) {
4053: int index = attrList.getFirstAttr(fAttrListHandle);
4054: while (index != -1) {
4055: System.out.print(" "
4056: + fStringPool.toString(attrList
4057: .getAttrName(index))
4058: + "=\""
4059: + fStringPool.toString(attrList
4060: .getAttValue(index)) + "\"");
4061: index = attrList.getNextAttr(index);
4062: }
4063: }
4064: System.out.println(">");
4065: }
4066: if (fAttrListHandle != -1 && !fNeedValidationOff) {
4067: int index = fAttrList.getFirstAttr(fAttrListHandle);
4068: while (index != -1) {
4069: int attrNameIndex = attrList.getAttrName(index);
4070:
4071: // here, we validate every "user-defined" attributes
4072: int _xmlns = fStringPool.addSymbol("xmlns");
4073:
4074: if (attrNameIndex != _xmlns
4075: && attrList.getAttrPrefix(index) != _xmlns)
4076: if (fGrammar != null) {
4077: fTempQName.setValues(attrList
4078: .getAttrPrefix(index), attrList
4079: .getAttrLocalpart(index), attrList
4080: .getAttrName(index), attrList
4081: .getAttrURI(index));
4082: int attDefIndex = getAttDefByElementIndex(
4083: elementIndex, fTempQName);
4084:
4085: if (fTempQName.uri != fXsiURI)
4086: if (attDefIndex == -1) {
4087: if (fValidating) {
4088: // REVISIT - cache the elem/attr tuple so that we only give
4089: // this error once for each unique occurrence
4090: Object[] args = {
4091: fStringPool
4092: .toString(element.rawname),
4093: fStringPool
4094: .toString(attrList
4095: .getAttrName(index)) };
4096:
4097: /*****/
4098: fAttrNameLocator = getLocatorImpl(fAttrNameLocator);
4099:
4100: fErrorReporter
4101: .reportError(
4102: fAttrNameLocator,
4103: XMLMessages.XML_DOMAIN,
4104: XMLMessages.MSG_ATTRIBUTE_NOT_DECLARED,
4105: XMLMessages.VC_ATTRIBUTE_VALUE_TYPE,
4106: args,
4107: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4108: /******/
4109: }
4110: } else {
4111:
4112: fGrammar.getAttributeDecl(
4113: attDefIndex, fTempAttDecl);
4114:
4115: int attributeType = attributeTypeName(fTempAttDecl);
4116: attrList.setAttType(index,
4117: attributeType);
4118:
4119: if (fGrammarIsDTDGrammar) {
4120: int normalizedValue = validateDTDattribute(
4121: element,
4122: attrList
4123: .getAttValue(index),
4124: fTempAttDecl);
4125: attrList.setAttValue(index,
4126: normalizedValue);
4127:
4128: }
4129: if (fValidating) {
4130: // check to see if this attribute matched an attribute wildcard
4131: if (fGrammarIsDTDGrammar) {
4132: //do nothing
4133: } else if (fGrammarIsSchemaGrammar
4134: && (fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_ANY
4135: || fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_LIST || fTempAttDecl.type == XMLAttributeDecl.TYPE_ANY_OTHER)) {
4136:
4137: if ((fTempAttDecl.defaultType & XMLAttributeDecl.PROCESSCONTENTS_SKIP) > 0) {
4138: // attribute should just be bypassed,
4139: } else if ((fTempAttDecl.defaultType & XMLAttributeDecl.PROCESSCONTENTS_STRICT) > 0
4140: || (fTempAttDecl.defaultType & XMLAttributeDecl.PROCESSCONTENTS_LAX) > 0) {
4141:
4142: boolean reportError = false;
4143: boolean processContentStrict = (fTempAttDecl.defaultType & XMLAttributeDecl.PROCESSCONTENTS_STRICT) > 0;
4144:
4145: // ??? REVISIT: can't tell whether it's a local attribute
4146: // or a global one with empty namespace
4147: //if (fTempQName.uri == StringPool.EMPTY_STRING) {
4148: // if (processContentStrict) {
4149: // reportError = true;
4150: // }
4151: //} else {
4152: {
4153: Grammar aGrammar = fGrammarResolver
4154: .getGrammar(fStringPool
4155: .toString(fTempQName.uri));
4156:
4157: if (aGrammar == null
4158: || !(aGrammar instanceof SchemaGrammar)) {
4159: if (processContentStrict) {
4160: reportError = true;
4161: }
4162: } else {
4163: SchemaGrammar sGrammar = (SchemaGrammar) aGrammar;
4164: Hashtable attRegistry = sGrammar
4165: .getAttributeDeclRegistry();
4166: if (attRegistry == null) {
4167: if (processContentStrict) {
4168: reportError = true;
4169: }
4170: } else {
4171: XMLAttributeDecl attDecl = (XMLAttributeDecl) attRegistry
4172: .get(fStringPool
4173: .toString(fTempQName.localpart));
4174: if (attDecl == null) {
4175: if (processContentStrict) {
4176: reportError = true;
4177: }
4178: } else {
4179: DatatypeValidator attDV = attDecl.datatypeValidator;
4180: if (attDV == null) {
4181: if (processContentStrict) {
4182: reportError = true;
4183: }
4184: } else {
4185: try {
4186: String value = fStringPool
4187: .toString(attrList
4188: .getAttValue(index));
4189: fWhiteSpace = attDV
4190: .getWSFacet();
4191: if (fWhiteSpace != DatatypeValidator.PRESERVE) {
4192: value = normalizeValue(value);
4193: }
4194: validateUsingDV(
4195: attDV,
4196: value,
4197: false);
4198: if (fNormalizeContents) {
4199: int normalizedValue = fStringPool
4200: .addString(value);
4201: attrList
4202: .setAttValue(
4203: index,
4204: normalizedValue);
4205: }
4206: } catch (InvalidDatatypeValueException idve) {
4207: fErrorReporter
4208: .reportError(
4209: fErrorReporter
4210: .getLocator(),
4211: SchemaMessageProvider.SCHEMA_DOMAIN,
4212: SchemaMessageProvider.DatatypeError,
4213: SchemaMessageProvider.MSG_NONE,
4214: new Object[] { idve
4215: .getMessage() },
4216: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4217: }
4218: }
4219: }
4220: }
4221: }
4222: }
4223: if (reportError) {
4224: Object[] args = {
4225: fStringPool
4226: .toString(element.rawname),
4227: "ANY---"
4228: + fStringPool
4229: .toString(attrList
4230: .getAttrName(index)) };
4231:
4232: fAttrNameLocator = getLocatorImpl(fAttrNameLocator);
4233:
4234: fErrorReporter
4235: .reportError(
4236: fAttrNameLocator,
4237: XMLMessages.XML_DOMAIN,
4238: XMLMessages.MSG_ATTRIBUTE_NOT_DECLARED,
4239: XMLMessages.VC_ATTRIBUTE_VALUE_TYPE,
4240: args,
4241: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4242:
4243: }
4244: }
4245: } else if (fTempAttDecl.datatypeValidator == null) {
4246: Object[] args = {
4247: fStringPool
4248: .toString(element.rawname),
4249: fStringPool
4250: .toString(attrList
4251: .getAttrName(index)) };
4252:
4253: System.out
4254: .println("[Error] Datatypevalidator for attribute "
4255: + fStringPool
4256: .toString(attrList
4257: .getAttrName(index))
4258: + " not found in element type "
4259: + fStringPool
4260: .toString(element.rawname));
4261: /****/
4262: fAttrNameLocator = getLocatorImpl(fAttrNameLocator);
4263:
4264: fErrorReporter
4265: .reportError(
4266: fAttrNameLocator,
4267: XMLMessages.XML_DOMAIN,
4268: XMLMessages.MSG_ATTRIBUTE_NOT_DECLARED,
4269: XMLMessages.VC_ATTRIBUTE_VALUE_TYPE,
4270: args,
4271: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4272: /****/
4273: } else {
4274: try {
4275: String value = fStringPool
4276: .toString(attrList
4277: .getAttValue(index));
4278: DatatypeValidator tempDV = fTempAttDecl.datatypeValidator;
4279: fWhiteSpace = tempDV
4280: .getWSFacet();
4281: if (fWhiteSpace != DatatypeValidator.PRESERVE) {
4282: value = normalizeValue(value);
4283: }
4284: // if "fixed" is specified, then get the fixed string,
4285: // and compare over value space
4286: if ((fTempAttDecl.defaultType & XMLAttributeDecl.DEFAULT_TYPE_FIXED) > 0
4287: && tempDV
4288: .compare(
4289: value,
4290: fTempAttDecl.defaultValue) != 0) {
4291: Object[] args = {
4292: fStringPool
4293: .toString(element.rawname),
4294: fStringPool
4295: .toString(attrList
4296: .getAttrName(index)),
4297: value,
4298: fTempAttDecl.defaultValue };
4299: fErrorReporter
4300: .reportError(
4301: fErrorReporter
4302: .getLocator(),
4303: XMLMessages.XML_DOMAIN,
4304: XMLMessages.MSG_FIXED_ATTVALUE_INVALID,
4305: XMLMessages.VC_FIXED_ATTRIBUTE_DEFAULT,
4306: args,
4307: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4308: }
4309: validateUsingDV(tempDV,
4310: value, false);
4311: if (fNormalizeContents) {
4312: int normalizedValue = fStringPool
4313: .addString(value);
4314: attrList
4315: .setAttValue(
4316: index,
4317: normalizedValue);
4318: }
4319: } catch (InvalidDatatypeValueException idve) {
4320: fErrorReporter
4321: .reportError(
4322: fErrorReporter
4323: .getLocator(),
4324: SchemaMessageProvider.SCHEMA_DOMAIN,
4325: SchemaMessageProvider.DatatypeError,
4326: SchemaMessageProvider.MSG_NONE,
4327: new Object[] { idve
4328: .getMessage() },
4329: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4330: }
4331: }
4332: } // end of if (fValidating)
4333:
4334: } // end of if (attDefIndex == -1) else
4335:
4336: }// end of if (fGrammar != null)
4337: index = fAttrList.getNextAttr(index);
4338: }
4339: }
4340: }
4341: if (fAttrListHandle != -1) {
4342: int index = attrList.getFirstAttr(fAttrListHandle);
4343: while (index != -1) {
4344: int attName = attrList.getAttrName(index);
4345: if (!fStringPool.equalNames(attName, fNamespacesPrefix)) {
4346: int attPrefix = attrList.getAttrPrefix(index);
4347: if (attPrefix != fNamespacesPrefix) {
4348: if (attPrefix != -1) {
4349: int uri = fNamespacesScope
4350: .getNamespaceForPrefix(attPrefix);
4351: if (uri == StringPool.EMPTY_STRING) {
4352: Object[] args = { fStringPool
4353: .toString(attPrefix) };
4354: fErrorReporter
4355: .reportError(
4356: fErrorReporter
4357: .getLocator(),
4358: XMLMessages.XMLNS_DOMAIN,
4359: XMLMessages.MSG_PREFIX_DECLARED,
4360: XMLMessages.NC_PREFIX_DECLARED,
4361: args,
4362: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4363: }
4364: attrList.setAttrURI(index, uri);
4365: }
4366: }
4367: }
4368: index = attrList.getNextAttr(index);
4369: }
4370: }
4371:
4372: fCurrentElementIndex = elementIndex;
4373: fCurrentContentSpecType = contentSpecType;
4374:
4375: if (fValidating
4376: && contentSpecType == XMLElementDecl.TYPE_SIMPLE) {
4377: fBufferDatatype = true;
4378: fDatatypeBuffer.setLength(0);
4379: }
4380:
4381: fInElementContent = (contentSpecType == XMLElementDecl.TYPE_CHILDREN);
4382:
4383: } // validateElementAndAttributes(QName,XMLAttrList)
4384:
4385: /**
4386: * Validate attributes in DTD fashion.
4387: * Validation is separated from attribute value normalization (which is required
4388: * for non-validating parsers)
4389: * @return normalized attribute value
4390: */
4391: private int validateDTDattribute(QName element, int attValue,
4392: XMLAttributeDecl attributeDecl) throws Exception {
4393: AttributeValidator av = null;
4394: switch (attributeDecl.type) {
4395: case XMLAttributeDecl.TYPE_ENTITY: {
4396: boolean isAlistAttribute = attributeDecl.list;//Caveat - Save this information because invalidStandaloneAttDef
4397: String unTrimValue = fStringPool.toString(attValue);
4398: String value = unTrimValue.trim();
4399: if (fValidationEnabled) {
4400: if (value != unTrimValue) {
4401: if (invalidStandaloneAttDef(element,
4402: attributeDecl.name)) {
4403: reportRecoverableXMLError(
4404: XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
4405: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
4406: fStringPool
4407: .toString(attributeDecl.name.rawname),
4408: unTrimValue, value);
4409: }
4410: }
4411: try {
4412: if (isAlistAttribute) {
4413: fValENTITIES.validate(value, fValidateEntity);
4414: } else {
4415: fValENTITY.validate(value, fValidateEntity);
4416: }
4417: } catch (InvalidDatatypeValueException ex) {
4418: if (ex.getMajorCode() != 1
4419: && ex.getMinorCode() != -1) {
4420: reportRecoverableXMLError(ex.getMajorCode(), ex
4421: .getMinorCode(), fStringPool
4422: .toString(attributeDecl.name.rawname),
4423: value);
4424: } else {
4425: reportRecoverableXMLError(
4426: XMLMessages.MSG_ENTITY_INVALID,
4427: XMLMessages.VC_ENTITY_NAME,
4428: fStringPool
4429: .toString(attributeDecl.name.rawname),
4430: value);
4431: }
4432: }
4433: }
4434: if (fNormalizeAttributeValues) {
4435: if (attributeDecl.list) {
4436: attValue = normalizeListAttribute(value, attValue,
4437: unTrimValue);
4438: } else {
4439: if (value != unTrimValue) {
4440: attValue = fStringPool.addSymbol(value);
4441: }
4442: }
4443: }
4444: }
4445: break;
4446: case XMLAttributeDecl.TYPE_ENUMERATION:
4447: av = fAttValidatorENUMERATION;
4448: break;
4449: case XMLAttributeDecl.TYPE_ID: {
4450: String unTrimValue = fStringPool.toString(attValue);
4451: String value = unTrimValue.trim();
4452: if (fValidationEnabled) {
4453: if (value != unTrimValue) {
4454: if (invalidStandaloneAttDef(element,
4455: attributeDecl.name)) {
4456: reportRecoverableXMLError(
4457: XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
4458: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
4459: fStringPool
4460: .toString(attributeDecl.name.rawname),
4461: unTrimValue, value);
4462: }
4463: }
4464:
4465: try {
4466: fValID.validate(value, fIdDefs);
4467: fValIDRef.validate(value, this .fValidateIDRef); //just in case we called id after IDREF
4468: } catch (InvalidDatatypeValueException ex) {
4469: int major = ex.getMajorCode(), minor = ex
4470: .getMinorCode();
4471: if (major == -1) {
4472: major = XMLMessages.MSG_ID_INVALID;
4473: minor = XMLMessages.VC_ID;
4474: }
4475: reportRecoverableXMLError(major, minor, fStringPool
4476: .toString(attributeDecl.name.rawname),
4477: value);
4478: }
4479: }
4480:
4481: if (fNormalizeAttributeValues && value != unTrimValue) {
4482: attValue = fStringPool.addSymbol(value);
4483: }
4484: }
4485: break;
4486: case XMLAttributeDecl.TYPE_IDREF: {
4487: String unTrimValue = fStringPool.toString(attValue);
4488: String value = unTrimValue.trim();
4489: boolean isAlistAttribute = attributeDecl.list;//Caveat - Save this information because invalidStandaloneAttDef
4490: //changes fTempAttDef
4491: if (fValidationEnabled) {
4492: if (value != unTrimValue) {
4493: if (invalidStandaloneAttDef(element,
4494: attributeDecl.name)) {
4495: reportRecoverableXMLError(
4496: XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
4497: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
4498: fStringPool
4499: .toString(attributeDecl.name.rawname),
4500: unTrimValue, value);
4501: }
4502: }
4503:
4504: if (attributeDecl.list && value.length() == 0) {
4505: reportRecoverableXMLError(
4506: XMLMessages.MSG_IDREFS_INVALID,
4507: XMLMessages.VC_IDREF,
4508: fStringPool
4509: .toString(attributeDecl.name.rawname));
4510: }
4511:
4512: try {
4513: if (isAlistAttribute) {
4514: fValIDRefs.validate(value, this .fValidateIDRef);
4515: } else {
4516: fValIDRef.validate(value, this .fValidateIDRef);
4517: }
4518: } catch (InvalidDatatypeValueException ex) {
4519: if (ex.getMajorCode() != 1
4520: && ex.getMinorCode() != -1) {
4521: reportRecoverableXMLError(ex.getMajorCode(), ex
4522: .getMinorCode(), fStringPool
4523: .toString(attributeDecl.name.rawname),
4524: value);
4525: } else {
4526: reportRecoverableXMLError(
4527: XMLMessages.MSG_IDREFS_INVALID,
4528: XMLMessages.VC_IDREF,
4529: fStringPool
4530: .toString(attributeDecl.name.rawname),
4531: value);
4532: }
4533: }
4534: }
4535: if (fNormalizeAttributeValues) {
4536: if (attributeDecl.list) {
4537: attValue = normalizeListAttribute(value, attValue,
4538: unTrimValue);
4539: } else {
4540: if (value != unTrimValue) {
4541: attValue = fStringPool.addSymbol(value);
4542: }
4543: }
4544: }
4545: }
4546: break;
4547: case XMLAttributeDecl.TYPE_NOTATION: {
4548: /* WIP
4549: String unTrimValue = fStringPool.toString(attValue);
4550: String value = unTrimValue.trim();
4551: if (fValidationEnabled) {
4552: if (value != unTrimValue) {
4553: if (invalidStandaloneAttDef(element, attributeDecl.name)) {
4554: reportRecoverableXMLError(XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
4555: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
4556: fStringPool.toString(attributeDecl.name.rawname), unTrimValue, value);
4557: }
4558: }
4559: }
4560: }
4561: */
4562: av = fAttValidatorNOTATION;
4563: }
4564: break;
4565: case XMLAttributeDecl.TYPE_NMTOKEN: {
4566: String unTrimValue = fStringPool.toString(attValue);
4567: String value = unTrimValue.trim();
4568: boolean isAlistAttribute = attributeDecl.list;//Caveat - Save this information because invalidStandaloneAttDef
4569: //changes fTempAttDef
4570: if (fValidationEnabled) {
4571: if (value != unTrimValue) {
4572: if (invalidStandaloneAttDef(element,
4573: attributeDecl.name)) {
4574: reportRecoverableXMLError(
4575: XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
4576: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
4577: fStringPool
4578: .toString(attributeDecl.name.rawname),
4579: unTrimValue, value);
4580: }
4581: }
4582: if (attributeDecl.list && value.length() == 0) {
4583: reportRecoverableXMLError(
4584: XMLMessages.MSG_NMTOKENS_INVALID,
4585: XMLMessages.VC_NAME_TOKEN,
4586: fStringPool
4587: .toString(attributeDecl.name.rawname));
4588: }
4589:
4590: try {
4591: if (isAlistAttribute) {
4592: fValNMTOKENS.validate(value, null);
4593: } else {
4594: fValNMTOKEN.validate(value, null);
4595: }
4596: } catch (InvalidDatatypeValueException ex) {
4597: reportRecoverableXMLError(
4598: XMLMessages.MSG_NMTOKEN_INVALID,
4599: XMLMessages.VC_NAME_TOKEN,
4600: fStringPool
4601: .toString(attributeDecl.name.rawname),
4602: value);//TODO NMTOKENS messge
4603: }
4604: }
4605: if (fNormalizeAttributeValues) {
4606: if (attributeDecl.list) {
4607: attValue = normalizeListAttribute(value, attValue,
4608: unTrimValue);
4609: } else {
4610: if (value != unTrimValue) {
4611: attValue = fStringPool.addSymbol(value);
4612: }
4613: }
4614: }
4615: }
4616: break;
4617: }
4618: if (av != null) {
4619: int newValue = av.normalize(element, attributeDecl.name,
4620: attValue, attributeDecl.type,
4621: attributeDecl.enumeration);
4622: if (fNormalizeAttributeValues)
4623: attValue = newValue;
4624: }
4625: return attValue;
4626: }
4627:
4628: /**
4629: * @param value This is already trimmed.
4630: */
4631: private int normalizeListAttribute(String value, int origIndex,
4632: String unTrimValue) {
4633:
4634: //REVISIT: some code might be shared: see normalizeWhitespace()
4635: //
4636: fNormalizedStr.setLength(0);
4637: int length = value.length();
4638: boolean skipSpace = true;
4639: char c = 0;
4640:
4641: for (int i = 0; i < length; i++) {
4642: c = value.charAt(i);
4643: if (c == 0x20) {
4644: if (!skipSpace) {
4645: // take the first whitespace as a space and skip the others
4646: fNormalizedStr.append(' ');
4647: skipSpace = true;
4648: }
4649: } else {
4650: fNormalizedStr.append((char) c);
4651: skipSpace = false;
4652: }
4653: }
4654: if (fNormalizedStr.length() == unTrimValue.length())
4655: return origIndex;
4656: return fStringPool.addSymbol(fNormalizedStr.toString());
4657: }
4658:
4659: /** Character data in content. */
4660: private void charDataInContent() {
4661:
4662: if (DEBUG_ELEMENT_CHILDREN) {
4663: System.out.println("charDataInContent()");
4664: }
4665: if (fElementChildren.length <= fElementChildrenLength) {
4666: QName[] newarray = new QName[fElementChildren.length * 2];
4667: System.arraycopy(fElementChildren, 0, newarray, 0,
4668: fElementChildren.length);
4669: fElementChildren = newarray;
4670: }
4671: QName qname = fElementChildren[fElementChildrenLength];
4672: if (qname == null) {
4673: for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
4674: fElementChildren[i] = new QName();
4675: }
4676: qname = fElementChildren[fElementChildrenLength];
4677: }
4678: qname.clear();
4679: fElementChildrenLength++;
4680:
4681: } // charDataInCount()
4682:
4683: /**
4684: * Check that the content of an element is valid.
4685: * <p>
4686: * This is the method of primary concern to the validator. This method is called
4687: * upon the scanner reaching the end tag of an element. At that time, the
4688: * element's children must be structurally validated, so it calls this method.
4689: * The index of the element being checked (in the decl pool), is provided as
4690: * well as an array of element name indexes of the children. The validator must
4691: * confirm that this element can have these children in this order.
4692: * <p>
4693: * This can also be called to do 'what if' testing of content models just to see
4694: * if they would be valid.
4695: * <p>
4696: * Note that the element index is an index into the element decl pool, whereas
4697: * the children indexes are name indexes, i.e. into the string pool.
4698: * <p>
4699: * A value of -1 in the children array indicates a PCDATA node. All other
4700: * indexes will be positive and represent child elements. The count can be
4701: * zero, since some elements have the EMPTY content model and that must be
4702: * confirmed.
4703: *
4704: * @param elementIndex The index within the <code>ElementDeclPool</code> of this
4705: * element.
4706: * @param childCount The number of entries in the <code>children</code> array.
4707: * @param children The children of this element. Each integer is an index within
4708: * the <code>StringPool</code> of the child element name. An index
4709: * of -1 is used to indicate an occurrence of non-whitespace character
4710: * data.
4711: *
4712: * @return The value -1 if fully valid, else the 0 based index of the child
4713: * that first failed. If the value returned is equal to the number
4714: * of children, then additional content is required to reach a valid
4715: * ending state.
4716: *
4717: * @exception Exception Thrown on error.
4718: */
4719: private int checkContent(int elementIndex, QName[] children,
4720: int childOffset, int childCount) throws Exception {
4721:
4722: // Get the element name index from the element
4723: // REVISIT: Validation
4724: final int elementType = fCurrentElement.rawname;
4725:
4726: if (DEBUG_PRINT_CONTENT) {
4727: String strTmp = fStringPool.toString(elementType);
4728: System.out.println("Name: " + strTmp + ", " + "Count: "
4729: + childCount + ", " + "ContentSpecType: "
4730: + fCurrentContentSpecType); //+getContentSpecAsString(elementIndex));
4731: for (int index = childOffset; index < (childOffset + childCount)
4732: && index < 10; index++) {
4733: if (index == 0) {
4734: System.out.print(" (");
4735: }
4736: String childName = (children[index].localpart == -1) ? "#PCDATA"
4737: : fStringPool
4738: .toString(children[index].localpart);
4739: if (index + 1 == childCount) {
4740: System.out.println(childName + ")");
4741: } else if (index + 1 == 10) {
4742: System.out.println(childName + ",...)");
4743: } else {
4744: System.out.print(childName + ",");
4745: }
4746: }
4747: }
4748:
4749: // Get out the content spec for this element
4750: final int contentType = fCurrentContentSpecType;
4751:
4752: //
4753: // Deal with the possible types of content. We try to optimized here
4754: // by dealing specially with content models that don't require the
4755: // full DFA treatment.
4756: //
4757: if (contentType == XMLElementDecl.TYPE_EMPTY) {
4758: //
4759: // If the child count is greater than zero, then this is
4760: // an error right off the bat at index 0.
4761: //
4762: if (childCount != 0) {
4763: return 0;
4764: }
4765: } else if (contentType == XMLElementDecl.TYPE_ANY) {
4766: //
4767: // This one is open game so we don't pass any judgement on it
4768: // at all. Its assumed to fine since it can hold anything.
4769: //
4770: } else if (contentType == XMLElementDecl.TYPE_MIXED_SIMPLE
4771: || contentType == XMLElementDecl.TYPE_MIXED_COMPLEX
4772: || contentType == XMLElementDecl.TYPE_CHILDREN) {
4773:
4774: // XML Schema REC: Validation Rule: Element Locally Valid (Element)
4775: // 3.2.1 The element information item must have no
4776: // character or element information item [children].
4777: //
4778: if (childCount == 0 && fNil) {
4779: fNil = false;
4780: //return success
4781: return -1;
4782: }
4783:
4784: // Get the content model for this element, faulting it in if needed
4785: XMLContentModel cmElem = null;
4786: try {
4787: cmElem = getElementContentModel(elementIndex);
4788: int curState = fContentModelStateStack[fElementDepth + 1];
4789: // if state!=-2, we have validate the children
4790: if (curState != -2) {
4791: // if state==-1, there is invalid child
4792: // if !finalState, then the content is not complete
4793: // both indicate an error, we return successful element count
4794: if (curState == -1
4795: || !((DFAContentModel) cmElem)
4796: .isFinalState(curState)) {
4797: return fContentModelEleCount[fElementDepth + 1];
4798: } else {
4799: // otherwise -1: succeeded
4800: return -1;
4801: }
4802: }
4803: //otherwise, we need to validateContent
4804: int result = cmElem.validateContent(children,
4805: childOffset, childCount);
4806: if (result != -1 && fGrammarIsSchemaGrammar) {
4807: result = cmElem.validateContentSpecial(children,
4808: childOffset, childCount);
4809: }
4810: return result;
4811: } catch (CMException excToCatch) {
4812: // REVISIT - Translate the caught exception to the protected error API
4813: int majorCode = excToCatch.getErrorCode();
4814: fErrorReporter
4815: .reportError(
4816: fErrorReporter.getLocator(),
4817: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
4818: majorCode, 0, null,
4819: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
4820: }
4821: } else if (contentType == -1) {
4822: reportRecoverableXMLError(
4823: XMLMessages.MSG_ELEMENT_NOT_DECLARED,
4824: XMLMessages.VC_ELEMENT_VALID, elementType);
4825: } else if (contentType == XMLElementDecl.TYPE_SIMPLE) {
4826:
4827: XMLContentModel cmElem = null;
4828: if (childCount > 0) {
4829: fErrorReporter
4830: .reportError(
4831: fErrorReporter.getLocator(),
4832: SchemaMessageProvider.SCHEMA_DOMAIN,
4833: SchemaMessageProvider.DatatypeError,
4834: SchemaMessageProvider.MSG_NONE,
4835: new Object[] { "In element '"
4836: + fStringPool
4837: .toString(elementType)
4838: + "' : "
4839: + "Can not have element children within a simple type content" },
4840: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4841: } else {
4842: try {
4843:
4844: if (fCurrentDV == null) { //no character data
4845: fGrammar.getElementDecl(elementIndex,
4846: fTempElementDecl);
4847: fCurrentDV = fTempElementDecl.datatypeValidator;
4848: }
4849:
4850: // If there is xsi:type validator, substitute it.
4851: if (fXsiTypeValidator != null) {
4852: fCurrentDV = fXsiTypeValidator;
4853: fXsiTypeValidator = null;
4854: }
4855: if (fCurrentDV == null) {
4856: System.out
4857: .println("Internal Error: this element have a simpletype "
4858: + "but no datatypevalidator was found, element "
4859: + fTempElementDecl.name
4860: + ",locapart: "
4861: + fStringPool
4862: .toString(fTempElementDecl.name.localpart));
4863: } else {
4864: String value = fDatatypeBuffer.toString();
4865: if (!fNormalizeContents
4866: && fWhiteSpace != DatatypeValidator.PRESERVE) {
4867: // normalize data before validating it
4868: fUnnormalizedStr.setLength(0);
4869: fUnnormalizedStr.append(value);
4870: normalizeWhitespace(
4871: fUnnormalizedStr,
4872: (fWhiteSpace == DatatypeValidator.COLLAPSE));
4873: value = fNormalizedStr.toString();
4874: }
4875: String currentElementDefault = ((SchemaGrammar) fGrammar)
4876: .getElementDefaultValue(fCurrentElementIndex);
4877: int hasFixed = (((SchemaGrammar) fGrammar)
4878: .getElementDeclMiscFlags(fCurrentElementIndex) & SchemaSymbols.FIXED);
4879: if (fNil) {
4880: if (value.length() != 0) {
4881: reportRecoverableXMLError(
4882: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
4883: XMLMessages.SCHEMA_GENERIC_ERROR,
4884: "An element <"
4885: + fStringPool
4886: .toString(elementType)
4887: + "> with attribute xsi:nil=\"true\" must be empty");
4888: }
4889: if (hasFixed != 0) {
4890: reportRecoverableXMLError(
4891: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
4892: XMLMessages.SCHEMA_GENERIC_ERROR,
4893: "An element <"
4894: + fStringPool
4895: .toString(elementType)
4896: + "> with attribute xsi:nil=\"true\" must not have fixed value constraint");
4897: }
4898: fNil = false;
4899: return -1;
4900: }
4901: // check for fixed/default values of elements here.
4902: if (currentElementDefault == null
4903: || currentElementDefault.length() == 0) {
4904: validateUsingDV(fCurrentDV, value, false);
4905: } else {
4906: if (hasFixed != 0) {
4907: if (value.length() == 0) { // use fixed as default value
4908: // Note: this is inefficient where the DOMParser
4909: // is concerned. However, if we used the characters(int)
4910: // callback instead, this would be just as inefficient for SAX.
4911: fDocumentHandler.characters(
4912: currentElementDefault
4913: .toCharArray(), 0,
4914: currentElementDefault
4915: .length());
4916: validateUsingDV(fCurrentDV,
4917: currentElementDefault, true);
4918: } else { // must check in valuespace!
4919: if (fCurrentDV.compare(value,
4920: currentElementDefault) != 0) {
4921: fErrorReporter
4922: .reportError(
4923: fErrorReporter
4924: .getLocator(),
4925: SchemaMessageProvider.SCHEMA_DOMAIN,
4926: SchemaMessageProvider.FixedDiffersFromActual,
4927: 0,
4928: null,
4929: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4930: }
4931: validateUsingDV(fCurrentDV, value,
4932: true);
4933: }
4934: } else {
4935: if (value.length() == 0) { // use default value
4936: fDocumentHandler.characters(
4937: currentElementDefault
4938: .toCharArray(), 0,
4939: currentElementDefault
4940: .length());
4941: validateUsingDV(fCurrentDV,
4942: currentElementDefault, true);
4943: } else {
4944: validateUsingDV(fCurrentDV, value,
4945: false);
4946: }
4947: }
4948: }
4949: }
4950: } catch (InvalidDatatypeValueException idve) {
4951: fErrorReporter
4952: .reportError(
4953: fErrorReporter.getLocator(),
4954: SchemaMessageProvider.SCHEMA_DOMAIN,
4955: SchemaMessageProvider.DatatypeError,
4956: SchemaMessageProvider.MSG_NONE,
4957: new Object[] { "In element '"
4958: + fStringPool
4959: .toString(elementType)
4960: + "' : "
4961: + idve.getMessage() },
4962: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
4963: }
4964:
4965: fCurrentDV = null;
4966: fFirstChunk = true;
4967: fTrailing = false;
4968: }
4969: } else {
4970: fErrorReporter
4971: .reportError(
4972: fErrorReporter.getLocator(),
4973: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
4974: ImplementationMessages.VAL_CST, 0, null,
4975: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
4976: }
4977:
4978: // We succeeded
4979: return -1;
4980:
4981: } // checkContent(int,int,int[]):int
4982:
4983: /**
4984: * Checks that all declared elements refer to declared elements
4985: * in their content models. This method calls out to the error
4986: * handler to indicate warnings.
4987: */
4988: /*private void checkDeclaredElements() throws Exception {
4989:
4990: //****DEBUG****
4991: if (DEBUG) print("(???) XMLValidator.checkDeclaredElements\n");
4992: //****DEBUG****
4993:
4994: for (int i = 0; i < fElementCount; i++) {
4995: int type = fGrammar.getContentSpecType(i);
4996: if (type == XMLElementDecl.TYPE_MIXED_SIMPLE ||
4997: type == XMLElementDecl.TYPE_MIXED_COMPLEX ||
4998: type == XMLElementDecl.TYPE_CHILDREN) {
4999: int chunk = i >> CHUNK_SHIFT;
5000: int index = i & CHUNK_MASK;
5001: int contentSpecIndex = fContentSpec[chunk][index];
5002: checkDeclaredElements(i, contentSpecIndex);
5003: }
5004: }
5005: }
5006: */
5007:
5008: private void printChildren() {
5009: if (DEBUG_ELEMENT_CHILDREN) {
5010: System.out.print('[');
5011: for (int i = 0; i < fElementChildrenLength; i++) {
5012: System.out.print(' ');
5013: QName qname = fElementChildren[i];
5014: if (qname != null) {
5015: System.out.print(fStringPool
5016: .toString(qname.rawname));
5017: } else {
5018: System.out.print("null");
5019: }
5020: if (i < fElementChildrenLength - 1) {
5021: System.out.print(", ");
5022: }
5023: System.out.flush();
5024: }
5025: System.out.print(" ]");
5026: System.out.println();
5027: }
5028: }
5029:
5030: private void printStack() {
5031: if (DEBUG_ELEMENT_CHILDREN) {
5032: System.out.print('{');
5033: for (int i = 0; i <= fElementDepth; i++) {
5034: System.out.print(' ');
5035: System.out.print(fElementChildrenOffsetStack[i]);
5036: if (i < fElementDepth) {
5037: System.out.print(", ");
5038: }
5039: System.out.flush();
5040: }
5041: System.out.print(" }");
5042: System.out.println();
5043: }
5044: }
5045:
5046: //
5047: // Interfaces
5048: //
5049:
5050: /**
5051: * AttributeValidator.
5052: */
5053: public interface AttributeValidator {
5054:
5055: //
5056: // AttributeValidator methods
5057: //
5058:
5059: /** Normalize. */
5060: public int normalize(QName element, QName attribute,
5061: int attValue, int attType, int enumHandle)
5062: throws Exception;
5063:
5064: } // interface AttributeValidator
5065:
5066: /** Returns true if invalid standalone attribute definition. */
5067: boolean invalidStandaloneAttDef(QName element, QName attribute) {
5068: if (fStandaloneReader == -1) {
5069: return false;
5070: }
5071: // we are normalizing a default att value... this ok?
5072: if (element.rawname == -1) {
5073: return false;
5074: }
5075: return getAttDefIsExternal(element, attribute);
5076: }
5077:
5078: void validateUsingDV(DatatypeValidator dv, String content,
5079: boolean onlyVal3Types) throws Exception,
5080: InvalidDatatypeValueException {
5081: if (dv instanceof IDDatatypeValidator) {
5082: dv.validate(content, fIdDefs);
5083: } else if (dv instanceof IDREFDatatypeValidator) {
5084: dv.validate(content, fValidateIDRef);
5085: } else if (dv instanceof ENTITYDatatypeValidator) {
5086: dv.validate(content, fValidateEntity);
5087: } else if (!onlyVal3Types) {
5088: if (dv instanceof NOTATIONDatatypeValidator
5089: && content != null) {
5090: content = bindNotationURI(content);
5091: }
5092: dv.validate(content, null);
5093: }
5094: }
5095:
5096: //
5097: // Classes
5098: //
5099:
5100: /**
5101: * AttValidatorNOTATION.
5102: */
5103: final class AttValidatorNOTATION implements AttributeValidator {
5104:
5105: //REVISIT: it looks like a redundant class
5106: //
5107:
5108: //
5109: // AttributeValidator methods
5110: //
5111:
5112: /** Normalize. */
5113: public int normalize(QName element, QName attribute,
5114: int attValueHandle, int attType, int enumHandle)
5115: throws Exception {
5116: //
5117: // Normalize attribute based upon attribute type...
5118: //
5119: String attValue = fStringPool.toString(attValueHandle);
5120: String newAttValue = attValue.trim();
5121: if (fValidating) {
5122: // REVISIT - can we release the old string?
5123: if (newAttValue != attValue) {
5124: if (invalidStandaloneAttDef(element, attribute)) {
5125: reportRecoverableXMLError(
5126: XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
5127: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
5128: fStringPool.toString(attribute.rawname),
5129: attValue, newAttValue);
5130: }
5131: attValueHandle = fStringPool.addSymbol(newAttValue);
5132: } else {
5133: attValueHandle = fStringPool
5134: .addSymbol(attValueHandle);
5135: }
5136: //
5137: // NOTATION - check that the value is in the AttDef enumeration (V_TAGo)
5138: //
5139: if (!fStringPool.stringInList(enumHandle,
5140: attValueHandle)) {
5141: reportRecoverableXMLError(
5142: XMLMessages.MSG_ATTRIBUTE_VALUE_NOT_IN_LIST,
5143: XMLMessages.VC_NOTATION_ATTRIBUTES,
5144: fStringPool.toString(attribute.rawname),
5145: newAttValue, fStringPool
5146: .stringListAsString(enumHandle));
5147: }
5148: } else if (newAttValue != attValue) {
5149: // REVISIT - can we release the old string?
5150: attValueHandle = fStringPool.addSymbol(newAttValue);
5151: }
5152: return attValueHandle;
5153:
5154: } // normalize(QName,QName,int,int,int):int
5155:
5156: //
5157: // Package methods
5158: //
5159:
5160: /** Returns true if invalid standalone attribute definition. */
5161: boolean invalidStandaloneAttDef(QName element, QName attribute) {
5162: if (fStandaloneReader == -1) {
5163: return false;
5164: }
5165: // we are normalizing a default att value... this ok?
5166: if (element.rawname == -1) {
5167: return false;
5168: }
5169: return getAttDefIsExternal(element, attribute);
5170: }
5171:
5172: } // class AttValidatorNOTATION
5173:
5174: /**
5175: * AttValidatorENUMERATION.
5176: */
5177: final class AttValidatorENUMERATION implements AttributeValidator {
5178:
5179: //REVISIT: it looks like a redundant class.
5180: // could be just a method. See also AttValidatorNOTATION
5181: //
5182: // AttributeValidator methods
5183: //
5184:
5185: /** Normalize. */
5186: public int normalize(QName element, QName attribute,
5187: int attValueHandle, int attType, int enumHandle)
5188: throws Exception {
5189: //
5190: // Normalize attribute based upon attribute type...
5191: //
5192: String attValue = fStringPool.toString(attValueHandle);
5193: String newAttValue = attValue.trim();
5194: if (fValidating) {
5195: // REVISIT - can we release the old string?
5196: if (newAttValue != attValue) {
5197: if (invalidStandaloneAttDef(element, attribute)) {
5198: reportRecoverableXMLError(
5199: XMLMessages.MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE,
5200: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
5201: fStringPool.toString(attribute.rawname),
5202: attValue, newAttValue);
5203: }
5204: attValueHandle = fStringPool.addSymbol(newAttValue);
5205: } else {
5206: attValueHandle = fStringPool
5207: .addSymbol(attValueHandle);
5208: }
5209: //
5210: // ENUMERATION - check that value is in the AttDef enumeration (V_TAG9)
5211: //
5212: if (!fStringPool.stringInList(enumHandle,
5213: attValueHandle)) {
5214: reportRecoverableXMLError(
5215: XMLMessages.MSG_ATTRIBUTE_VALUE_NOT_IN_LIST,
5216: XMLMessages.VC_ENUMERATION, fStringPool
5217: .toString(attribute.rawname),
5218: newAttValue, fStringPool
5219: .stringListAsString(enumHandle));
5220: }
5221: } else if (newAttValue != attValue) {
5222: // REVISIT - can we release the old string?
5223: attValueHandle = fStringPool.addSymbol(newAttValue);
5224: }
5225: return attValueHandle;
5226:
5227: } // normalize(QName,QName,int,int,int):int
5228:
5229: //
5230: // Package methods
5231: //
5232:
5233: /** Returns true if invalid standalone attribute definition. */
5234: boolean invalidStandaloneAttDef(QName element, QName attribute) {
5235: if (fStandaloneReader == -1) {
5236: return false;
5237: }
5238: // we are normalizing a default att value... this ok?
5239: if (element.rawname == -1) {
5240: return false;
5241: }
5242: return getAttDefIsExternal(element, attribute);
5243: }
5244:
5245: } // class AttValidatorENUMERATION
5246:
5247: // xpath matcher information
5248:
5249: /**
5250: * Stack of XPath matchers for identity constraints.
5251: *
5252: * @author Andy Clark, IBM
5253: */
5254: protected static class XPathMatcherStack {
5255:
5256: //
5257: // Data
5258: //
5259:
5260: /** Active matchers. */
5261: protected XPathMatcher[] fMatchers = new XPathMatcher[4];
5262:
5263: /** Count of active matchers. */
5264: protected int fMatchersCount;
5265:
5266: /** Offset stack for contexts. */
5267: protected IntStack fContextStack = new IntStack();
5268:
5269: //
5270: // Constructors
5271: //
5272:
5273: public XPathMatcherStack() {
5274: } // <init>()
5275:
5276: //
5277: // Public methods
5278: //
5279:
5280: /** Resets the XPath matcher stack. */
5281: public void clear() {
5282: for (int i = 0; i < fMatchersCount; i++) {
5283: fMatchers[i] = null;
5284: }
5285: fMatchersCount = 0;
5286: fContextStack.clear();
5287: } // clear()
5288:
5289: /** Returns the size of the stack. */
5290: public int size() {
5291: return fContextStack.size();
5292: } // size():int
5293:
5294: /** Returns the count of XPath matchers. */
5295: public int getMatcherCount() {
5296: return fMatchersCount;
5297: } // getMatcherCount():int
5298:
5299: /** Adds a matcher. */
5300: public void addMatcher(XPathMatcher matcher) {
5301: ensureMatcherCapacity();
5302: fMatchers[fMatchersCount++] = matcher;
5303: } // addMatcher(XPathMatcher)
5304:
5305: /** Returns the XPath matcher at the specified index. */
5306: public XPathMatcher getMatcherAt(int index) {
5307: return fMatchers[index];
5308: } // getMatcherAt(index):XPathMatcher
5309:
5310: /** Pushes a new context onto the stack. */
5311: public void pushContext() {
5312: fContextStack.push(fMatchersCount);
5313: } // pushContext()
5314:
5315: /** Pops a context off of the stack. */
5316: public void popContext() {
5317: fMatchersCount = fContextStack.pop();
5318: } // popContext()
5319:
5320: //
5321: // Private methods
5322: //
5323:
5324: /** Ensures the size of the matchers array. */
5325: private void ensureMatcherCapacity() {
5326: if (fMatchersCount == fMatchers.length) {
5327: XPathMatcher[] array = new XPathMatcher[fMatchers.length * 2];
5328: System.arraycopy(fMatchers, 0, array, 0,
5329: fMatchers.length);
5330: fMatchers = array;
5331: }
5332: } // ensureMatcherCapacity()
5333:
5334: } // class XPathMatcherStack
5335:
5336: // value store implementations
5337:
5338: /**
5339: * Value store implementation base class. There are specific subclasses
5340: * for handling unique, key, and keyref.
5341: *
5342: * @author Andy Clark, IBM
5343: */
5344: protected abstract class ValueStoreBase implements ValueStore {
5345:
5346: //
5347: // Constants
5348: //
5349:
5350: /** Not a value (Unicode: #FFFF). */
5351: protected IDValue NOT_AN_IDVALUE = new IDValue("\uFFFF", null);
5352:
5353: //
5354: // Data
5355: //
5356:
5357: /** Identity constraint. */
5358: protected IdentityConstraint fIdentityConstraint;
5359:
5360: /** Current data values. */
5361: protected final OrderedHashtable fValues = new OrderedHashtable();
5362:
5363: /** Current data value count. */
5364: protected int fValuesCount;
5365:
5366: /** Data value tuples. */
5367: protected final Vector fValueTuples = new Vector();
5368:
5369: //
5370: // Constructors
5371: //
5372:
5373: /** Constructs a value store for the specified identity constraint. */
5374: protected ValueStoreBase(IdentityConstraint identityConstraint) {
5375: fIdentityConstraint = identityConstraint;
5376: } // <init>(IdentityConstraint)
5377:
5378: //
5379: // Public methods
5380: //
5381:
5382: // destroys this ValueStore; useful when, for instanc,e a
5383: // locally-scoped ID constraint is involved.
5384: public void destroy() {
5385: fValuesCount = 0;
5386: fValues.clear();
5387: fValueTuples.removeAllElements();
5388: } // end destroy():void
5389:
5390: // appends the contents of one ValueStore to those of us.
5391: public void append(ValueStoreBase newVal) {
5392: for (int i = 0; i < newVal.fValueTuples.size(); i++) {
5393: OrderedHashtable o = (OrderedHashtable) newVal.fValueTuples
5394: .elementAt(i);
5395: if (!contains(o))
5396: fValueTuples.addElement(o);
5397: }
5398: } // append(ValueStoreBase)
5399:
5400: /** Start scope for value store. */
5401: public void startValueScope() throws Exception {
5402: if (DEBUG_VALUE_STORES) {
5403: System.out.println("<VS>: " + toString()
5404: + "#startValueScope()");
5405: }
5406: fValuesCount = 0;
5407: int count = fIdentityConstraint.getFieldCount();
5408: for (int i = 0; i < count; i++) {
5409: fValues.put(fIdentityConstraint.getFieldAt(i),
5410: NOT_AN_IDVALUE);
5411: }
5412: } // startValueScope()
5413:
5414: /** Ends scope for value store. */
5415: public void endValueScope() throws Exception {
5416: if (DEBUG_VALUE_STORES) {
5417: System.out.println("<VS>: " + toString()
5418: + "#endValueScope()");
5419: }
5420:
5421: // is there anything to do?
5422: // REVISIT: This check solves the problem with field matchers
5423: // that get activated because they are at the same
5424: // level as the declaring element (e.g. selector xpath
5425: // is ".") but never match.
5426: // However, this doesn't help us catch the problem
5427: // when we expect a field value but never see it. A
5428: // better solution has to be found. -Ac
5429: // REVISIT: Is this a problem? -Ac
5430: // Yes - NG
5431: if (fValuesCount == 0) {
5432: if (fIdentityConstraint.getType() == IdentityConstraint.KEY) {
5433: int code = SchemaMessageProvider.AbsentKeyValue;
5434: String eName = fIdentityConstraint.getElementName();
5435: reportSchemaError(code, new Object[] { eName });
5436: }
5437: return;
5438: }
5439:
5440: // do we have enough values?
5441: if (fValuesCount != fIdentityConstraint.getFieldCount()) {
5442: switch (fIdentityConstraint.getType()) {
5443: case IdentityConstraint.UNIQUE: {
5444: int code = SchemaMessageProvider.UniqueNotEnoughValues;
5445: String ename = fIdentityConstraint.getElementName();
5446: reportSchemaError(code, new Object[] { ename });
5447: break;
5448: }
5449: case IdentityConstraint.KEY: {
5450: int code = SchemaMessageProvider.KeyNotEnoughValues;
5451: Key key = (Key) fIdentityConstraint;
5452: String ename = fIdentityConstraint.getElementName();
5453: String kname = key.getIdentityConstraintName();
5454: reportSchemaError(code,
5455: new Object[] { ename, kname });
5456: break;
5457: }
5458: case IdentityConstraint.KEYREF: {
5459: int code = SchemaMessageProvider.KeyRefNotEnoughValues;
5460: KeyRef keyref = (KeyRef) fIdentityConstraint;
5461: String ename = fIdentityConstraint.getElementName();
5462: String kname = (keyref.getKey())
5463: .getIdentityConstraintName();
5464: reportSchemaError(code,
5465: new Object[] { ename, kname });
5466: break;
5467: }
5468: }
5469: return;
5470: }
5471:
5472: } // endValueScope()
5473:
5474: // This is needed to allow keyref's to look for matched keys
5475: // in the correct scope. Unique and Key may also need to
5476: // override this method for purposes of their own.
5477: // This method is called whenever the DocumentFragment
5478: // of an ID Constraint goes out of scope.
5479: public void endDocumentFragment() throws Exception {
5480: } // endDocumentFragment():void
5481:
5482: /**
5483: * Signals the end of the document. This is where the specific
5484: * instances of value stores can verify the integrity of the
5485: * identity constraints.
5486: */
5487: public void endDocument() throws Exception {
5488: if (DEBUG_VALUE_STORES) {
5489: System.out.println("<VS>: " + toString()
5490: + "#endDocument()");
5491: }
5492: } // endDocument()
5493:
5494: //
5495: // ValueStore methods
5496: //
5497:
5498: /* reports an error if an element is matched
5499: * has nillable true and is matched by a key.
5500: */
5501:
5502: public void reportNilError(IdentityConstraint id)
5503: throws Exception {
5504: if (id.getType() == IdentityConstraint.KEY) {
5505: int code = SchemaMessageProvider.KeyMatchesNillable;
5506: reportSchemaError(code, new Object[] { id
5507: .getElementName() });
5508: }
5509: } // reportNilError
5510:
5511: /**
5512: * Adds the specified value to the value store.
5513: *
5514: * @param value The value to add.
5515: * @param field The field associated to the value. This reference
5516: * is used to ensure that each field only adds a value
5517: * once within a selection scope.
5518: */
5519: public void addValue(Field field, IDValue value)
5520: throws Exception {
5521: if (!field.mayMatch()) {
5522: int code = SchemaMessageProvider.FieldMultipleMatch;
5523: reportSchemaError(code,
5524: new Object[] { field.toString() });
5525: }
5526: if (DEBUG_VALUE_STORES) {
5527: System.out.println("<VS>: " + toString() + "#addValue("
5528: + "field=" + field + ',' + "value=" + value
5529: + ")");
5530: }
5531:
5532: // do we even know this field?
5533: int index = fValues.indexOf(field);
5534: if (index == -1) {
5535: int code = SchemaMessageProvider.UnknownField;
5536: reportSchemaError(code,
5537: new Object[] { field.toString() });
5538: return;
5539: }
5540:
5541: // store value
5542: IDValue storedValue = fValues.valueAt(index);
5543: if (storedValue.isDuplicateOf(NOT_AN_IDVALUE)) {
5544: fValuesCount++;
5545: }
5546: fValues.put(field, value);
5547:
5548: if (fValuesCount == fValues.size()) {
5549: // is this value as a group duplicated?
5550: if (contains(fValues)) {
5551: duplicateValue(fValues);
5552: }
5553:
5554: // store values
5555: OrderedHashtable values = (OrderedHashtable) fValues
5556: .clone();
5557: fValueTuples.addElement(values);
5558: }
5559:
5560: } // addValue(String,Field)
5561:
5562: /**
5563: * Returns true if this value store contains the specified
5564: * values tuple.
5565: */
5566: public boolean contains(OrderedHashtable tuple) {
5567: if (DEBUG_VALUE_STORES) {
5568: System.out.println("<VS>: " + this .toString()
5569: + "#contains(" + toString(tuple) + ")");
5570: }
5571:
5572: // do sizes match?
5573: int tcount = tuple.size();
5574:
5575: // iterate over tuples to find it
5576: int count = fValueTuples.size();
5577: LOOP: for (int i = 0; i < count; i++) {
5578: OrderedHashtable vtuple = (OrderedHashtable) fValueTuples
5579: .elementAt(i);
5580: // compare values
5581: for (int j = 0; j < tcount; j++) {
5582: IDValue value1 = vtuple.valueAt(j);
5583: IDValue value2 = tuple.valueAt(j);
5584: if (!(value1.isDuplicateOf(value2))) {
5585: continue LOOP;
5586: }
5587: }
5588:
5589: // found it
5590: return true;
5591: }
5592:
5593: // didn't find it
5594: return false;
5595:
5596: } // contains(Hashtable):boolean
5597:
5598: //
5599: // Protected methods
5600: //
5601:
5602: /**
5603: * Called when a duplicate value is added. Subclasses should override
5604: * this method to perform error checking.
5605: *
5606: * @param tuple The duplicate value tuple.
5607: */
5608: protected void duplicateValue(OrderedHashtable tuple)
5609: throws Exception {
5610: // no-op
5611: } // duplicateValue(Hashtable)
5612:
5613: /** Returns a string of the specified values. */
5614: protected String toString(OrderedHashtable tuple) {
5615:
5616: // no values
5617: int size = tuple.size();
5618: if (size == 0) {
5619: return "";
5620: }
5621:
5622: // construct value string
5623: StringBuffer str = new StringBuffer();
5624: for (int i = 0; i < size; i++) {
5625: if (i > 0) {
5626: str.append(',');
5627: }
5628: str.append(tuple.valueAt(i));
5629: }
5630: return str.toString();
5631:
5632: } // toString(OrderedHashtable):String
5633:
5634: //
5635: // Object methods
5636: //
5637:
5638: /** Returns a string representation of this object. */
5639: public String toString() {
5640: String s = super .toString();
5641: int index1 = s.lastIndexOf('$');
5642: if (index1 != -1) {
5643: s = s.substring(index1 + 1);
5644: }
5645: int index2 = s.lastIndexOf('.');
5646: if (index2 != -1) {
5647: s = s.substring(index2 + 1);
5648: }
5649: return s + '[' + fIdentityConstraint + ']';
5650: } // toString():String
5651:
5652: } // class ValueStoreBase
5653:
5654: /**
5655: * Unique value store.
5656: *
5657: * @author Andy Clark, IBM
5658: */
5659: protected class UniqueValueStore extends ValueStoreBase {
5660:
5661: //
5662: // Constructors
5663: //
5664:
5665: /** Constructs a unique value store. */
5666: public UniqueValueStore(Unique unique) {
5667: super (unique);
5668: } // <init>(Unique)
5669:
5670: //
5671: // ValueStoreBase protected methods
5672: //
5673:
5674: /**
5675: * Called when a duplicate value is added.
5676: *
5677: * @param tuple The duplicate value tuple.
5678: */
5679: protected void duplicateValue(OrderedHashtable tuple)
5680: throws Exception {
5681: int code = SchemaMessageProvider.DuplicateUnique;
5682: String value = toString(tuple);
5683: String ename = fIdentityConstraint.getElementName();
5684: reportSchemaError(code, new Object[] { value, ename });
5685: } // duplicateValue(Hashtable)
5686:
5687: } // class UniqueValueStore
5688:
5689: /**
5690: * Key value store.
5691: *
5692: * @author Andy Clark, IBM
5693: */
5694: protected class KeyValueStore extends ValueStoreBase {
5695:
5696: // REVISIT: Implement a more efficient storage mechanism. -Ac
5697:
5698: //
5699: // Constructors
5700: //
5701:
5702: /** Constructs a key value store. */
5703: public KeyValueStore(Key key) {
5704: super (key);
5705: } // <init>(Key)
5706:
5707: //
5708: // ValueStoreBase protected methods
5709: //
5710:
5711: /**
5712: * Called when a duplicate value is added.
5713: *
5714: * @param tuple The duplicate value tuple.
5715: */
5716: protected void duplicateValue(OrderedHashtable tuple)
5717: throws Exception {
5718: int code = SchemaMessageProvider.DuplicateKey;
5719: String value = toString(tuple);
5720: String ename = fIdentityConstraint.getElementName();
5721: reportSchemaError(code, new Object[] { value, ename });
5722: } // duplicateValue(Hashtable)
5723:
5724: } // class KeyValueStore
5725:
5726: /**
5727: * Key reference value store.
5728: *
5729: * @author Andy Clark, IBM
5730: */
5731: protected class KeyRefValueStore extends ValueStoreBase {
5732:
5733: //
5734: // Data
5735: //
5736:
5737: /** Key value store. */
5738: protected ValueStoreBase fKeyValueStore;
5739:
5740: //
5741: // Constructors
5742: //
5743:
5744: /** Constructs a key value store. */
5745: public KeyRefValueStore(KeyRef keyRef,
5746: KeyValueStore keyValueStore) {
5747: super (keyRef);
5748: fKeyValueStore = keyValueStore;
5749: } // <init>(KeyRef)
5750:
5751: //
5752: // ValueStoreBase methods
5753: //
5754:
5755: // end the value Scope; here's where we have to tie
5756: // up keyRef loose ends.
5757: public void endDocumentFragment() throws Exception {
5758:
5759: // do all the necessary management...
5760: super .endDocumentFragment();
5761:
5762: // verify references
5763: // get the key store corresponding (if it exists):
5764: fKeyValueStore = (ValueStoreBase) fValueStoreCache.fGlobalIDConstraintMap
5765: .get(((KeyRef) fIdentityConstraint).getKey());
5766:
5767: if (fKeyValueStore == null) {
5768: // report error
5769: int code = SchemaMessageProvider.KeyRefOutOfScope;
5770: String value = fIdentityConstraint.toString();
5771: reportSchemaError(code, new Object[] { value });
5772: return;
5773: }
5774:
5775: int count = fValueTuples.size();
5776: for (int i = 0; i < count; i++) {
5777: OrderedHashtable values = (OrderedHashtable) fValueTuples
5778: .elementAt(i);
5779: if (!fKeyValueStore.contains(values)) {
5780: int code = SchemaMessageProvider.KeyNotFound;
5781: String value = toString(values);
5782: String element = fIdentityConstraint
5783: .getElementName();
5784: reportSchemaError(code, new Object[] { value,
5785: element });
5786: }
5787: }
5788:
5789: } // endDocumentFragment()
5790:
5791: /** End document. */
5792: public void endDocument() throws Exception {
5793: super .endDocument();
5794:
5795: } // endDocument()
5796:
5797: } // class KeyRefValueStore
5798:
5799: // value store management
5800:
5801: /**
5802: * Value store cache. This class is used to store the values for
5803: * identity constraints.
5804: *
5805: * @author Andy Clark, IBM
5806: */
5807: protected class ValueStoreCache {
5808:
5809: //
5810: // Data
5811: //
5812:
5813: // values stores
5814:
5815: /** stores all global Values stores. */
5816: protected final Vector fValueStores = new Vector();
5817:
5818: /** Values stores associated to specific identity constraints. */
5819: protected final Hashtable fIdentityConstraint2ValueStoreMap = new Hashtable();
5820:
5821: // sketch of algorithm:
5822: // - when a constraint is first encountered, its
5823: // values are stored in the (local) fIdentityConstraint2ValueStoreMap;
5824: // - Once it is validated (i.e., wen it goes out of scope),
5825: // its values are merged into the fGlobalIDConstraintMap;
5826: // - as we encounter keyref's, we look at the global table to
5827: // validate them.
5828: // the fGlobalIDMapStack has the following structure:
5829: // - validation always occurs against the fGlobalIDConstraintMap
5830: // (which comprises all the "eligible" id constraints);
5831: // When an endelement is found, this Hashtable is merged with the one
5832: // below in the stack.
5833: // When a start tag is encountered, we create a new
5834: // fGlobalIDConstraintMap.
5835: // i.e., the top of the fGlobalIDMapStack always contains
5836: // the preceding siblings' eligible id constraints;
5837: // the fGlobalIDConstraintMap contains descendants+self.
5838: // keyrefs can only match descendants+self.
5839: protected final Stack fGlobalMapStack = new Stack();
5840: protected final Hashtable fGlobalIDConstraintMap = new Hashtable();
5841:
5842: //
5843: // Constructors
5844: //
5845:
5846: /** Default constructor. */
5847: public ValueStoreCache() {
5848: } // <init>()
5849:
5850: //
5851: // Public methods
5852: //
5853:
5854: /** Resets the identity constraint cache. */
5855: public void startDocument() throws Exception {
5856: if (DEBUG_VALUE_STORES) {
5857: System.out.println("<VS>: " + toString()
5858: + "#startDocument()");
5859: }
5860: fValueStores.removeAllElements();
5861: fIdentityConstraint2ValueStoreMap.clear();
5862: fGlobalIDConstraintMap.clear();
5863: fGlobalMapStack.removeAllElements();
5864: } // startDocument()
5865:
5866: // startElement: pushes the current fGlobalIDConstraintMap
5867: // onto fGlobalMapStack and clears fGlobalIDConstraint map.
5868: public void startElement() {
5869: fGlobalMapStack.push(fGlobalIDConstraintMap.clone());
5870: fGlobalIDConstraintMap.clear();
5871: } // startElement(void)
5872:
5873: // endElement(): merges contents of fGlobalIDConstraintMap with the
5874: // top of fGlobalMapStack into fGlobalIDConstraintMap.
5875: public void endElement() {
5876: if (fGlobalMapStack.isEmpty())
5877: return; // must be an invalid doc!
5878: Hashtable oldMap = (Hashtable) fGlobalMapStack.pop();
5879: Enumeration keys = oldMap.keys();
5880: while (keys.hasMoreElements()) {
5881: IdentityConstraint id = (IdentityConstraint) keys
5882: .nextElement();
5883: ValueStoreBase oldVal = (ValueStoreBase) oldMap.get(id);
5884: if (oldVal != null) {
5885: ValueStoreBase currVal = (ValueStoreBase) fGlobalIDConstraintMap
5886: .get(id);
5887: if (currVal == null)
5888: fGlobalIDConstraintMap.put(id, oldVal);
5889: else {
5890: currVal.append(oldVal);
5891: fGlobalIDConstraintMap.put(id, currVal);
5892: }
5893: }
5894: }
5895: } // endElement()
5896:
5897: /**
5898: * Initializes the value stores for the specified element
5899: * declaration.
5900: */
5901: public void initValueStoresFor(XMLElementDecl eDecl)
5902: throws Exception {
5903: if (DEBUG_VALUE_STORES) {
5904: System.out.println("<VS>: " + toString()
5905: + "#initValueStoresFor("
5906: + fStringPool.toString(eDecl.name.rawname)
5907: + ")");
5908: }
5909:
5910: // initialize value stores for unique fields
5911: Vector uVector = eDecl.unique;
5912: int uCount = uVector.size();
5913: for (int i = 0; i < uCount; i++) {
5914: Unique unique = (Unique) uVector.elementAt(i);
5915: UniqueValueStore valueStore = (UniqueValueStore) fIdentityConstraint2ValueStoreMap
5916: .get(unique);
5917: if (valueStore != null) {
5918: // NOTE: If already initialized, don't need to
5919: // do it again. -Ac
5920: continue;
5921: }
5922: valueStore = new UniqueValueStore(unique);
5923: fValueStores.addElement(valueStore);
5924: if (DEBUG_VALUE_STORES) {
5925: System.out.println("<VS>: " + unique + " -> "
5926: + valueStore);
5927: }
5928: fIdentityConstraint2ValueStoreMap.put(unique,
5929: valueStore);
5930: }
5931:
5932: // initialize value stores for key fields
5933: Vector kVector = eDecl.key;
5934: int kCount = kVector.size();
5935: for (int i = 0; i < kCount; i++) {
5936: Key key = (Key) kVector.elementAt(i);
5937: KeyValueStore valueStore = (KeyValueStore) fIdentityConstraint2ValueStoreMap
5938: .get(key);
5939: if (valueStore != null) {
5940: // NOTE: If already initialized, don't need to
5941: // do it again. -Ac
5942: continue;
5943: }
5944: valueStore = new KeyValueStore(key);
5945: fValueStores.addElement(valueStore);
5946: if (DEBUG_VALUE_STORES) {
5947: System.out.println("<VS>: " + key + " -> "
5948: + valueStore);
5949: }
5950: fIdentityConstraint2ValueStoreMap.put(key, valueStore);
5951: }
5952:
5953: // initialize value stores for key reference fields
5954: Vector krVector = eDecl.keyRef;
5955: int krCount = krVector.size();
5956: for (int i = 0; i < krCount; i++) {
5957: KeyRef keyRef = (KeyRef) krVector.elementAt(i);
5958: KeyRefValueStore keyRefValueStore = new KeyRefValueStore(
5959: keyRef, null);
5960: fValueStores.addElement(keyRefValueStore);
5961: if (DEBUG_VALUE_STORES) {
5962: System.out.println("<VS>: " + keyRef + " -> "
5963: + keyRefValueStore);
5964: }
5965: fIdentityConstraint2ValueStoreMap.put(keyRef,
5966: keyRefValueStore);
5967: }
5968:
5969: } // initValueStoresFor(XMLElementDecl)
5970:
5971: /** Returns the value store associated to the specified field. */
5972: public ValueStoreBase getValueStoreFor(Field field) {
5973: if (DEBUG_VALUE_STORES) {
5974: System.out.println("<VS>: " + toString()
5975: + "#getValueStoreFor(" + field + ")");
5976: }
5977: IdentityConstraint identityConstraint = field
5978: .getIdentityConstraint();
5979: return (ValueStoreBase) fIdentityConstraint2ValueStoreMap
5980: .get(identityConstraint);
5981: } // getValueStoreFor(Field):ValueStoreBase
5982:
5983: /** Returns the value store associated to the specified IdentityConstraint. */
5984: public ValueStoreBase getValueStoreFor(IdentityConstraint id) {
5985: if (DEBUG_VALUE_STORES) {
5986: System.out.println("<VS>: " + toString()
5987: + "#getValueStoreFor(" + id + ")");
5988: }
5989: return (ValueStoreBase) fIdentityConstraint2ValueStoreMap
5990: .get(id);
5991: } // getValueStoreFor(IdentityConstraint):ValueStoreBase
5992:
5993: /** Returns the global value store associated to the specified IdentityConstraint. */
5994: public ValueStoreBase getGlobalValueStoreFor(
5995: IdentityConstraint id) {
5996: if (DEBUG_VALUE_STORES) {
5997: System.out.println("<VS>: " + toString()
5998: + "#getGlobalValueStoreFor(" + id + ")");
5999: }
6000: return (ValueStoreBase) fGlobalIDConstraintMap.get(id);
6001: } // getValueStoreFor(IdentityConstraint):ValueStoreBase
6002:
6003: // This method takes the contents of the (local) ValueStore
6004: // associated with id and moves them into the global
6005: // hashtable, if id is a <unique> or a <key>.
6006: // If it's a <keyRef>, then we leave it for later.
6007: public void transplant(IdentityConstraint id) throws Exception {
6008: if (id.getType() == IdentityConstraint.KEYREF)
6009: return;
6010: ValueStoreBase newVals = (ValueStoreBase) fIdentityConstraint2ValueStoreMap
6011: .get(id);
6012: fIdentityConstraint2ValueStoreMap.remove(id);
6013: ValueStoreBase currVals = (ValueStoreBase) fGlobalIDConstraintMap
6014: .get(id);
6015: if (currVals != null) {
6016: currVals.append(newVals);
6017: fGlobalIDConstraintMap.put(id, currVals);
6018: } else
6019: fGlobalIDConstraintMap.put(id, newVals);
6020:
6021: } // transplant(id)
6022:
6023: /** Check identity constraints. */
6024: public void endDocument() throws Exception {
6025: if (DEBUG_VALUE_STORES) {
6026: System.out.println("<VS>: " + toString()
6027: + "#endDocument()");
6028: }
6029:
6030: int count = fValueStores.size();
6031: for (int i = 0; i < count; i++) {
6032: ValueStoreBase valueStore = (ValueStoreBase) fValueStores
6033: .elementAt(i);
6034: valueStore.endDocument();
6035: }
6036:
6037: } // endDocument()
6038:
6039: //
6040: // Object methods
6041: //
6042:
6043: /** Returns a string representation of this object. */
6044: public String toString() {
6045: String s = super .toString();
6046: int index1 = s.lastIndexOf('$');
6047: if (index1 != -1) {
6048: return s.substring(index1 + 1);
6049: }
6050: int index2 = s.lastIndexOf('.');
6051: if (index2 != -1) {
6052: return s.substring(index2 + 1);
6053: }
6054: return s;
6055: } // toString():String
6056:
6057: } // class ValueStoreCache
6058:
6059: // utility classes
6060:
6061: /**
6062: * Ordered hashtable. This class acts as a hashtable with
6063: * <code>put()</code> and <code>get()</code> operations but also
6064: * allows values to be queried via the order that they were
6065: * added to the hashtable.
6066: * <p>
6067: * <strong>Note:</strong> This class does not perform any error
6068: * checking.
6069: * <p>
6070: * <strong>Note:</strong> This class is <em>not</em> efficient but
6071: * is assumed to be used for a very small set of values.
6072: *
6073: * @author Andy Clark, IBM
6074: */
6075: static final class OrderedHashtable implements Cloneable {
6076:
6077: //
6078: // Data
6079: //
6080:
6081: /** Size. */
6082: private int fSize;
6083:
6084: /** Hashtable entries. */
6085: private Entry[] fEntries = null;
6086:
6087: //
6088: // Public methods
6089: //
6090:
6091: /** Returns the number of entries in the hashtable. */
6092: public int size() {
6093: return fSize;
6094: } // size():int
6095:
6096: /** Puts an entry into the hashtable. */
6097: public void put(Field key, IDValue value) {
6098: int index = indexOf(key);
6099: if (index == -1) {
6100: ensureCapacity(fSize);
6101: index = fSize++;
6102: fEntries[index].key = key;
6103: }
6104: fEntries[index].value = value;
6105: } // put(Field,String)
6106:
6107: /** Returns the value associated to the specified key. */
6108: public IDValue get(Field key) {
6109: return fEntries[indexOf(key)].value;
6110: } // get(Field):String
6111:
6112: /** Returns the index of the entry with the specified key. */
6113: public int indexOf(Field key) {
6114: for (int i = 0; i < fSize; i++) {
6115: // NOTE: Only way to be sure that the keys are the
6116: // same is by using a reference comparison. In
6117: // order to rely on the equals method, each
6118: // field would have to take into account its
6119: // position in the identity constraint, the
6120: // identity constraint, the declaring element,
6121: // and the grammar that it is defined in.
6122: // Otherwise, you have the possibility that
6123: // the equals method would return true for two
6124: // fields that look *very* similar.
6125: // The reference compare isn't bad, actually,
6126: // because the field objects are cacheable. -Ac
6127: if (fEntries[i].key == key) {
6128: return i;
6129: }
6130: }
6131: return -1;
6132: } // indexOf(Field):int
6133:
6134: /** Returns the key at the specified index. */
6135: public Field keyAt(int index) {
6136: return fEntries[index].key;
6137: } // keyAt(int):Field
6138:
6139: /** Returns the value at the specified index. */
6140: public IDValue valueAt(int index) {
6141: return fEntries[index].value;
6142: } // valueAt(int):String
6143:
6144: /** Removes all of the entries from the hashtable. */
6145: public void clear() {
6146: fSize = 0;
6147: } // clear()
6148:
6149: //
6150: // Private methods
6151: //
6152:
6153: /** Ensures the capacity of the entries array. */
6154: private void ensureCapacity(int size) {
6155:
6156: // sizes
6157: int osize = -1;
6158: int nsize = -1;
6159:
6160: // create array
6161: if (fEntries == null) {
6162: osize = 0;
6163: nsize = 2;
6164: fEntries = new Entry[nsize];
6165: }
6166:
6167: // resize array
6168: else if (fEntries.length <= size) {
6169: osize = fEntries.length;
6170: nsize = 2 * osize;
6171: Entry[] array = new Entry[nsize];
6172: System.arraycopy(fEntries, 0, array, 0, osize);
6173: fEntries = array;
6174: }
6175:
6176: // create new entries
6177: for (int i = osize; i < nsize; i++) {
6178: fEntries[i] = new Entry();
6179: }
6180:
6181: } // ensureCapacity(int)
6182:
6183: //
6184: // Cloneable methods
6185: //
6186:
6187: /** Clones this object. */
6188: public Object clone() {
6189:
6190: OrderedHashtable hashtable = new OrderedHashtable();
6191: for (int i = 0; i < fSize; i++) {
6192: hashtable.put(fEntries[i].key, fEntries[i].value);
6193: }
6194: return hashtable;
6195:
6196: } // clone():Object
6197:
6198: //
6199: // Object methods
6200: //
6201:
6202: /** Returns a string representation of this object. */
6203: public String toString() {
6204: if (fSize == 0) {
6205: return "[]";
6206: }
6207: StringBuffer str = new StringBuffer();
6208: str.append('[');
6209: for (int i = 0; i < fSize; i++) {
6210: if (i > 0) {
6211: str.append(',');
6212: }
6213: str.append('{');
6214: str.append(fEntries[i].key);
6215: str.append(',');
6216: str.append(fEntries[i].value);
6217: str.append('}');
6218: }
6219: str.append(']');
6220: return str.toString();
6221: } // toString():String
6222:
6223: //
6224: // Classes
6225: //
6226:
6227: /**
6228: * Hashtable entry.
6229: */
6230: public static final class Entry {
6231:
6232: //
6233: // Data
6234: //
6235:
6236: /** Key. */
6237: public Field key;
6238:
6239: /** Value. */
6240: public IDValue value;
6241:
6242: } // class Entry
6243:
6244: } // class OrderedHashtable
6245:
6246: } // class XMLValidator
|