0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.xerces.impl.dtd;
0019:
0020: import org.apache.xerces.impl.Constants;
0021: import org.apache.xerces.impl.RevalidationHandler;
0022: import org.apache.xerces.impl.XMLEntityManager;
0023: import org.apache.xerces.impl.XMLErrorReporter;
0024: import org.apache.xerces.impl.dtd.models.ContentModelValidator;
0025: import org.apache.xerces.impl.dv.DTDDVFactory;
0026: import org.apache.xerces.impl.dv.DatatypeValidator;
0027: import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
0028: import org.apache.xerces.impl.msg.XMLMessageFormatter;
0029: import org.apache.xerces.impl.validation.ValidationManager;
0030: import org.apache.xerces.impl.validation.ValidationState;
0031: import org.apache.xerces.util.SymbolTable;
0032: import org.apache.xerces.util.XMLChar;
0033: import org.apache.xerces.util.XMLSymbols;
0034: import org.apache.xerces.xni.Augmentations;
0035: import org.apache.xerces.xni.NamespaceContext;
0036: import org.apache.xerces.xni.QName;
0037: import org.apache.xerces.xni.XMLAttributes;
0038: import org.apache.xerces.xni.XMLDocumentHandler;
0039: import org.apache.xerces.xni.XMLLocator;
0040: import org.apache.xerces.xni.XMLResourceIdentifier;
0041: import org.apache.xerces.xni.XMLString;
0042: import org.apache.xerces.xni.XNIException;
0043: import org.apache.xerces.xni.grammars.Grammar;
0044: import org.apache.xerces.xni.grammars.XMLGrammarDescription;
0045: import org.apache.xerces.xni.grammars.XMLGrammarPool;
0046: import org.apache.xerces.xni.parser.XMLComponent;
0047: import org.apache.xerces.xni.parser.XMLComponentManager;
0048: import org.apache.xerces.xni.parser.XMLConfigurationException;
0049: import org.apache.xerces.xni.parser.XMLDocumentFilter;
0050: import org.apache.xerces.xni.parser.XMLDocumentSource;
0051:
0052: /**
0053: * The DTD validator. The validator implements a document
0054: * filter: receiving document events from the scanner; validating
0055: * the content and structure; augmenting the InfoSet, if applicable;
0056: * and notifying the parser of the information resulting from the
0057: * validation process.
0058: * <p> Formerly, this component also handled DTD events and grammar construction.
0059: * To facilitate the development of a meaningful DTD grammar caching/preparsing
0060: * framework, this functionality has been moved into the XMLDTDLoader
0061: * class. Therefore, this class no longer implements the DTDFilter
0062: * or DTDContentModelFilter interfaces.
0063: * <p>
0064: * This component requires the following features and properties from the
0065: * component manager that uses it:
0066: * <ul>
0067: * <li>http://xml.org/sax/features/namespaces</li>
0068: * <li>http://xml.org/sax/features/validation</li>
0069: * <li>http://apache.org/xml/features/validation/dynamic</li>
0070: * <li>http://apache.org/xml/properties/internal/symbol-table</li>
0071: * <li>http://apache.org/xml/properties/internal/error-reporter</li>
0072: * <li>http://apache.org/xml/properties/internal/grammar-pool</li>
0073: * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
0074: * </ul>
0075: *
0076: * @xerces.internal
0077: *
0078: * @author Eric Ye, IBM
0079: * @author Andy Clark, IBM
0080: * @author Jeffrey Rodriguez IBM
0081: * @author Neil Graham, IBM
0082: *
0083: * @version $Id: XMLDTDValidator.java 572055 2007-09-02 17:55:43Z mrglavas $
0084: */
0085: public class XMLDTDValidator implements XMLComponent,
0086: XMLDocumentFilter, XMLDTDValidatorFilter, RevalidationHandler {
0087:
0088: //
0089: // Constants
0090: //
0091:
0092: /** Symbol: "<<datatypes>>". */
0093:
0094: /** Top level scope (-1). */
0095: private static final int TOP_LEVEL_SCOPE = -1;
0096:
0097: // feature identifiers
0098:
0099: /** Feature identifier: namespaces. */
0100: protected static final String NAMESPACES = Constants.SAX_FEATURE_PREFIX
0101: + Constants.NAMESPACES_FEATURE;
0102:
0103: /** Feature identifier: validation. */
0104: protected static final String VALIDATION = Constants.SAX_FEATURE_PREFIX
0105: + Constants.VALIDATION_FEATURE;
0106:
0107: /** Feature identifier: dynamic validation. */
0108: protected static final String DYNAMIC_VALIDATION = Constants.XERCES_FEATURE_PREFIX
0109: + Constants.DYNAMIC_VALIDATION_FEATURE;
0110:
0111: /** Feature identifier: balance syntax trees. */
0112: protected static final String BALANCE_SYNTAX_TREES = Constants.XERCES_FEATURE_PREFIX
0113: + Constants.BALANCE_SYNTAX_TREES;
0114:
0115: /** Feature identifier: warn on duplicate attdef */
0116: protected static final String WARN_ON_DUPLICATE_ATTDEF = Constants.XERCES_FEATURE_PREFIX
0117: + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE;
0118:
0119: protected static final String PARSER_SETTINGS = Constants.XERCES_FEATURE_PREFIX
0120: + Constants.PARSER_SETTINGS;
0121:
0122: // property identifiers
0123:
0124: /** Property identifier: symbol table. */
0125: protected static final String SYMBOL_TABLE = Constants.XERCES_PROPERTY_PREFIX
0126: + Constants.SYMBOL_TABLE_PROPERTY;
0127:
0128: /** Property identifier: error reporter. */
0129: protected static final String ERROR_REPORTER = Constants.XERCES_PROPERTY_PREFIX
0130: + Constants.ERROR_REPORTER_PROPERTY;
0131:
0132: /** Property identifier: grammar pool. */
0133: protected static final String GRAMMAR_POOL = Constants.XERCES_PROPERTY_PREFIX
0134: + Constants.XMLGRAMMAR_POOL_PROPERTY;
0135:
0136: /** Property identifier: datatype validator factory. */
0137: protected static final String DATATYPE_VALIDATOR_FACTORY = Constants.XERCES_PROPERTY_PREFIX
0138: + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY;
0139:
0140: // property identifier: ValidationManager
0141: protected static final String VALIDATION_MANAGER = Constants.XERCES_PROPERTY_PREFIX
0142: + Constants.VALIDATION_MANAGER_PROPERTY;
0143:
0144: // recognized features and properties
0145:
0146: /** Recognized features. */
0147: private static final String[] RECOGNIZED_FEATURES = { NAMESPACES,
0148: VALIDATION, DYNAMIC_VALIDATION, BALANCE_SYNTAX_TREES };
0149:
0150: /** Feature defaults. */
0151: private static final Boolean[] FEATURE_DEFAULTS = { null, null,
0152: Boolean.FALSE, Boolean.FALSE, };
0153:
0154: /** Recognized properties. */
0155: private static final String[] RECOGNIZED_PROPERTIES = {
0156: SYMBOL_TABLE, ERROR_REPORTER, GRAMMAR_POOL,
0157: DATATYPE_VALIDATOR_FACTORY, VALIDATION_MANAGER };
0158:
0159: /** Property defaults. */
0160: private static final Object[] PROPERTY_DEFAULTS = { null, null,
0161: null, null, null, };
0162:
0163: // debugging
0164:
0165: /** Compile to true to debug attributes. */
0166: private static final boolean DEBUG_ATTRIBUTES = false;
0167:
0168: /** Compile to true to debug element children. */
0169: private static final boolean DEBUG_ELEMENT_CHILDREN = false;
0170:
0171: //
0172: // Data
0173: //
0174:
0175: // updated during reset
0176: protected ValidationManager fValidationManager = null;
0177:
0178: // validation state
0179: protected final ValidationState fValidationState = new ValidationState();
0180:
0181: // features
0182:
0183: /** Namespaces. */
0184: protected boolean fNamespaces;
0185:
0186: /** Validation. */
0187: protected boolean fValidation;
0188:
0189: /** Validation against only DTD */
0190: protected boolean fDTDValidation;
0191:
0192: /**
0193: * Dynamic validation. This state of this feature is only useful when
0194: * the validation feature is set to <code>true</code>.
0195: */
0196: protected boolean fDynamicValidation;
0197:
0198: /** Controls whether the DTD grammar produces balanced syntax trees. */
0199: protected boolean fBalanceSyntaxTrees;
0200:
0201: /** warn on duplicate attribute definition, this feature works only when validation is true */
0202: protected boolean fWarnDuplicateAttdef;
0203:
0204: // properties
0205:
0206: /** Symbol table. */
0207: protected SymbolTable fSymbolTable;
0208:
0209: /** Error reporter. */
0210: protected XMLErrorReporter fErrorReporter;
0211:
0212: // the grammar pool
0213: protected XMLGrammarPool fGrammarPool;
0214:
0215: /** Grammar bucket. */
0216: protected DTDGrammarBucket fGrammarBucket;
0217:
0218: /* location of the document as passed in from startDocument call */
0219: protected XMLLocator fDocLocation;
0220:
0221: /** Namespace support. */
0222: protected NamespaceContext fNamespaceContext = null;
0223:
0224: /** Datatype validator factory. */
0225: protected DTDDVFactory fDatatypeValidatorFactory;
0226:
0227: // handlers
0228:
0229: /** Document handler. */
0230: protected XMLDocumentHandler fDocumentHandler;
0231:
0232: protected XMLDocumentSource fDocumentSource;
0233: // grammars
0234:
0235: /** DTD Grammar. */
0236: protected DTDGrammar fDTDGrammar;
0237:
0238: // state
0239:
0240: /** True if seen DOCTYPE declaration. */
0241: protected boolean fSeenDoctypeDecl = false;
0242:
0243: /** Perform validation. */
0244: private boolean fPerformValidation;
0245:
0246: /** Schema type: None, DTD, Schema */
0247: private String fSchemaType;
0248:
0249: // information regarding the current element
0250:
0251: /** Current element name. */
0252: private final QName fCurrentElement = new QName();
0253:
0254: /** Current element index. */
0255: private int fCurrentElementIndex = -1;
0256:
0257: /** Current content spec type. */
0258: private int fCurrentContentSpecType = -1;
0259:
0260: /** The root element name. */
0261: private final QName fRootElement = new QName();
0262:
0263: private boolean fInCDATASection = false;
0264: // element stack
0265:
0266: /** Element index stack. */
0267: private int[] fElementIndexStack = new int[8];
0268:
0269: /** Content spec type stack. */
0270: private int[] fContentSpecTypeStack = new int[8];
0271:
0272: /** Element name stack. */
0273: private QName[] fElementQNamePartsStack = new QName[8];
0274:
0275: // children list and offset stack
0276:
0277: /**
0278: * Element children. This data structure is a growing stack that
0279: * holds the children of elements from the root to the current
0280: * element depth. This structure never gets "deeper" than the
0281: * deepest element. Space is re-used once each element is closed.
0282: * <p>
0283: * <strong>Note:</strong> This is much more efficient use of memory
0284: * than creating new arrays for each element depth.
0285: * <p>
0286: * <strong>Note:</strong> The use of this data structure is for
0287: * validation "on the way out". If the validation model changes to
0288: * "on the way in", then this data structure is not needed.
0289: */
0290: private QName[] fElementChildren = new QName[32];
0291:
0292: /** Element children count. */
0293: private int fElementChildrenLength = 0;
0294:
0295: /**
0296: * Element children offset stack. This stack refers to offsets
0297: * into the <code>fElementChildren</code> array.
0298: * @see #fElementChildren
0299: */
0300: private int[] fElementChildrenOffsetStack = new int[32];
0301:
0302: /** Element depth. */
0303: private int fElementDepth = -1;
0304:
0305: // validation states
0306:
0307: /** True if seen the root element. */
0308: private boolean fSeenRootElement = false;
0309:
0310: /** True if inside of element content. */
0311: private boolean fInElementContent = false;
0312:
0313: // temporary variables
0314:
0315: /** Temporary element declaration. */
0316: private XMLElementDecl fTempElementDecl = new XMLElementDecl();
0317:
0318: /** Temporary atribute declaration. */
0319: private XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl();
0320:
0321: /** Temporary entity declaration. */
0322: private XMLEntityDecl fEntityDecl = new XMLEntityDecl();
0323:
0324: /** Temporary qualified name. */
0325: private QName fTempQName = new QName();
0326:
0327: /** Temporary string buffers. */
0328: private StringBuffer fBuffer = new StringBuffer();
0329:
0330: // symbols: general
0331:
0332: // attribute validators
0333:
0334: /** Datatype validator: ID. */
0335: protected DatatypeValidator fValID;
0336:
0337: /** Datatype validator: IDREF. */
0338: protected DatatypeValidator fValIDRef;
0339:
0340: /** Datatype validator: IDREFS. */
0341: protected DatatypeValidator fValIDRefs;
0342:
0343: /** Datatype validator: ENTITY. */
0344: protected DatatypeValidator fValENTITY;
0345:
0346: /** Datatype validator: ENTITIES. */
0347: protected DatatypeValidator fValENTITIES;
0348:
0349: /** Datatype validator: NMTOKEN. */
0350: protected DatatypeValidator fValNMTOKEN;
0351:
0352: /** Datatype validator: NMTOKENS. */
0353: protected DatatypeValidator fValNMTOKENS;
0354:
0355: /** Datatype validator: NOTATION. */
0356: protected DatatypeValidator fValNOTATION;
0357:
0358: // to check for duplicate ID or ANNOTATION attribute declare in
0359: // ATTLIST, and misc VCs
0360:
0361: //
0362: // Constructors
0363: //
0364:
0365: /** Default constructor. */
0366: public XMLDTDValidator() {
0367:
0368: // initialize data
0369: for (int i = 0; i < fElementQNamePartsStack.length; i++) {
0370: fElementQNamePartsStack[i] = new QName();
0371: }
0372: fGrammarBucket = new DTDGrammarBucket();
0373:
0374: } // <init>()
0375:
0376: DTDGrammarBucket getGrammarBucket() {
0377: return fGrammarBucket;
0378: } // getGrammarBucket(): DTDGrammarBucket
0379:
0380: //
0381: // XMLComponent methods
0382: //
0383:
0384: /*
0385: * Resets the component. The component can query the component manager
0386: * about any features and properties that affect the operation of the
0387: * component.
0388: *
0389: * @param componentManager The component manager.
0390: *
0391: * @throws SAXException Thrown by component on finitialization error.
0392: * For example, if a feature or property is
0393: * required for the operation of the component, the
0394: * component manager may throw a
0395: * SAXNotRecognizedException or a
0396: * SAXNotSupportedException.
0397: */
0398: public void reset(XMLComponentManager componentManager)
0399: throws XMLConfigurationException {
0400:
0401: // clear grammars
0402: fDTDGrammar = null;
0403: fSeenDoctypeDecl = false;
0404: fInCDATASection = false;
0405: // initialize state
0406: fSeenRootElement = false;
0407: fInElementContent = false;
0408: fCurrentElementIndex = -1;
0409: fCurrentContentSpecType = -1;
0410:
0411: fRootElement.clear();
0412:
0413: fValidationState.resetIDTables();
0414:
0415: fGrammarBucket.clear();
0416: fElementDepth = -1;
0417: fElementChildrenLength = 0;
0418:
0419: boolean parser_settings;
0420: try {
0421: parser_settings = componentManager
0422: .getFeature(PARSER_SETTINGS);
0423: } catch (XMLConfigurationException e) {
0424: parser_settings = true;
0425: }
0426:
0427: if (!parser_settings) {
0428: // parser settings have not been changed
0429: fValidationManager.addValidationState(fValidationState);
0430: return;
0431: }
0432:
0433: // sax features
0434: try {
0435: fNamespaces = componentManager.getFeature(NAMESPACES);
0436: } catch (XMLConfigurationException e) {
0437: fNamespaces = true;
0438: }
0439: try {
0440: fValidation = componentManager.getFeature(VALIDATION);
0441: } catch (XMLConfigurationException e) {
0442: fValidation = false;
0443: }
0444: try {
0445: fDTDValidation = !(componentManager
0446: .getFeature(Constants.XERCES_FEATURE_PREFIX
0447: + Constants.SCHEMA_VALIDATION_FEATURE));
0448: } catch (XMLConfigurationException e) {
0449: // must be in a schema-less configuration!
0450: fDTDValidation = true;
0451: }
0452:
0453: // Xerces features
0454: try {
0455: fDynamicValidation = componentManager
0456: .getFeature(DYNAMIC_VALIDATION);
0457: } catch (XMLConfigurationException e) {
0458: fDynamicValidation = false;
0459: }
0460:
0461: try {
0462: fBalanceSyntaxTrees = componentManager
0463: .getFeature(BALANCE_SYNTAX_TREES);
0464: } catch (XMLConfigurationException e) {
0465: fBalanceSyntaxTrees = false;
0466: }
0467:
0468: try {
0469: fWarnDuplicateAttdef = componentManager
0470: .getFeature(WARN_ON_DUPLICATE_ATTDEF);
0471: } catch (XMLConfigurationException e) {
0472: fWarnDuplicateAttdef = false;
0473: }
0474:
0475: try {
0476: fSchemaType = (String) componentManager
0477: .getProperty(Constants.JAXP_PROPERTY_PREFIX
0478: + Constants.SCHEMA_LANGUAGE);
0479: } catch (XMLConfigurationException e) {
0480: fSchemaType = null;
0481: }
0482:
0483: fValidationManager = (ValidationManager) componentManager
0484: .getProperty(VALIDATION_MANAGER);
0485: fValidationManager.addValidationState(fValidationState);
0486: fValidationState.setUsingNamespaces(fNamespaces);
0487:
0488: // get needed components
0489: fErrorReporter = (XMLErrorReporter) componentManager
0490: .getProperty(Constants.XERCES_PROPERTY_PREFIX
0491: + Constants.ERROR_REPORTER_PROPERTY);
0492: fSymbolTable = (SymbolTable) componentManager
0493: .getProperty(Constants.XERCES_PROPERTY_PREFIX
0494: + Constants.SYMBOL_TABLE_PROPERTY);
0495: try {
0496: fGrammarPool = (XMLGrammarPool) componentManager
0497: .getProperty(GRAMMAR_POOL);
0498: } catch (XMLConfigurationException e) {
0499: fGrammarPool = null;
0500: }
0501:
0502: fDatatypeValidatorFactory = (DTDDVFactory) componentManager
0503: .getProperty(Constants.XERCES_PROPERTY_PREFIX
0504: + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY);
0505: init();
0506:
0507: } // reset(XMLComponentManager)
0508:
0509: /**
0510: * Returns a list of feature identifiers that are recognized by
0511: * this component. This method may return null if no features
0512: * are recognized by this component.
0513: */
0514: public String[] getRecognizedFeatures() {
0515: return (String[]) (RECOGNIZED_FEATURES.clone());
0516: } // getRecognizedFeatures():String[]
0517:
0518: /**
0519: * Sets the state of a feature. This method is called by the component
0520: * manager any time after reset when a feature changes state.
0521: * <p>
0522: * <strong>Note:</strong> Components should silently ignore features
0523: * that do not affect the operation of the component.
0524: *
0525: * @param featureId The feature identifier.
0526: * @param state The state of the feature.
0527: *
0528: * @throws SAXNotRecognizedException The component should not throw
0529: * this exception.
0530: * @throws SAXNotSupportedException The component should not throw
0531: * this exception.
0532: */
0533: public void setFeature(String featureId, boolean state)
0534: throws XMLConfigurationException {
0535: } // setFeature(String,boolean)
0536:
0537: /**
0538: * Returns a list of property identifiers that are recognized by
0539: * this component. This method may return null if no properties
0540: * are recognized by this component.
0541: */
0542: public String[] getRecognizedProperties() {
0543: return (String[]) (RECOGNIZED_PROPERTIES.clone());
0544: } // getRecognizedProperties():String[]
0545:
0546: /**
0547: * Sets the value of a property. This method is called by the component
0548: * manager any time after reset when a property changes value.
0549: * <p>
0550: * <strong>Note:</strong> Components should silently ignore properties
0551: * that do not affect the operation of the component.
0552: *
0553: * @param propertyId The property identifier.
0554: * @param value The value of the property.
0555: *
0556: * @throws SAXNotRecognizedException The component should not throw
0557: * this exception.
0558: * @throws SAXNotSupportedException The component should not throw
0559: * this exception.
0560: */
0561: public void setProperty(String propertyId, Object value)
0562: throws XMLConfigurationException {
0563: } // setProperty(String,Object)
0564:
0565: /**
0566: * Returns the default state for a feature, or null if this
0567: * component does not want to report a default value for this
0568: * feature.
0569: *
0570: * @param featureId The feature identifier.
0571: *
0572: * @since Xerces 2.2.0
0573: */
0574: public Boolean getFeatureDefault(String featureId) {
0575: for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
0576: if (RECOGNIZED_FEATURES[i].equals(featureId)) {
0577: return FEATURE_DEFAULTS[i];
0578: }
0579: }
0580: return null;
0581: } // getFeatureDefault(String):Boolean
0582:
0583: /**
0584: * Returns the default state for a property, or null if this
0585: * component does not want to report a default value for this
0586: * property.
0587: *
0588: * @param propertyId The property identifier.
0589: *
0590: * @since Xerces 2.2.0
0591: */
0592: public Object getPropertyDefault(String propertyId) {
0593: for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
0594: if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
0595: return PROPERTY_DEFAULTS[i];
0596: }
0597: }
0598: return null;
0599: } // getPropertyDefault(String):Object
0600:
0601: //
0602: // XMLDocumentSource methods
0603: //
0604:
0605: /** Sets the document handler to receive information about the document. */
0606: public void setDocumentHandler(XMLDocumentHandler documentHandler) {
0607: fDocumentHandler = documentHandler;
0608: } // setDocumentHandler(XMLDocumentHandler)
0609:
0610: /** Returns the document handler */
0611: public XMLDocumentHandler getDocumentHandler() {
0612: return fDocumentHandler;
0613: } // getDocumentHandler(): XMLDocumentHandler
0614:
0615: //
0616: // XMLDocumentHandler methods
0617: //
0618:
0619: /** Sets the document source */
0620: public void setDocumentSource(XMLDocumentSource source) {
0621: fDocumentSource = source;
0622: } // setDocumentSource
0623:
0624: /** Returns the document source */
0625: public XMLDocumentSource getDocumentSource() {
0626: return fDocumentSource;
0627: } // getDocumentSource
0628:
0629: /**
0630: * The start of the document.
0631: *
0632: * @param locator The system identifier of the entity if the entity
0633: * is external, null otherwise.
0634: * @param encoding The auto-detected IANA encoding name of the entity
0635: * stream. This value will be null in those situations
0636: * where the entity encoding is not auto-detected (e.g.
0637: * internal entities or a document entity that is
0638: * parsed from a java.io.Reader).
0639: * @param namespaceContext
0640: * The namespace context in effect at the
0641: * start of this document.
0642: * This object represents the current context.
0643: * Implementors of this class are responsible
0644: * for copying the namespace bindings from the
0645: * the current context (and its parent contexts)
0646: * if that information is important.
0647: * @param augs Additional information that may include infoset augmentations
0648: *
0649: * @throws XNIException Thrown by handler to signal an error.
0650: */
0651: public void startDocument(XMLLocator locator, String encoding,
0652: NamespaceContext namespaceContext, Augmentations augs)
0653: throws XNIException {
0654:
0655: // call handlers
0656: // get initial grammars
0657: if (fGrammarPool != null) {
0658: Grammar[] grammars = fGrammarPool
0659: .retrieveInitialGrammarSet(XMLGrammarDescription.XML_DTD);
0660: for (int i = 0; i < grammars.length; i++) {
0661: fGrammarBucket.putGrammar((DTDGrammar) grammars[i]);
0662: }
0663: }
0664: fDocLocation = locator;
0665: fNamespaceContext = namespaceContext;
0666:
0667: if (fDocumentHandler != null) {
0668: fDocumentHandler.startDocument(locator, encoding,
0669: namespaceContext, augs);
0670: }
0671:
0672: } // startDocument(XMLLocator,String)
0673:
0674: /**
0675: * Notifies of the presence of an XMLDecl line in the document. If
0676: * present, this method will be called immediately following the
0677: * startDocument call.
0678: *
0679: * @param version The XML version.
0680: * @param encoding The IANA encoding name of the document, or null if
0681: * not specified.
0682: * @param standalone The standalone value, or null if not specified.
0683: * @param augs Additional information that may include infoset augmentations
0684: *
0685: * @throws XNIException Thrown by handler to signal an error.
0686: */
0687: public void xmlDecl(String version, String encoding,
0688: String standalone, Augmentations augs) throws XNIException {
0689:
0690: // save standalone state
0691: fGrammarBucket.setStandalone(standalone != null
0692: && standalone.equals("yes"));
0693:
0694: // call handlers
0695: if (fDocumentHandler != null) {
0696: fDocumentHandler.xmlDecl(version, encoding, standalone,
0697: augs);
0698: }
0699:
0700: } // xmlDecl(String,String,String)
0701:
0702: /**
0703: * Notifies of the presence of the DOCTYPE line in the document.
0704: *
0705: * @param rootElement The name of the root element.
0706: * @param publicId The public identifier if an external DTD or null
0707: * if the external DTD is specified using SYSTEM.
0708: * @param systemId The system identifier if an external DTD, null
0709: * otherwise.
0710: * @param augs Additional information that may include infoset augmentations
0711: *
0712: * @throws XNIException Thrown by handler to signal an error.
0713: */
0714: public void doctypeDecl(String rootElement, String publicId,
0715: String systemId, Augmentations augs) throws XNIException {
0716:
0717: // save root element state
0718: fSeenDoctypeDecl = true;
0719: fRootElement.setValues(null, rootElement, rootElement, null);
0720: // find or create grammar:
0721: String eid = null;
0722: try {
0723: eid = XMLEntityManager.expandSystemId(systemId,
0724: fDocLocation.getExpandedSystemId(), false);
0725: } catch (java.io.IOException e) {
0726: }
0727: XMLDTDDescription grammarDesc = new XMLDTDDescription(publicId,
0728: systemId, fDocLocation.getExpandedSystemId(), eid,
0729: rootElement);
0730: fDTDGrammar = fGrammarBucket.getGrammar(grammarDesc);
0731: if (fDTDGrammar == null) {
0732: // give grammar pool a chance...
0733: //
0734: // Do not bother checking the pool if no public or system identifier was provided.
0735: // Since so many different DTDs have roots in common, using only a root name as the
0736: // key may cause an unexpected grammar to be retrieved from the grammar pool. This scenario
0737: // would occur when an ExternalSubsetResolver has been queried and the
0738: // XMLInputSource returned contains an input stream but no external identifier.
0739: // This can never happen when the instance document specified a DOCTYPE. -- mrglavas
0740: if (fGrammarPool != null
0741: && (systemId != null || publicId != null)) {
0742: fDTDGrammar = (DTDGrammar) fGrammarPool
0743: .retrieveGrammar(grammarDesc);
0744: }
0745: }
0746: if (fDTDGrammar == null) {
0747: // we'll have to create it...
0748: if (!fBalanceSyntaxTrees) {
0749: fDTDGrammar = new DTDGrammar(fSymbolTable, grammarDesc);
0750: } else {
0751: fDTDGrammar = new BalancedDTDGrammar(fSymbolTable,
0752: grammarDesc);
0753: }
0754: } else {
0755: // we've found a cached one;so let's make sure not to read
0756: // any external subset!
0757: fValidationManager.setCachedDTD(true);
0758: }
0759: fGrammarBucket.setActiveGrammar(fDTDGrammar);
0760:
0761: // call handlers
0762: if (fDocumentHandler != null) {
0763: fDocumentHandler.doctypeDecl(rootElement, publicId,
0764: systemId, augs);
0765: }
0766:
0767: } // doctypeDecl(String,String,String, Augmentations)
0768:
0769: /**
0770: * The start of an element.
0771: *
0772: * @param element The name of the element.
0773: * @param attributes The element attributes.
0774: * @param augs Additional information that may include infoset augmentations
0775: *
0776: * @throws XNIException Thrown by handler to signal an error.
0777: */
0778: public void startElement(QName element, XMLAttributes attributes,
0779: Augmentations augs) throws XNIException {
0780:
0781: handleStartElement(element, attributes, augs);
0782: // call handlers
0783: if (fDocumentHandler != null) {
0784: fDocumentHandler.startElement(element, attributes, augs);
0785:
0786: }
0787:
0788: } // startElement(QName,XMLAttributes)
0789:
0790: /**
0791: * An empty element.
0792: *
0793: * @param element The name of the element.
0794: * @param attributes The element attributes.
0795: * @param augs Additional information that may include infoset augmentations
0796: *
0797: * @throws XNIException Thrown by handler to signal an error.
0798: */
0799: public void emptyElement(QName element, XMLAttributes attributes,
0800: Augmentations augs) throws XNIException {
0801:
0802: boolean removed = handleStartElement(element, attributes, augs);
0803:
0804: if (fDocumentHandler != null) {
0805: fDocumentHandler.emptyElement(element, attributes, augs);
0806: }
0807: if (!removed) {
0808: handleEndElement(element, augs, true);
0809: }
0810:
0811: } // emptyElement(QName,XMLAttributes)
0812:
0813: /**
0814: * Character content.
0815: *
0816: * @param text The content.
0817: *
0818: * @param augs Additional information that may include infoset augmentations
0819: *
0820: * @throws XNIException Thrown by handler to signal an error.
0821: */
0822: public void characters(XMLString text, Augmentations augs)
0823: throws XNIException {
0824:
0825: boolean callNextCharacters = true;
0826:
0827: // REVISIT: [Q] Is there a more efficient way of doing this?
0828: // Perhaps if the scanner told us so we don't have to
0829: // look at the characters again. -Ac
0830: boolean allWhiteSpace = true;
0831: for (int i = text.offset; i < text.offset + text.length; i++) {
0832: if (!isSpace(text.ch[i])) {
0833: allWhiteSpace = false;
0834: break;
0835: }
0836: }
0837: // call the ignoreableWhiteSpace callback
0838: // never call ignorableWhitespace if we are in cdata section
0839: if (fInElementContent && allWhiteSpace && !fInCDATASection) {
0840: if (fDocumentHandler != null) {
0841: fDocumentHandler.ignorableWhitespace(text, augs);
0842: callNextCharacters = false;
0843: }
0844: }
0845:
0846: // validate
0847: if (fPerformValidation) {
0848: if (fInElementContent) {
0849: if (fGrammarBucket.getStandalone()
0850: && fDTDGrammar
0851: .getElementDeclIsExternal(fCurrentElementIndex)) {
0852: if (allWhiteSpace) {
0853: fErrorReporter
0854: .reportError(
0855: XMLMessageFormatter.XML_DOMAIN,
0856: "MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE",
0857: null,
0858: XMLErrorReporter.SEVERITY_ERROR);
0859: }
0860: }
0861: if (!allWhiteSpace) {
0862: charDataInContent();
0863: }
0864:
0865: // For E15.2
0866: if (augs != null
0867: && augs.getItem(Constants.CHAR_REF_PROBABLE_WS) == Boolean.TRUE) {
0868: fErrorReporter
0869: .reportError(
0870: XMLMessageFormatter.XML_DOMAIN,
0871: "MSG_CONTENT_INVALID_SPECIFIED",
0872: new Object[] {
0873: fCurrentElement.rawname,
0874: fDTDGrammar
0875: .getContentSpecAsString(fElementDepth),
0876: "character reference" },
0877: XMLErrorReporter.SEVERITY_ERROR);
0878: }
0879: }
0880:
0881: if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
0882: charDataInContent();
0883: }
0884: }
0885:
0886: // call handlers
0887: if (callNextCharacters && fDocumentHandler != null) {
0888: fDocumentHandler.characters(text, augs);
0889: }
0890:
0891: } // characters(XMLString)
0892:
0893: /**
0894: * Ignorable whitespace. For this method to be called, the document
0895: * source must have some way of determining that the text containing
0896: * only whitespace characters should be considered ignorable. For
0897: * example, the validator can determine if a length of whitespace
0898: * characters in the document are ignorable based on the element
0899: * content model.
0900: *
0901: * @param text The ignorable whitespace.
0902: * @param augs Additional information that may include infoset augmentations
0903: *
0904: * @throws XNIException Thrown by handler to signal an error.
0905: */
0906: public void ignorableWhitespace(XMLString text, Augmentations augs)
0907: throws XNIException {
0908:
0909: // call handlers
0910: if (fDocumentHandler != null) {
0911: fDocumentHandler.ignorableWhitespace(text, augs);
0912: }
0913:
0914: } // ignorableWhitespace(XMLString)
0915:
0916: /**
0917: * The end of an element.
0918: *
0919: * @param element The name of the element.
0920: * @param augs Additional information that may include infoset augmentations
0921: *
0922: * @throws XNIException Thrown by handler to signal an error.
0923: */
0924: public void endElement(QName element, Augmentations augs)
0925: throws XNIException {
0926:
0927: handleEndElement(element, augs, false);
0928:
0929: } // endElement(QName)
0930:
0931: /**
0932: * The start of a CDATA section.
0933: * @param augs Additional information that may include infoset augmentations
0934: *
0935: * @throws XNIException Thrown by handler to signal an error.
0936: */
0937: public void startCDATA(Augmentations augs) throws XNIException {
0938:
0939: if (fPerformValidation && fInElementContent) {
0940: charDataInContent();
0941: }
0942: fInCDATASection = true;
0943: // call handlers
0944: if (fDocumentHandler != null) {
0945: fDocumentHandler.startCDATA(augs);
0946: }
0947:
0948: } // startCDATA()
0949:
0950: /**
0951: * The end of a CDATA section.
0952: * @param augs Additional information that may include infoset augmentations
0953: *
0954: * @throws XNIException Thrown by handler to signal an error.
0955: */
0956: public void endCDATA(Augmentations augs) throws XNIException {
0957:
0958: fInCDATASection = false;
0959: // call handlers
0960: if (fDocumentHandler != null) {
0961: fDocumentHandler.endCDATA(augs);
0962: }
0963:
0964: } // endCDATA()
0965:
0966: /**
0967: * The end of the document.
0968: * @param augs Additional information that may include infoset augmentations
0969: *
0970: * @throws XNIException Thrown by handler to signal an error.
0971: */
0972: public void endDocument(Augmentations augs) throws XNIException {
0973:
0974: // call handlers
0975: if (fDocumentHandler != null) {
0976: fDocumentHandler.endDocument(augs);
0977: }
0978:
0979: } // endDocument()
0980:
0981: /**
0982: * A comment.
0983: *
0984: * @param text The text in the comment.
0985: * @param augs Additional information that may include infoset augmentations
0986: *
0987: * @throws XNIException Thrown by application to signal an error.
0988: */
0989: public void comment(XMLString text, Augmentations augs)
0990: throws XNIException {
0991: // fixes E15.1
0992: if (fPerformValidation && fElementDepth >= 0
0993: && fDTDGrammar != null) {
0994: fDTDGrammar.getElementDecl(fCurrentElementIndex,
0995: fTempElementDecl);
0996: if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
0997: fErrorReporter.reportError(
0998: XMLMessageFormatter.XML_DOMAIN,
0999: "MSG_CONTENT_INVALID_SPECIFIED", new Object[] {
1000: fCurrentElement.rawname, "EMPTY",
1001: "comment" },
1002: XMLErrorReporter.SEVERITY_ERROR);
1003: }
1004: }
1005: // call handlers
1006: if (fDocumentHandler != null) {
1007: fDocumentHandler.comment(text, augs);
1008: }
1009:
1010: } // comment(XMLString)
1011:
1012: /**
1013: * A processing instruction. Processing instructions consist of a
1014: * target name and, optionally, text data. The data is only meaningful
1015: * to the application.
1016: * <p>
1017: * Typically, a processing instruction's data will contain a series
1018: * of pseudo-attributes. These pseudo-attributes follow the form of
1019: * element attributes but are <strong>not</strong> parsed or presented
1020: * to the application as anything other than text. The application is
1021: * responsible for parsing the data.
1022: *
1023: * @param target The target.
1024: * @param data The data or null if none specified.
1025: * @param augs Additional information that may include infoset augmentations
1026: *
1027: * @throws XNIException Thrown by handler to signal an error.
1028: */
1029: public void processingInstruction(String target, XMLString data,
1030: Augmentations augs) throws XNIException {
1031:
1032: // fixes E15.1
1033: if (fPerformValidation && fElementDepth >= 0
1034: && fDTDGrammar != null) {
1035: fDTDGrammar.getElementDecl(fCurrentElementIndex,
1036: fTempElementDecl);
1037: if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
1038: fErrorReporter.reportError(
1039: XMLMessageFormatter.XML_DOMAIN,
1040: "MSG_CONTENT_INVALID_SPECIFIED", new Object[] {
1041: fCurrentElement.rawname, "EMPTY",
1042: "processing instruction" },
1043: XMLErrorReporter.SEVERITY_ERROR);
1044: }
1045: }
1046: // call handlers
1047: if (fDocumentHandler != null) {
1048: fDocumentHandler.processingInstruction(target, data, augs);
1049: }
1050: } // processingInstruction(String,XMLString)
1051:
1052: /**
1053: * This method notifies the start of a general entity.
1054: * <p>
1055: * <strong>Note:</strong> This method is not called for entity references
1056: * appearing as part of attribute values.
1057: *
1058: * @param name The name of the general entity.
1059: * @param identifier The resource identifier.
1060: * @param encoding The auto-detected IANA encoding name of the entity
1061: * stream. This value will be null in those situations
1062: * where the entity encoding is not auto-detected (e.g.
1063: * internal entities or a document entity that is
1064: * parsed from a java.io.Reader).
1065: * @param augs Additional information that may include infoset augmentations
1066: *
1067: * @exception XNIException Thrown by handler to signal an error.
1068: */
1069: public void startGeneralEntity(String name,
1070: XMLResourceIdentifier identifier, String encoding,
1071: Augmentations augs) throws XNIException {
1072: if (fPerformValidation && fElementDepth >= 0
1073: && fDTDGrammar != null) {
1074: fDTDGrammar.getElementDecl(fCurrentElementIndex,
1075: fTempElementDecl);
1076: // fixes E15.1
1077: if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
1078: fErrorReporter.reportError(
1079: XMLMessageFormatter.XML_DOMAIN,
1080: "MSG_CONTENT_INVALID_SPECIFIED", new Object[] {
1081: fCurrentElement.rawname, "EMPTY",
1082: "ENTITY" },
1083: XMLErrorReporter.SEVERITY_ERROR);
1084: }
1085: if (fGrammarBucket.getStandalone()) {
1086: XMLDTDLoader.checkStandaloneEntityRef(name,
1087: fDTDGrammar, fEntityDecl, fErrorReporter);
1088: }
1089: }
1090: if (fDocumentHandler != null) {
1091: fDocumentHandler.startGeneralEntity(name, identifier,
1092: encoding, augs);
1093: }
1094: }
1095:
1096: /**
1097: * This method notifies the end of a general entity.
1098: * <p>
1099: * <strong>Note:</strong> This method is not called for entity references
1100: * appearing as part of attribute values.
1101: *
1102: * @param name The name of the entity.
1103: * @param augs Additional information that may include infoset augmentations
1104: *
1105: * @exception XNIException
1106: * Thrown by handler to signal an error.
1107: */
1108: public void endGeneralEntity(String name, Augmentations augs)
1109: throws XNIException {
1110: // call handlers
1111: if (fDocumentHandler != null) {
1112: fDocumentHandler.endGeneralEntity(name, augs);
1113: }
1114: } // endEntity(String)
1115:
1116: /**
1117: * Notifies of the presence of a TextDecl line in an entity. If present,
1118: * this method will be called immediately following the startParameterEntity call.
1119: * <p>
1120: * <strong>Note:</strong> This method is only called for external
1121: * parameter entities referenced in the DTD.
1122: *
1123: * @param version The XML version, or null if not specified.
1124: * @param encoding The IANA encoding name of the entity.
1125: * @param augs Additional information that may include infoset
1126: * augmentations.
1127: *
1128: * @throws XNIException Thrown by handler to signal an error.
1129: */
1130: public void textDecl(String version, String encoding,
1131: Augmentations augs) throws XNIException {
1132:
1133: // call handlers
1134: if (fDocumentHandler != null) {
1135: fDocumentHandler.textDecl(version, encoding, augs);
1136: }
1137: }
1138:
1139: public final boolean hasGrammar() {
1140:
1141: return (fDTDGrammar != null);
1142: }
1143:
1144: public final boolean validate() {
1145: // Do validation if all of the following are true:
1146: // 1. The JAXP Schema Language property is not XML Schema
1147: // REVISIT: since only DTD and Schema are supported at this time,
1148: // such checking is sufficient. but if more schema types
1149: // are introduced in the future, we'll need to change it
1150: // to something like
1151: // (fSchemaType == null || fSchemaType == NS_XML_DTD)
1152: // 2. One of the following is true (validation features)
1153: // 2.1 Dynamic validation is off, and validation is on
1154: // 2.2 Dynamic validation is on, and DOCTYPE was seen
1155: // 3 Xerces schema validation feature is off, or DOCTYPE was seen.
1156: return (fSchemaType != Constants.NS_XMLSCHEMA)
1157: && (!fDynamicValidation && fValidation || fDynamicValidation
1158: && fSeenDoctypeDecl)
1159: && (fDTDValidation || fSeenDoctypeDecl);
1160: }
1161:
1162: //REVISIT:we can convert into functions.. adding default attribute values.. and one validating.
1163:
1164: /** Add default attributes and validate. */
1165: protected void addDTDDefaultAttrsAndValidate(QName elementName,
1166: int elementIndex, XMLAttributes attributes)
1167: throws XNIException {
1168:
1169: // is there anything to do?
1170: if (elementIndex == -1 || fDTDGrammar == null) {
1171: return;
1172: }
1173:
1174: //
1175: // Check after all specified attrs are scanned
1176: // (1) report error for REQUIRED attrs that are missing (V_TAGc)
1177: // (2) add default attrs (FIXED and NOT_FIXED)
1178: //
1179: int attlistIndex = fDTDGrammar
1180: .getFirstAttributeDeclIndex(elementIndex);
1181:
1182: while (attlistIndex != -1) {
1183:
1184: fDTDGrammar.getAttributeDecl(attlistIndex, fTempAttDecl);
1185:
1186: if (DEBUG_ATTRIBUTES) {
1187: if (fTempAttDecl != null) {
1188: XMLElementDecl elementDecl = new XMLElementDecl();
1189: fDTDGrammar.getElementDecl(elementIndex,
1190: elementDecl);
1191: System.out.println("element: "
1192: + (elementDecl.name.localpart));
1193: System.out.println("attlistIndex " + attlistIndex
1194: + "\n" + "attName : '"
1195: + (fTempAttDecl.name.localpart) + "'\n"
1196: + "attType : "
1197: + fTempAttDecl.simpleType.type + "\n"
1198: + "attDefaultType : "
1199: + fTempAttDecl.simpleType.defaultType
1200: + "\n" + "attDefaultValue : '"
1201: + fTempAttDecl.simpleType.defaultValue
1202: + "'\n" + attributes.getLength() + "\n");
1203: }
1204: }
1205: String attPrefix = fTempAttDecl.name.prefix;
1206: String attLocalpart = fTempAttDecl.name.localpart;
1207: String attRawName = fTempAttDecl.name.rawname;
1208: String attType = getAttributeTypeName(fTempAttDecl);
1209: int attDefaultType = fTempAttDecl.simpleType.defaultType;
1210: String attValue = null;
1211:
1212: if (fTempAttDecl.simpleType.defaultValue != null) {
1213: attValue = fTempAttDecl.simpleType.defaultValue;
1214: }
1215:
1216: boolean specified = false;
1217: boolean required = attDefaultType == XMLSimpleType.DEFAULT_TYPE_REQUIRED;
1218: boolean cdata = attType == XMLSymbols.fCDATASymbol;
1219:
1220: if (!cdata || required || attValue != null) {
1221: int attrCount = attributes.getLength();
1222: for (int i = 0; i < attrCount; i++) {
1223: if (attributes.getQName(i) == attRawName) {
1224: specified = true;
1225: break;
1226: }
1227: }
1228: }
1229:
1230: if (!specified) {
1231: if (required) {
1232: if (fPerformValidation) {
1233: Object[] args = { elementName.localpart,
1234: attRawName };
1235: fErrorReporter.reportError(
1236: XMLMessageFormatter.XML_DOMAIN,
1237: "MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED",
1238: args, XMLErrorReporter.SEVERITY_ERROR);
1239: }
1240: } else if (attValue != null) {
1241: if (fPerformValidation
1242: && fGrammarBucket.getStandalone()) {
1243: if (fDTDGrammar
1244: .getAttributeDeclIsExternal(attlistIndex)) {
1245:
1246: Object[] args = { elementName.localpart,
1247: attRawName };
1248: fErrorReporter
1249: .reportError(
1250: XMLMessageFormatter.XML_DOMAIN,
1251: "MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED",
1252: args,
1253: XMLErrorReporter.SEVERITY_ERROR);
1254: }
1255: }
1256:
1257: // add namespace information
1258: if (fNamespaces) {
1259: int index = attRawName.indexOf(':');
1260: if (index != -1) {
1261: attPrefix = attRawName.substring(0, index);
1262: attPrefix = fSymbolTable
1263: .addSymbol(attPrefix);
1264: attLocalpart = attRawName
1265: .substring(index + 1);
1266: attLocalpart = fSymbolTable
1267: .addSymbol(attLocalpart);
1268: }
1269: }
1270:
1271: // add attribute
1272: fTempQName.setValues(attPrefix, attLocalpart,
1273: attRawName, fTempAttDecl.name.uri);
1274: int newAttr = attributes.addAttribute(fTempQName,
1275: attType, attValue);
1276: }
1277: }
1278: // get next att decl in the Grammar for this element
1279: attlistIndex = fDTDGrammar
1280: .getNextAttributeDeclIndex(attlistIndex);
1281: }
1282:
1283: // now iterate through the expanded attributes for
1284: // 1. if every attribute seen is declared in the DTD
1285: // 2. check if the VC: default_fixed holds
1286: // 3. validate every attribute.
1287: int attrCount = attributes.getLength();
1288: for (int i = 0; i < attrCount; i++) {
1289: String attrRawName = attributes.getQName(i);
1290: boolean declared = false;
1291: if (fPerformValidation) {
1292: if (fGrammarBucket.getStandalone()) {
1293: // check VC: Standalone Document Declaration, entities
1294: // references appear in the document.
1295: // REVISIT: this can be combined to a single check in
1296: // startEntity if we add one more argument in
1297: // startEnity, inAttrValue
1298: String nonNormalizedValue = attributes
1299: .getNonNormalizedValue(i);
1300: if (nonNormalizedValue != null) {
1301: String entityName = getExternalEntityRefInAttrValue(nonNormalizedValue);
1302: if (entityName != null) {
1303: fErrorReporter
1304: .reportError(
1305: XMLMessageFormatter.XML_DOMAIN,
1306: "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE",
1307: new Object[] { entityName },
1308: XMLErrorReporter.SEVERITY_ERROR);
1309: }
1310: }
1311: }
1312: }
1313: int attDefIndex = -1;
1314: int position = fDTDGrammar
1315: .getFirstAttributeDeclIndex(elementIndex);
1316: while (position != -1) {
1317: fDTDGrammar.getAttributeDecl(position, fTempAttDecl);
1318: if (fTempAttDecl.name.rawname == attrRawName) {
1319: // found the match att decl,
1320: attDefIndex = position;
1321: declared = true;
1322: break;
1323: }
1324: position = fDTDGrammar
1325: .getNextAttributeDeclIndex(position);
1326: }
1327: if (!declared) {
1328: if (fPerformValidation) {
1329: // REVISIT - cache the elem/attr tuple so that we only
1330: // give this error once for each unique occurrence
1331: Object[] args = { elementName.rawname, attrRawName };
1332:
1333: fErrorReporter.reportError(
1334: XMLMessageFormatter.XML_DOMAIN,
1335: "MSG_ATTRIBUTE_NOT_DECLARED", args,
1336: XMLErrorReporter.SEVERITY_ERROR);
1337: }
1338: continue;
1339: }
1340: // attribute is declared
1341:
1342: // fTempAttDecl should have the right value set now, so
1343: // the following is not needed
1344: // fGrammar.getAttributeDecl(attDefIndex,fTempAttDecl);
1345:
1346: String type = getAttributeTypeName(fTempAttDecl);
1347: attributes.setType(i, type);
1348: attributes.getAugmentations(i).putItem(
1349: Constants.ATTRIBUTE_DECLARED, Boolean.TRUE);
1350:
1351: boolean changedByNormalization = false;
1352: String oldValue = attributes.getValue(i);
1353: String attrValue = oldValue;
1354: if (attributes.isSpecified(i)
1355: && type != XMLSymbols.fCDATASymbol) {
1356: changedByNormalization = normalizeAttrValue(attributes,
1357: i);
1358: attrValue = attributes.getValue(i);
1359: if (fPerformValidation
1360: && fGrammarBucket.getStandalone()
1361: && changedByNormalization
1362: && fDTDGrammar
1363: .getAttributeDeclIsExternal(position)) {
1364: // check VC: Standalone Document Declaration
1365: fErrorReporter
1366: .reportError(
1367: XMLMessageFormatter.XML_DOMAIN,
1368: "MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE",
1369: new Object[] { attrRawName,
1370: oldValue, attrValue },
1371: XMLErrorReporter.SEVERITY_ERROR);
1372: }
1373: }
1374: if (!fPerformValidation) {
1375: continue;
1376: }
1377: if (fTempAttDecl.simpleType.defaultType == XMLSimpleType.DEFAULT_TYPE_FIXED) {
1378: String defaultValue = fTempAttDecl.simpleType.defaultValue;
1379:
1380: if (!attrValue.equals(defaultValue)) {
1381: Object[] args = { elementName.localpart,
1382: attrRawName, attrValue, defaultValue };
1383: fErrorReporter.reportError(
1384: XMLMessageFormatter.XML_DOMAIN,
1385: "MSG_FIXED_ATTVALUE_INVALID", args,
1386: XMLErrorReporter.SEVERITY_ERROR);
1387: }
1388: }
1389:
1390: if (fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENTITY
1391: || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENUMERATION
1392: || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ID
1393: || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_IDREF
1394: || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NMTOKEN
1395: || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NOTATION) {
1396: validateDTDattribute(elementName, attrValue,
1397: fTempAttDecl);
1398: }
1399: } // for all attributes
1400:
1401: } // addDTDDefaultAttrsAndValidate(int,XMLAttrList)
1402:
1403: /** Checks entities in attribute values for standalone VC. */
1404: protected String getExternalEntityRefInAttrValue(
1405: String nonNormalizedValue) {
1406: int valLength = nonNormalizedValue.length();
1407: int ampIndex = nonNormalizedValue.indexOf('&');
1408: while (ampIndex != -1) {
1409: if (ampIndex + 1 < valLength
1410: && nonNormalizedValue.charAt(ampIndex + 1) != '#') {
1411: int semicolonIndex = nonNormalizedValue.indexOf(';',
1412: ampIndex + 1);
1413: String entityName = nonNormalizedValue.substring(
1414: ampIndex + 1, semicolonIndex);
1415: entityName = fSymbolTable.addSymbol(entityName);
1416: int entIndex = fDTDGrammar
1417: .getEntityDeclIndex(entityName);
1418: if (entIndex > -1) {
1419: fDTDGrammar.getEntityDecl(entIndex, fEntityDecl);
1420: if (fEntityDecl.inExternal
1421: || (entityName = getExternalEntityRefInAttrValue(fEntityDecl.value)) != null) {
1422: return entityName;
1423: }
1424: }
1425: }
1426: ampIndex = nonNormalizedValue.indexOf('&', ampIndex + 1);
1427: }
1428: return null;
1429: } // isExternalEntityRefInAttrValue(String):String
1430:
1431: /**
1432: * Validate attributes in DTD fashion.
1433: */
1434: protected void validateDTDattribute(QName element, String attValue,
1435: XMLAttributeDecl attributeDecl) throws XNIException {
1436:
1437: switch (attributeDecl.simpleType.type) {
1438: case XMLSimpleType.TYPE_ENTITY: {
1439: // NOTE: Save this information because invalidStandaloneAttDef
1440: boolean isAlistAttribute = attributeDecl.simpleType.list;
1441:
1442: try {
1443: if (isAlistAttribute) {
1444: fValENTITIES.validate(attValue, fValidationState);
1445: } else {
1446: fValENTITY.validate(attValue, fValidationState);
1447: }
1448: } catch (InvalidDatatypeValueException ex) {
1449: fErrorReporter.reportError(
1450: XMLMessageFormatter.XML_DOMAIN, ex.getKey(), ex
1451: .getArgs(),
1452: XMLErrorReporter.SEVERITY_ERROR);
1453:
1454: }
1455: break;
1456: }
1457:
1458: case XMLSimpleType.TYPE_NOTATION:
1459: case XMLSimpleType.TYPE_ENUMERATION: {
1460: boolean found = false;
1461: String[] enumVals = attributeDecl.simpleType.enumeration;
1462: if (enumVals == null) {
1463: found = false;
1464: } else
1465: for (int i = 0; i < enumVals.length; i++) {
1466: if (attValue == enumVals[i]
1467: || attValue.equals(enumVals[i])) {
1468: found = true;
1469: break;
1470: }
1471: }
1472:
1473: if (!found) {
1474: StringBuffer enumValueString = new StringBuffer();
1475: if (enumVals != null)
1476: for (int i = 0; i < enumVals.length; i++) {
1477: enumValueString.append(enumVals[i] + " ");
1478: }
1479: fErrorReporter.reportError(
1480: XMLMessageFormatter.XML_DOMAIN,
1481: "MSG_ATTRIBUTE_VALUE_NOT_IN_LIST",
1482: new Object[] { attributeDecl.name.rawname,
1483: attValue, enumValueString },
1484: XMLErrorReporter.SEVERITY_ERROR);
1485: }
1486: break;
1487: }
1488:
1489: case XMLSimpleType.TYPE_ID: {
1490: try {
1491: fValID.validate(attValue, fValidationState);
1492: } catch (InvalidDatatypeValueException ex) {
1493: fErrorReporter.reportError(
1494: XMLMessageFormatter.XML_DOMAIN, ex.getKey(), ex
1495: .getArgs(),
1496: XMLErrorReporter.SEVERITY_ERROR);
1497: }
1498: break;
1499: }
1500:
1501: case XMLSimpleType.TYPE_IDREF: {
1502: boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef
1503:
1504: try {
1505: if (isAlistAttribute) {
1506: fValIDRefs.validate(attValue, fValidationState);
1507: } else {
1508: fValIDRef.validate(attValue, fValidationState);
1509: }
1510: } catch (InvalidDatatypeValueException ex) {
1511: if (isAlistAttribute) {
1512: fErrorReporter.reportError(
1513: XMLMessageFormatter.XML_DOMAIN,
1514: "IDREFSInvalid", new Object[] { attValue },
1515: XMLErrorReporter.SEVERITY_ERROR);
1516: } else {
1517: fErrorReporter.reportError(
1518: XMLMessageFormatter.XML_DOMAIN,
1519: ex.getKey(), ex.getArgs(),
1520: XMLErrorReporter.SEVERITY_ERROR);
1521: }
1522:
1523: }
1524: break;
1525: }
1526:
1527: case XMLSimpleType.TYPE_NMTOKEN: {
1528: boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef
1529: //changes fTempAttDef
1530: try {
1531: if (isAlistAttribute) {
1532: fValNMTOKENS.validate(attValue, fValidationState);
1533: } else {
1534: fValNMTOKEN.validate(attValue, fValidationState);
1535: }
1536: } catch (InvalidDatatypeValueException ex) {
1537: if (isAlistAttribute) {
1538: fErrorReporter.reportError(
1539: XMLMessageFormatter.XML_DOMAIN,
1540: "NMTOKENSInvalid",
1541: new Object[] { attValue },
1542: XMLErrorReporter.SEVERITY_ERROR);
1543: } else {
1544: fErrorReporter.reportError(
1545: XMLMessageFormatter.XML_DOMAIN,
1546: "NMTOKENInvalid",
1547: new Object[] { attValue },
1548: XMLErrorReporter.SEVERITY_ERROR);
1549: }
1550: }
1551: break;
1552: }
1553:
1554: } // switch
1555:
1556: } // validateDTDattribute(QName,String,XMLAttributeDecl)
1557:
1558: /** Returns true if invalid standalone attribute definition. */
1559: protected boolean invalidStandaloneAttDef(QName element,
1560: QName attribute) {
1561: // REVISIT: This obviously needs to be fixed! -Ac
1562: boolean state = true;
1563: /*
1564: if (fStandaloneReader == -1) {
1565: return false;
1566: }
1567: // we are normalizing a default att value... this ok?
1568: if (element.rawname == -1) {
1569: return false;
1570: }
1571: return getAttDefIsExternal(element, attribute);
1572: */
1573: return state;
1574: }
1575:
1576: //
1577: // Private methods
1578: //
1579:
1580: /**
1581: * Normalize the attribute value of a non CDATA attributes collapsing
1582: * sequences of space characters (x20)
1583: *
1584: * @param attributes The list of attributes
1585: * @param index The index of the attribute to normalize
1586: */
1587: private boolean normalizeAttrValue(XMLAttributes attributes,
1588: int index) {
1589: // vars
1590: boolean leadingSpace = true;
1591: boolean spaceStart = false;
1592: boolean readingNonSpace = false;
1593: int count = 0;
1594: int eaten = 0;
1595: String attrValue = attributes.getValue(index);
1596: char[] attValue = new char[attrValue.length()];
1597:
1598: fBuffer.setLength(0);
1599: attrValue.getChars(0, attrValue.length(), attValue, 0);
1600: for (int i = 0; i < attValue.length; i++) {
1601:
1602: if (attValue[i] == ' ') {
1603:
1604: // now the tricky part
1605: if (readingNonSpace) {
1606: spaceStart = true;
1607: readingNonSpace = false;
1608: }
1609:
1610: if (spaceStart && !leadingSpace) {
1611: spaceStart = false;
1612: fBuffer.append(attValue[i]);
1613: count++;
1614: } else {
1615: if (leadingSpace || !spaceStart) {
1616: eaten++;
1617: /*** BUG #3512 ***
1618: int entityCount = attributes.getEntityCount(index);
1619: for (int j = 0; j < entityCount; j++) {
1620: int offset = attributes.getEntityOffset(index, j);
1621: int length = attributes.getEntityLength(index, j);
1622: if (offset <= i-eaten+1) {
1623: if (offset+length >= i-eaten+1) {
1624: if (length > 0)
1625: length--;
1626: }
1627: }
1628: else {
1629: if (offset > 0)
1630: offset--;
1631: }
1632: attributes.setEntityOffset(index, j, offset);
1633: attributes.setEntityLength(index, j, length);
1634: }
1635: /***/
1636: }
1637: }
1638:
1639: } else {
1640: readingNonSpace = true;
1641: spaceStart = false;
1642: leadingSpace = false;
1643: fBuffer.append(attValue[i]);
1644: count++;
1645: }
1646: }
1647:
1648: // check if the last appended character is a space.
1649: if (count > 0 && fBuffer.charAt(count - 1) == ' ') {
1650: fBuffer.setLength(count - 1);
1651: /*** BUG #3512 ***
1652: int entityCount = attributes.getEntityCount(index);
1653: for (int j=0; j < entityCount; j++) {
1654: int offset = attributes.getEntityOffset(index, j);
1655: int length = attributes.getEntityLength(index, j);
1656: if (offset < count-1) {
1657: if (offset+length == count) {
1658: length--;
1659: }
1660: }
1661: else {
1662: offset--;
1663: }
1664: attributes.setEntityOffset(index, j, offset);
1665: attributes.setEntityLength(index, j, length);
1666: }
1667: /***/
1668: }
1669: String newValue = fBuffer.toString();
1670: attributes.setValue(index, newValue);
1671: return !attrValue.equals(newValue);
1672: }
1673:
1674: /** Root element specified. */
1675: private final void rootElementSpecified(QName rootElement)
1676: throws XNIException {
1677: if (fPerformValidation) {
1678: String root1 = fRootElement.rawname;
1679: String root2 = rootElement.rawname;
1680: if (root1 == null || !root1.equals(root2)) {
1681: fErrorReporter.reportError(
1682: XMLMessageFormatter.XML_DOMAIN,
1683: "RootElementTypeMustMatchDoctypedecl",
1684: new Object[] { root1, root2 },
1685: XMLErrorReporter.SEVERITY_ERROR);
1686: }
1687: }
1688: } // rootElementSpecified(QName)
1689:
1690: /**
1691: * Check that the content of an element is valid.
1692: * <p>
1693: * This is the method of primary concern to the validator. This method is called
1694: * upon the scanner reaching the end tag of an element. At that time, the
1695: * element's children must be structurally validated, so it calls this method.
1696: * The index of the element being checked (in the decl pool), is provided as
1697: * well as an array of element name indexes of the children. The validator must
1698: * confirm that this element can have these children in this order.
1699: * <p>
1700: * This can also be called to do 'what if' testing of content models just to see
1701: * if they would be valid.
1702: * <p>
1703: * Note that the element index is an index into the element decl pool, whereas
1704: * the children indexes are name indexes, i.e. into the string pool.
1705: * <p>
1706: * A value of -1 in the children array indicates a PCDATA node. All other
1707: * indexes will be positive and represent child elements. The count can be
1708: * zero, since some elements have the EMPTY content model and that must be
1709: * confirmed.
1710: *
1711: * @param elementIndex The index within the <code>ElementDeclPool</code> of this
1712: * element.
1713: * @param childCount The number of entries in the <code>children</code> array.
1714: * @param children The children of this element.
1715: *
1716: * @return The value -1 if fully valid, else the 0 based index of the child
1717: * that first failed. If the value returned is equal to the number
1718: * of children, then additional content is required to reach a valid
1719: * ending state.
1720: *
1721: * @exception Exception Thrown on error.
1722: */
1723: private int checkContent(int elementIndex, QName[] children,
1724: int childOffset, int childCount) throws XNIException {
1725:
1726: fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl);
1727:
1728: // Get the element name index from the element
1729: final String elementType = fCurrentElement.rawname;
1730:
1731: // Get out the content spec for this element
1732: final int contentType = fCurrentContentSpecType;
1733:
1734: //
1735: // Deal with the possible types of content. We try to optimized here
1736: // by dealing specially with content models that don't require the
1737: // full DFA treatment.
1738: //
1739: if (contentType == XMLElementDecl.TYPE_EMPTY) {
1740: //
1741: // If the child count is greater than zero, then this is
1742: // an error right off the bat at index 0.
1743: //
1744: if (childCount != 0) {
1745: return 0;
1746: }
1747: } else if (contentType == XMLElementDecl.TYPE_ANY) {
1748: //
1749: // This one is open game so we don't pass any judgement on it
1750: // at all. Its assumed to fine since it can hold anything.
1751: //
1752: } else if (contentType == XMLElementDecl.TYPE_MIXED
1753: || contentType == XMLElementDecl.TYPE_CHILDREN) {
1754: // Get the content model for this element, faulting it in if needed
1755: ContentModelValidator cmElem = null;
1756: cmElem = fTempElementDecl.contentModelValidator;
1757: int result = cmElem.validate(children, childOffset,
1758: childCount);
1759: return result;
1760: } else if (contentType == -1) {
1761: //REVISIT
1762: /****
1763: reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED,
1764: XMLMessages.VC_ELEMENT_VALID,
1765: elementType);
1766: /****/
1767: } else if (contentType == XMLElementDecl.TYPE_SIMPLE) {
1768:
1769: //REVISIT
1770: // this should never be reached in the case of DTD validation.
1771:
1772: } else {
1773: //REVISIT
1774: /****
1775: fErrorReporter.reportError(fErrorReporter.getLocator(),
1776: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
1777: ImplementationMessages.VAL_CST,
1778: 0,
1779: null,
1780: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
1781: /****/
1782: }
1783:
1784: // We succeeded
1785: return -1;
1786:
1787: } // checkContent(int,int,QName[]):int
1788:
1789: /** Returns the content spec type for an element index. */
1790: private int getContentSpecType(int elementIndex) {
1791:
1792: int contentSpecType = -1;
1793: if (elementIndex > -1) {
1794: if (fDTDGrammar.getElementDecl(elementIndex,
1795: fTempElementDecl)) {
1796: contentSpecType = fTempElementDecl.type;
1797: }
1798: }
1799: return contentSpecType;
1800: }
1801:
1802: /** Character data in content. */
1803: private void charDataInContent() {
1804:
1805: if (DEBUG_ELEMENT_CHILDREN) {
1806: System.out.println("charDataInContent()");
1807: }
1808: if (fElementChildren.length <= fElementChildrenLength) {
1809: QName[] newarray = new QName[fElementChildren.length * 2];
1810: System.arraycopy(fElementChildren, 0, newarray, 0,
1811: fElementChildren.length);
1812: fElementChildren = newarray;
1813: }
1814: QName qname = fElementChildren[fElementChildrenLength];
1815: if (qname == null) {
1816: for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
1817: fElementChildren[i] = new QName();
1818: }
1819: qname = fElementChildren[fElementChildrenLength];
1820: }
1821: qname.clear();
1822: fElementChildrenLength++;
1823:
1824: } // charDataInCount()
1825:
1826: /** convert attribute type from ints to strings */
1827: private String getAttributeTypeName(XMLAttributeDecl attrDecl) {
1828:
1829: switch (attrDecl.simpleType.type) {
1830: case XMLSimpleType.TYPE_ENTITY: {
1831: return attrDecl.simpleType.list ? XMLSymbols.fENTITIESSymbol
1832: : XMLSymbols.fENTITYSymbol;
1833: }
1834: case XMLSimpleType.TYPE_ENUMERATION: {
1835: StringBuffer buffer = new StringBuffer();
1836: buffer.append('(');
1837: for (int i = 0; i < attrDecl.simpleType.enumeration.length; i++) {
1838: if (i > 0) {
1839: buffer.append("|");
1840: }
1841: buffer.append(attrDecl.simpleType.enumeration[i]);
1842: }
1843: buffer.append(')');
1844: return fSymbolTable.addSymbol(buffer.toString());
1845: }
1846: case XMLSimpleType.TYPE_ID: {
1847: return XMLSymbols.fIDSymbol;
1848: }
1849: case XMLSimpleType.TYPE_IDREF: {
1850: return attrDecl.simpleType.list ? XMLSymbols.fIDREFSSymbol
1851: : XMLSymbols.fIDREFSymbol;
1852: }
1853: case XMLSimpleType.TYPE_NMTOKEN: {
1854: return attrDecl.simpleType.list ? XMLSymbols.fNMTOKENSSymbol
1855: : XMLSymbols.fNMTOKENSymbol;
1856: }
1857: case XMLSimpleType.TYPE_NOTATION: {
1858: return XMLSymbols.fNOTATIONSymbol;
1859: }
1860: }
1861: return XMLSymbols.fCDATASymbol;
1862:
1863: } // getAttributeTypeName(XMLAttributeDecl):String
1864:
1865: /** initialization */
1866: protected void init() {
1867:
1868: // datatype validators
1869: if (fValidation || fDynamicValidation) {
1870: try {
1871: //REVISIT: datatypeRegistry + initialization of datatype
1872: // why do we cast to ListDatatypeValidator?
1873: fValID = fDatatypeValidatorFactory
1874: .getBuiltInDV(XMLSymbols.fIDSymbol);
1875: fValIDRef = fDatatypeValidatorFactory
1876: .getBuiltInDV(XMLSymbols.fIDREFSymbol);
1877: fValIDRefs = fDatatypeValidatorFactory
1878: .getBuiltInDV(XMLSymbols.fIDREFSSymbol);
1879: fValENTITY = fDatatypeValidatorFactory
1880: .getBuiltInDV(XMLSymbols.fENTITYSymbol);
1881: fValENTITIES = fDatatypeValidatorFactory
1882: .getBuiltInDV(XMLSymbols.fENTITIESSymbol);
1883: fValNMTOKEN = fDatatypeValidatorFactory
1884: .getBuiltInDV(XMLSymbols.fNMTOKENSymbol);
1885: fValNMTOKENS = fDatatypeValidatorFactory
1886: .getBuiltInDV(XMLSymbols.fNMTOKENSSymbol);
1887: fValNOTATION = fDatatypeValidatorFactory
1888: .getBuiltInDV(XMLSymbols.fNOTATIONSymbol);
1889:
1890: } catch (Exception e) {
1891: // should never happen
1892: e.printStackTrace(System.err);
1893: }
1894:
1895: }
1896:
1897: } // init()
1898:
1899: /** ensure element stack capacity */
1900: private void ensureStackCapacity(int newElementDepth) {
1901: if (newElementDepth == fElementQNamePartsStack.length) {
1902:
1903: QName[] newStackOfQueue = new QName[newElementDepth * 2];
1904: System.arraycopy(this .fElementQNamePartsStack, 0,
1905: newStackOfQueue, 0, newElementDepth);
1906: fElementQNamePartsStack = newStackOfQueue;
1907:
1908: QName qname = fElementQNamePartsStack[newElementDepth];
1909: if (qname == null) {
1910: for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) {
1911: fElementQNamePartsStack[i] = new QName();
1912: }
1913: }
1914:
1915: int[] newStack = new int[newElementDepth * 2];
1916: System.arraycopy(fElementIndexStack, 0, newStack, 0,
1917: newElementDepth);
1918: fElementIndexStack = newStack;
1919:
1920: newStack = new int[newElementDepth * 2];
1921: System.arraycopy(fContentSpecTypeStack, 0, newStack, 0,
1922: newElementDepth);
1923: fContentSpecTypeStack = newStack;
1924:
1925: }
1926: } // ensureStackCapacity
1927:
1928: //
1929: // Protected methods
1930: //
1931:
1932: /** Handle element
1933: * @return true if validator is removed from the pipeline
1934: */
1935: protected boolean handleStartElement(QName element,
1936: XMLAttributes attributes, Augmentations augs)
1937: throws XNIException {
1938:
1939: // VC: Root Element Type
1940: // see if the root element's name matches the one in DoctypeDecl
1941: if (!fSeenRootElement) {
1942: // REVISIT: Here are current assumptions about validation features
1943: // given that XMLSchema validator is in the pipeline
1944: //
1945: // http://xml.org/sax/features/validation = true
1946: // http://apache.org/xml/features/validation/schema = true
1947: //
1948: // [1] XML instance document only has reference to a DTD
1949: // Outcome: report validation errors only against dtd.
1950: //
1951: // [2] XML instance document has only XML Schema grammars:
1952: // Outcome: report validation errors only against schemas (no errors produced from DTD validator)
1953: //
1954: // [3] XML instance document has DTD and XML schemas:
1955: // [a] if schema language is not set outcome - validation errors reported against both grammars: DTD and schemas.
1956: // [b] if schema language is set to XML Schema - do not report validation errors
1957: //
1958: // if dynamic validation is on
1959: // validate only against grammar we've found (depending on settings
1960: // for schema feature)
1961: //
1962: //
1963: fPerformValidation = validate();
1964: fSeenRootElement = true;
1965: fValidationManager.setEntityState(fDTDGrammar);
1966: fValidationManager.setGrammarFound(fSeenDoctypeDecl);
1967: rootElementSpecified(element);
1968: }
1969: if (fDTDGrammar == null) {
1970:
1971: if (!fPerformValidation) {
1972: fCurrentElementIndex = -1;
1973: fCurrentContentSpecType = -1;
1974: fInElementContent = false;
1975: }
1976: if (fPerformValidation) {
1977: fErrorReporter.reportError(
1978: XMLMessageFormatter.XML_DOMAIN,
1979: "MSG_GRAMMAR_NOT_FOUND",
1980: new Object[] { element.rawname },
1981: XMLErrorReporter.SEVERITY_ERROR);
1982: }
1983: // modify pipeline
1984: if (fDocumentSource != null) {
1985: fDocumentSource.setDocumentHandler(fDocumentHandler);
1986: if (fDocumentHandler != null)
1987: fDocumentHandler.setDocumentSource(fDocumentSource);
1988: return true;
1989: }
1990: } else {
1991: // resolve the element
1992: fCurrentElementIndex = fDTDGrammar
1993: .getElementDeclIndex(element);
1994: //changed here.. new function for getContentSpecType
1995: fCurrentContentSpecType = fDTDGrammar
1996: .getContentSpecType(fCurrentElementIndex);
1997: if (fCurrentContentSpecType == -1 && fPerformValidation) {
1998: fErrorReporter.reportError(
1999: XMLMessageFormatter.XML_DOMAIN,
2000: "MSG_ELEMENT_NOT_DECLARED",
2001: new Object[] { element.rawname },
2002: XMLErrorReporter.SEVERITY_ERROR);
2003: }
2004:
2005: // 0. insert default attributes
2006: // 1. normalize the attributes
2007: // 2. validate the attrivute list.
2008: // TO DO:
2009: //changed here.. also pass element name,
2010: addDTDDefaultAttrsAndValidate(element,
2011: fCurrentElementIndex, attributes);
2012: }
2013:
2014: // set element content state
2015: fInElementContent = fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN;
2016:
2017: // increment the element depth, add this element's
2018: // QName to its enclosing element 's children list
2019: fElementDepth++;
2020: if (fPerformValidation) {
2021: // push current length onto stack
2022: if (fElementChildrenOffsetStack.length <= fElementDepth) {
2023: int newarray[] = new int[fElementChildrenOffsetStack.length * 2];
2024: System
2025: .arraycopy(fElementChildrenOffsetStack, 0,
2026: newarray, 0,
2027: fElementChildrenOffsetStack.length);
2028: fElementChildrenOffsetStack = newarray;
2029: }
2030: fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength;
2031:
2032: // add this element to children
2033: if (fElementChildren.length <= fElementChildrenLength) {
2034: QName[] newarray = new QName[fElementChildrenLength * 2];
2035: System.arraycopy(fElementChildren, 0, newarray, 0,
2036: fElementChildren.length);
2037: fElementChildren = newarray;
2038: }
2039: QName qname = fElementChildren[fElementChildrenLength];
2040: if (qname == null) {
2041: for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
2042: fElementChildren[i] = new QName();
2043: }
2044: qname = fElementChildren[fElementChildrenLength];
2045: }
2046: qname.setValues(element);
2047: fElementChildrenLength++;
2048: }
2049:
2050: // save current element information
2051: fCurrentElement.setValues(element);
2052: ensureStackCapacity(fElementDepth);
2053: fElementQNamePartsStack[fElementDepth]
2054: .setValues(fCurrentElement);
2055: fElementIndexStack[fElementDepth] = fCurrentElementIndex;
2056: fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType;
2057: startNamespaceScope(element, attributes, augs);
2058: return false;
2059:
2060: } // handleStartElement(QName,XMLAttributes)
2061:
2062: protected void startNamespaceScope(QName element,
2063: XMLAttributes attributes, Augmentations augs) {
2064: }
2065:
2066: /** Handle end element. */
2067: protected void handleEndElement(QName element, Augmentations augs,
2068: boolean isEmpty) throws XNIException {
2069:
2070: // decrease element depth
2071: fElementDepth--;
2072:
2073: // validate
2074: if (fPerformValidation) {
2075: int elementIndex = fCurrentElementIndex;
2076: if (elementIndex != -1 && fCurrentContentSpecType != -1) {
2077: QName children[] = fElementChildren;
2078: int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
2079: int childrenLength = fElementChildrenLength
2080: - childrenOffset;
2081: int result = checkContent(elementIndex, children,
2082: childrenOffset, childrenLength);
2083:
2084: if (result != -1) {
2085: fDTDGrammar.getElementDecl(elementIndex,
2086: fTempElementDecl);
2087: if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
2088: fErrorReporter.reportError(
2089: XMLMessageFormatter.XML_DOMAIN,
2090: "MSG_CONTENT_INVALID", new Object[] {
2091: element.rawname, "EMPTY" },
2092: XMLErrorReporter.SEVERITY_ERROR);
2093: } else {
2094: String messageKey = result != childrenLength ? "MSG_CONTENT_INVALID"
2095: : "MSG_CONTENT_INCOMPLETE";
2096: fErrorReporter
2097: .reportError(
2098: XMLMessageFormatter.XML_DOMAIN,
2099: messageKey,
2100: new Object[] {
2101: element.rawname,
2102: fDTDGrammar
2103: .getContentSpecAsString(elementIndex) },
2104: XMLErrorReporter.SEVERITY_ERROR);
2105: }
2106: }
2107: }
2108: fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
2109: }
2110:
2111: endNamespaceScope(fCurrentElement, augs, isEmpty);
2112:
2113: // now pop this element off the top of the element stack
2114: if (fElementDepth < -1) {
2115: throw new RuntimeException("FWK008 Element stack underflow");
2116: }
2117: if (fElementDepth < 0) {
2118: fCurrentElement.clear();
2119: fCurrentElementIndex = -1;
2120: fCurrentContentSpecType = -1;
2121: fInElementContent = false;
2122:
2123: // TO DO : fix this
2124: //
2125: // Check after document is fully parsed
2126: // (1) check that there was an element with a matching id for every
2127: // IDREF and IDREFS attr (V_IDREF0)
2128: //
2129: if (fPerformValidation) {
2130: String value = fValidationState.checkIDRefID();
2131: if (value != null) {
2132: fErrorReporter.reportError(
2133: XMLMessageFormatter.XML_DOMAIN,
2134: "MSG_ELEMENT_WITH_ID_REQUIRED",
2135: new Object[] { value },
2136: XMLErrorReporter.SEVERITY_ERROR);
2137: }
2138: }
2139: return;
2140: }
2141:
2142: // If Namespace enable then localName != rawName
2143: fCurrentElement
2144: .setValues(fElementQNamePartsStack[fElementDepth]);
2145:
2146: fCurrentElementIndex = fElementIndexStack[fElementDepth];
2147: fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth];
2148: fInElementContent = (fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN);
2149:
2150: } // handleEndElement(QName,boolean)
2151:
2152: protected void endNamespaceScope(QName element, Augmentations augs,
2153: boolean isEmpty) {
2154:
2155: // call handlers
2156: if (fDocumentHandler != null && !isEmpty) {
2157: // NOTE: The binding of the element doesn't actually happen
2158: // yet because the namespace binder does that. However,
2159: // if it does it before this point, then the endPrefix-
2160: // Mapping calls get made too soon! As long as the
2161: // rawnames match, we know it'll have a good binding,
2162: // so we can just use the current element. -Ac
2163: fDocumentHandler.endElement(fCurrentElement, augs);
2164: }
2165: }
2166:
2167: // returns whether a character is space according to the
2168: // version of XML this validator supports.
2169: protected boolean isSpace(int c) {
2170: return XMLChar.isSpace(c);
2171: } // isSpace(int): boolean
2172:
2173: public boolean characterData(String data, Augmentations augs) {
2174: characters(new XMLString(data.toCharArray(), 0, data.length()),
2175: augs);
2176: return true;
2177: }
2178:
2179: } // class XMLDTDValidator
|