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 java.util.Enumeration;
0021: import java.util.Hashtable;
0022: import java.util.Locale;
0023: import java.util.StringTokenizer;
0024: import java.util.Vector;
0025:
0026: import org.apache.xerces.impl.Constants;
0027: import org.apache.xerces.impl.XMLErrorReporter;
0028: import org.apache.xerces.impl.msg.XMLMessageFormatter;
0029: import org.apache.xerces.util.SymbolTable;
0030: import org.apache.xerces.util.XMLChar;
0031: import org.apache.xerces.util.XMLSymbols;
0032: import org.apache.xerces.xni.Augmentations;
0033: import org.apache.xerces.xni.XMLDTDContentModelHandler;
0034: import org.apache.xerces.xni.XMLDTDHandler;
0035: import org.apache.xerces.xni.XMLLocator;
0036: import org.apache.xerces.xni.XMLResourceIdentifier;
0037: import org.apache.xerces.xni.XMLString;
0038: import org.apache.xerces.xni.XNIException;
0039: import org.apache.xerces.xni.grammars.Grammar;
0040: import org.apache.xerces.xni.grammars.XMLGrammarDescription;
0041: import org.apache.xerces.xni.grammars.XMLGrammarPool;
0042: import org.apache.xerces.xni.parser.XMLComponent;
0043: import org.apache.xerces.xni.parser.XMLComponentManager;
0044: import org.apache.xerces.xni.parser.XMLConfigurationException;
0045: import org.apache.xerces.xni.parser.XMLDTDContentModelFilter;
0046: import org.apache.xerces.xni.parser.XMLDTDContentModelSource;
0047: import org.apache.xerces.xni.parser.XMLDTDFilter;
0048: import org.apache.xerces.xni.parser.XMLDTDSource;
0049:
0050: /**
0051: * The DTD processor. The processor implements a DTD
0052: * filter: receiving DTD events from the DTD scanner; validating
0053: * the content and structure; building a grammar, if applicable;
0054: * and notifying the DTDHandler of the information resulting from the
0055: * process.
0056: * <p>
0057: * This component requires the following features and properties from the
0058: * component manager that uses it:
0059: * <ul>
0060: * <li>http://xml.org/sax/features/namespaces</li>
0061: * <li>http://apache.org/xml/properties/internal/symbol-table</li>
0062: * <li>http://apache.org/xml/properties/internal/error-reporter</li>
0063: * <li>http://apache.org/xml/properties/internal/grammar-pool</li>
0064: * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
0065: * </ul>
0066: *
0067: * @xerces.internal
0068: *
0069: * @author Neil Graham, IBM
0070: *
0071: * @version $Id: XMLDTDProcessor.java 572055 2007-09-02 17:55:43Z mrglavas $
0072: */
0073: public class XMLDTDProcessor implements XMLComponent, XMLDTDFilter,
0074: XMLDTDContentModelFilter {
0075:
0076: //
0077: // Constants
0078: //
0079:
0080: /** Top level scope (-1). */
0081: private static final int TOP_LEVEL_SCOPE = -1;
0082:
0083: // feature identifiers
0084:
0085: /** Feature identifier: validation. */
0086: protected static final String VALIDATION = Constants.SAX_FEATURE_PREFIX
0087: + Constants.VALIDATION_FEATURE;
0088:
0089: /** Feature identifier: notify character references. */
0090: protected static final String NOTIFY_CHAR_REFS = Constants.XERCES_FEATURE_PREFIX
0091: + Constants.NOTIFY_CHAR_REFS_FEATURE;
0092:
0093: /** Feature identifier: warn on duplicate attdef */
0094: protected static final String WARN_ON_DUPLICATE_ATTDEF = Constants.XERCES_FEATURE_PREFIX
0095: + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE;
0096:
0097: /** Feature identifier: warn on undeclared element referenced in content model. */
0098: protected static final String WARN_ON_UNDECLARED_ELEMDEF = Constants.XERCES_FEATURE_PREFIX
0099: + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE;
0100:
0101: protected static final String PARSER_SETTINGS = Constants.XERCES_FEATURE_PREFIX
0102: + Constants.PARSER_SETTINGS;
0103:
0104: // property identifiers
0105:
0106: /** Property identifier: symbol table. */
0107: protected static final String SYMBOL_TABLE = Constants.XERCES_PROPERTY_PREFIX
0108: + Constants.SYMBOL_TABLE_PROPERTY;
0109:
0110: /** Property identifier: error reporter. */
0111: protected static final String ERROR_REPORTER = Constants.XERCES_PROPERTY_PREFIX
0112: + Constants.ERROR_REPORTER_PROPERTY;
0113:
0114: /** Property identifier: grammar pool. */
0115: protected static final String GRAMMAR_POOL = Constants.XERCES_PROPERTY_PREFIX
0116: + Constants.XMLGRAMMAR_POOL_PROPERTY;
0117:
0118: /** Property identifier: validator . */
0119: protected static final String DTD_VALIDATOR = Constants.XERCES_PROPERTY_PREFIX
0120: + Constants.DTD_VALIDATOR_PROPERTY;
0121:
0122: // recognized features and properties
0123:
0124: /** Recognized features. */
0125: private static final String[] RECOGNIZED_FEATURES = { VALIDATION,
0126: WARN_ON_DUPLICATE_ATTDEF, WARN_ON_UNDECLARED_ELEMDEF,
0127: NOTIFY_CHAR_REFS, };
0128:
0129: /** Feature defaults. */
0130: private static final Boolean[] FEATURE_DEFAULTS = { null,
0131: Boolean.FALSE, Boolean.FALSE, null, };
0132:
0133: /** Recognized properties. */
0134: private static final String[] RECOGNIZED_PROPERTIES = {
0135: SYMBOL_TABLE, ERROR_REPORTER, GRAMMAR_POOL, DTD_VALIDATOR, };
0136:
0137: /** Property defaults. */
0138: private static final Object[] PROPERTY_DEFAULTS = { null, null,
0139: null, null, };
0140:
0141: // debugging
0142:
0143: //
0144: // Data
0145: //
0146:
0147: // features
0148:
0149: /** Validation. */
0150: protected boolean fValidation;
0151:
0152: /** Validation against only DTD */
0153: protected boolean fDTDValidation;
0154:
0155: /** warn on duplicate attribute definition, this feature works only when validation is true */
0156: protected boolean fWarnDuplicateAttdef;
0157:
0158: /** warn on undeclared element referenced in content model, this feature only works when valiation is true */
0159: protected boolean fWarnOnUndeclaredElemdef;
0160:
0161: // properties
0162:
0163: /** Symbol table. */
0164: protected SymbolTable fSymbolTable;
0165:
0166: /** Error reporter. */
0167: protected XMLErrorReporter fErrorReporter;
0168:
0169: /** Grammar bucket. */
0170: protected DTDGrammarBucket fGrammarBucket;
0171:
0172: // the validator to which we look for our grammar bucket (the
0173: // validator needs to hold the bucket so that it can initialize
0174: // the grammar with details like whether it's for a standalone document...
0175: protected XMLDTDValidator fValidator;
0176:
0177: // the grammar pool we'll try to add the grammar to:
0178: protected XMLGrammarPool fGrammarPool;
0179:
0180: // what's our Locale?
0181: protected Locale fLocale;
0182:
0183: // handlers
0184:
0185: /** DTD handler. */
0186: protected XMLDTDHandler fDTDHandler;
0187:
0188: /** DTD source. */
0189: protected XMLDTDSource fDTDSource;
0190:
0191: /** DTD content model handler. */
0192: protected XMLDTDContentModelHandler fDTDContentModelHandler;
0193:
0194: /** DTD content model source. */
0195: protected XMLDTDContentModelSource fDTDContentModelSource;
0196:
0197: // grammars
0198:
0199: /** DTD Grammar. */
0200: protected DTDGrammar fDTDGrammar;
0201:
0202: // state
0203:
0204: /** Perform validation. */
0205: private boolean fPerformValidation;
0206:
0207: /** True if in an ignore conditional section of the DTD. */
0208: protected boolean fInDTDIgnore;
0209:
0210: // information regarding the current element
0211:
0212: // validation states
0213:
0214: /** Mixed. */
0215: private boolean fMixed;
0216:
0217: // temporary variables
0218:
0219: /** Temporary entity declaration. */
0220: private final XMLEntityDecl fEntityDecl = new XMLEntityDecl();
0221:
0222: /** Notation declaration hash. */
0223: private final Hashtable fNDataDeclNotations = new Hashtable();
0224:
0225: /** DTD element declaration name. */
0226: private String fDTDElementDeclName = null;
0227:
0228: /** Mixed element type "hash". */
0229: private final Vector fMixedElementTypes = new Vector();
0230:
0231: /** Element declarations in DTD. */
0232: private final Vector fDTDElementDecls = new Vector();
0233:
0234: // to check for duplicate ID or ANNOTATION attribute declare in
0235: // ATTLIST, and misc VCs
0236:
0237: /** ID attribute names. */
0238: private Hashtable fTableOfIDAttributeNames;
0239:
0240: /** NOTATION attribute names. */
0241: private Hashtable fTableOfNOTATIONAttributeNames;
0242:
0243: /** NOTATION enumeration values. */
0244: private Hashtable fNotationEnumVals;
0245:
0246: //
0247: // Constructors
0248: //
0249:
0250: /** Default constructor. */
0251: public XMLDTDProcessor() {
0252:
0253: // initialize data
0254:
0255: } // <init>()
0256:
0257: //
0258: // XMLComponent methods
0259: //
0260:
0261: /*
0262: * Resets the component. The component can query the component manager
0263: * about any features and properties that affect the operation of the
0264: * component.
0265: *
0266: * @param componentManager The component manager.
0267: *
0268: * @throws SAXException Thrown by component on finitialization error.
0269: * For example, if a feature or property is
0270: * required for the operation of the component, the
0271: * component manager may throw a
0272: * SAXNotRecognizedException or a
0273: * SAXNotSupportedException.
0274: */
0275: public void reset(XMLComponentManager componentManager)
0276: throws XMLConfigurationException {
0277:
0278: boolean parser_settings;
0279: try {
0280: parser_settings = componentManager
0281: .getFeature(PARSER_SETTINGS);
0282: } catch (XMLConfigurationException e) {
0283: parser_settings = true;
0284: }
0285:
0286: if (!parser_settings) {
0287: // parser settings have not been changed
0288: reset();
0289: return;
0290: }
0291:
0292: // sax features
0293: try {
0294: fValidation = componentManager.getFeature(VALIDATION);
0295: } catch (XMLConfigurationException e) {
0296: fValidation = false;
0297: }
0298: try {
0299: fDTDValidation = !(componentManager
0300: .getFeature(Constants.XERCES_FEATURE_PREFIX
0301: + Constants.SCHEMA_VALIDATION_FEATURE));
0302: } catch (XMLConfigurationException e) {
0303: // must be in a schema-less configuration!
0304: fDTDValidation = true;
0305: }
0306:
0307: // Xerces features
0308:
0309: try {
0310: fWarnDuplicateAttdef = componentManager
0311: .getFeature(WARN_ON_DUPLICATE_ATTDEF);
0312: } catch (XMLConfigurationException e) {
0313: fWarnDuplicateAttdef = false;
0314: }
0315: try {
0316: fWarnOnUndeclaredElemdef = componentManager
0317: .getFeature(WARN_ON_UNDECLARED_ELEMDEF);
0318: } catch (XMLConfigurationException e) {
0319: fWarnOnUndeclaredElemdef = false;
0320: }
0321:
0322: // get needed components
0323: fErrorReporter = (XMLErrorReporter) componentManager
0324: .getProperty(Constants.XERCES_PROPERTY_PREFIX
0325: + Constants.ERROR_REPORTER_PROPERTY);
0326: fSymbolTable = (SymbolTable) componentManager
0327: .getProperty(Constants.XERCES_PROPERTY_PREFIX
0328: + Constants.SYMBOL_TABLE_PROPERTY);
0329: try {
0330: fGrammarPool = (XMLGrammarPool) componentManager
0331: .getProperty(GRAMMAR_POOL);
0332: } catch (XMLConfigurationException e) {
0333: fGrammarPool = null;
0334: }
0335: try {
0336: fValidator = (XMLDTDValidator) componentManager
0337: .getProperty(DTD_VALIDATOR);
0338: } catch (XMLConfigurationException e) {
0339: fValidator = null;
0340: } catch (ClassCastException e) {
0341: fValidator = null;
0342: }
0343: // we get our grammarBucket from the validator...
0344: if (fValidator != null) {
0345: fGrammarBucket = fValidator.getGrammarBucket();
0346: } else {
0347: fGrammarBucket = null;
0348: }
0349: reset();
0350:
0351: } // reset(XMLComponentManager)
0352:
0353: protected void reset() {
0354: // clear grammars
0355: fDTDGrammar = null;
0356: // initialize state
0357: fInDTDIgnore = false;
0358:
0359: fNDataDeclNotations.clear();
0360:
0361: // datatype validators
0362: if (fValidation) {
0363:
0364: if (fNotationEnumVals == null) {
0365: fNotationEnumVals = new Hashtable();
0366: }
0367: fNotationEnumVals.clear();
0368:
0369: fTableOfIDAttributeNames = new Hashtable();
0370: fTableOfNOTATIONAttributeNames = new Hashtable();
0371: }
0372:
0373: }
0374:
0375: /**
0376: * Returns a list of feature identifiers that are recognized by
0377: * this component. This method may return null if no features
0378: * are recognized by this component.
0379: */
0380: public String[] getRecognizedFeatures() {
0381: return (String[]) (RECOGNIZED_FEATURES.clone());
0382: } // getRecognizedFeatures():String[]
0383:
0384: /**
0385: * Sets the state of a feature. This method is called by the component
0386: * manager any time after reset when a feature changes state.
0387: * <p>
0388: * <strong>Note:</strong> Components should silently ignore features
0389: * that do not affect the operation of the component.
0390: *
0391: * @param featureId The feature identifier.
0392: * @param state The state of the feature.
0393: *
0394: * @throws SAXNotRecognizedException The component should not throw
0395: * this exception.
0396: * @throws SAXNotSupportedException The component should not throw
0397: * this exception.
0398: */
0399: public void setFeature(String featureId, boolean state)
0400: throws XMLConfigurationException {
0401: } // setFeature(String,boolean)
0402:
0403: /**
0404: * Returns a list of property identifiers that are recognized by
0405: * this component. This method may return null if no properties
0406: * are recognized by this component.
0407: */
0408: public String[] getRecognizedProperties() {
0409: return (String[]) (RECOGNIZED_PROPERTIES.clone());
0410: } // getRecognizedProperties():String[]
0411:
0412: /**
0413: * Sets the value of a property. This method is called by the component
0414: * manager any time after reset when a property changes value.
0415: * <p>
0416: * <strong>Note:</strong> Components should silently ignore properties
0417: * that do not affect the operation of the component.
0418: *
0419: * @param propertyId The property identifier.
0420: * @param value The value of the property.
0421: *
0422: * @throws SAXNotRecognizedException The component should not throw
0423: * this exception.
0424: * @throws SAXNotSupportedException The component should not throw
0425: * this exception.
0426: */
0427: public void setProperty(String propertyId, Object value)
0428: throws XMLConfigurationException {
0429: } // setProperty(String,Object)
0430:
0431: /**
0432: * Returns the default state for a feature, or null if this
0433: * component does not want to report a default value for this
0434: * feature.
0435: *
0436: * @param featureId The feature identifier.
0437: *
0438: * @since Xerces 2.2.0
0439: */
0440: public Boolean getFeatureDefault(String featureId) {
0441: for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
0442: if (RECOGNIZED_FEATURES[i].equals(featureId)) {
0443: return FEATURE_DEFAULTS[i];
0444: }
0445: }
0446: return null;
0447: } // getFeatureDefault(String):Boolean
0448:
0449: /**
0450: * Returns the default state for a property, or null if this
0451: * component does not want to report a default value for this
0452: * property.
0453: *
0454: * @param propertyId The property identifier.
0455: *
0456: * @since Xerces 2.2.0
0457: */
0458: public Object getPropertyDefault(String propertyId) {
0459: for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
0460: if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
0461: return PROPERTY_DEFAULTS[i];
0462: }
0463: }
0464: return null;
0465: } // getPropertyDefault(String):Object
0466:
0467: //
0468: // XMLDTDSource methods
0469: //
0470:
0471: /**
0472: * Sets the DTD handler.
0473: *
0474: * @param dtdHandler The DTD handler.
0475: */
0476: public void setDTDHandler(XMLDTDHandler dtdHandler) {
0477: fDTDHandler = dtdHandler;
0478: } // setDTDHandler(XMLDTDHandler)
0479:
0480: /**
0481: * Returns the DTD handler.
0482: *
0483: * @return The DTD handler.
0484: */
0485: public XMLDTDHandler getDTDHandler() {
0486: return fDTDHandler;
0487: } // getDTDHandler(): XMLDTDHandler
0488:
0489: //
0490: // XMLDTDContentModelSource methods
0491: //
0492:
0493: /**
0494: * Sets the DTD content model handler.
0495: *
0496: * @param dtdContentModelHandler The DTD content model handler.
0497: */
0498: public void setDTDContentModelHandler(
0499: XMLDTDContentModelHandler dtdContentModelHandler) {
0500: fDTDContentModelHandler = dtdContentModelHandler;
0501: } // setDTDContentModelHandler(XMLDTDContentModelHandler)
0502:
0503: /**
0504: * Gets the DTD content model handler.
0505: *
0506: * @return dtdContentModelHandler The DTD content model handler.
0507: */
0508: public XMLDTDContentModelHandler getDTDContentModelHandler() {
0509: return fDTDContentModelHandler;
0510: } // getDTDContentModelHandler(): XMLDTDContentModelHandler
0511:
0512: //
0513: // XMLDTDContentModelHandler and XMLDTDHandler methods
0514: //
0515:
0516: /**
0517: * The start of the DTD external subset.
0518: *
0519: * @param augs Additional information that may include infoset
0520: * augmentations.
0521: *
0522: * @throws XNIException Thrown by handler to signal an error.
0523: */
0524: public void startExternalSubset(XMLResourceIdentifier identifier,
0525: Augmentations augs) throws XNIException {
0526: if (fDTDGrammar != null)
0527: fDTDGrammar.startExternalSubset(identifier, augs);
0528: if (fDTDHandler != null) {
0529: fDTDHandler.startExternalSubset(identifier, augs);
0530: }
0531: }
0532:
0533: /**
0534: * The end of the DTD external subset.
0535: *
0536: * @param augs Additional information that may include infoset
0537: * augmentations.
0538: *
0539: * @throws XNIException Thrown by handler to signal an error.
0540: */
0541: public void endExternalSubset(Augmentations augs)
0542: throws XNIException {
0543: if (fDTDGrammar != null)
0544: fDTDGrammar.endExternalSubset(augs);
0545: if (fDTDHandler != null) {
0546: fDTDHandler.endExternalSubset(augs);
0547: }
0548: }
0549:
0550: /**
0551: * Check standalone entity reference.
0552: * Made static to make common between the validator and loader.
0553: *
0554: * @param name
0555: *@param grammar grammar to which entity belongs
0556: * @param tempEntityDecl empty entity declaration to put results in
0557: * @param errorReporter error reporter to send errors to
0558: *
0559: * @throws XNIException Thrown by application to signal an error.
0560: */
0561: protected static void checkStandaloneEntityRef(String name,
0562: DTDGrammar grammar, XMLEntityDecl tempEntityDecl,
0563: XMLErrorReporter errorReporter) throws XNIException {
0564: // check VC: Standalone Document Declartion, entities references appear in the document.
0565: int entIndex = grammar.getEntityDeclIndex(name);
0566: if (entIndex > -1) {
0567: grammar.getEntityDecl(entIndex, tempEntityDecl);
0568: if (tempEntityDecl.inExternal) {
0569: errorReporter
0570: .reportError(
0571: XMLMessageFormatter.XML_DOMAIN,
0572: "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE",
0573: new Object[] { name },
0574: XMLErrorReporter.SEVERITY_ERROR);
0575: }
0576: }
0577: }
0578:
0579: /**
0580: * A comment.
0581: *
0582: * @param text The text in the comment.
0583: * @param augs Additional information that may include infoset augmentations
0584: *
0585: * @throws XNIException Thrown by application to signal an error.
0586: */
0587: public void comment(XMLString text, Augmentations augs)
0588: throws XNIException {
0589:
0590: // call handlers
0591: if (fDTDGrammar != null)
0592: fDTDGrammar.comment(text, augs);
0593: if (fDTDHandler != null) {
0594: fDTDHandler.comment(text, augs);
0595: }
0596:
0597: } // comment(XMLString)
0598:
0599: /**
0600: * A processing instruction. Processing instructions consist of a
0601: * target name and, optionally, text data. The data is only meaningful
0602: * to the application.
0603: * <p>
0604: * Typically, a processing instruction's data will contain a series
0605: * of pseudo-attributes. These pseudo-attributes follow the form of
0606: * element attributes but are <strong>not</strong> parsed or presented
0607: * to the application as anything other than text. The application is
0608: * responsible for parsing the data.
0609: *
0610: * @param target The target.
0611: * @param data The data or null if none specified.
0612: * @param augs Additional information that may include infoset augmentations
0613: *
0614: * @throws XNIException Thrown by handler to signal an error.
0615: */
0616: public void processingInstruction(String target, XMLString data,
0617: Augmentations augs) throws XNIException {
0618:
0619: // call handlers
0620: if (fDTDGrammar != null)
0621: fDTDGrammar.processingInstruction(target, data, augs);
0622: if (fDTDHandler != null) {
0623: fDTDHandler.processingInstruction(target, data, augs);
0624: }
0625: } // processingInstruction(String,XMLString)
0626:
0627: //
0628: // XMLDTDHandler methods
0629: //
0630:
0631: /**
0632: * The start of the DTD.
0633: *
0634: * @param locator The document locator, or null if the document
0635: * location cannot be reported during the parsing of
0636: * the document DTD. However, it is <em>strongly</em>
0637: * recommended that a locator be supplied that can
0638: * at least report the base system identifier of the
0639: * DTD.
0640: * @param augs Additional information that may include infoset
0641: * augmentations.
0642: *
0643: * @throws XNIException Thrown by handler to signal an error.
0644: */
0645: public void startDTD(XMLLocator locator, Augmentations augs)
0646: throws XNIException {
0647:
0648: // initialize state
0649: fNDataDeclNotations.clear();
0650: fDTDElementDecls.removeAllElements();
0651:
0652: // the grammar bucket's DTDGrammar will now be the
0653: // one we want, whether we're constructing it or not.
0654: // if we're not constructing it, then we should not have a reference
0655: // to it!
0656: if (!fGrammarBucket.getActiveGrammar().isImmutable()) {
0657: fDTDGrammar = fGrammarBucket.getActiveGrammar();
0658: }
0659:
0660: // call handlers
0661: if (fDTDGrammar != null)
0662: fDTDGrammar.startDTD(locator, augs);
0663: if (fDTDHandler != null) {
0664: fDTDHandler.startDTD(locator, augs);
0665: }
0666:
0667: } // startDTD(XMLLocator)
0668:
0669: /**
0670: * Characters within an IGNORE conditional section.
0671: *
0672: * @param text The ignored text.
0673: * @param augs Additional information that may include infoset
0674: * augmentations.
0675: *
0676: * @throws XNIException Thrown by handler to signal an error.
0677: */
0678: public void ignoredCharacters(XMLString text, Augmentations augs)
0679: throws XNIException {
0680:
0681: // ignored characters in DTD
0682: if (fDTDGrammar != null)
0683: fDTDGrammar.ignoredCharacters(text, augs);
0684: if (fDTDHandler != null) {
0685: fDTDHandler.ignoredCharacters(text, augs);
0686: }
0687: }
0688:
0689: /**
0690: * Notifies of the presence of a TextDecl line in an entity. If present,
0691: * this method will be called immediately following the startParameterEntity call.
0692: * <p>
0693: * <strong>Note:</strong> This method is only called for external
0694: * parameter entities referenced in the DTD.
0695: *
0696: * @param version The XML version, or null if not specified.
0697: * @param encoding The IANA encoding name of the entity.
0698: * @param augs Additional information that may include infoset
0699: * augmentations.
0700: *
0701: * @throws XNIException Thrown by handler to signal an error.
0702: */
0703: public void textDecl(String version, String encoding,
0704: Augmentations augs) throws XNIException {
0705:
0706: // call handlers
0707: if (fDTDGrammar != null)
0708: fDTDGrammar.textDecl(version, encoding, augs);
0709: if (fDTDHandler != null) {
0710: fDTDHandler.textDecl(version, encoding, augs);
0711: }
0712: }
0713:
0714: /**
0715: * This method notifies of the start of a parameter entity. The parameter
0716: * entity name start with a '%' character.
0717: *
0718: * @param name The name of the parameter entity.
0719: * @param identifier The resource identifier.
0720: * @param encoding The auto-detected IANA encoding name of the entity
0721: * stream. This value will be null in those situations
0722: * where the entity encoding is not auto-detected (e.g.
0723: * internal parameter entities).
0724: * @param augs Additional information that may include infoset
0725: * augmentations.
0726: *
0727: * @throws XNIException Thrown by handler to signal an error.
0728: */
0729: public void startParameterEntity(String name,
0730: XMLResourceIdentifier identifier, String encoding,
0731: Augmentations augs) throws XNIException {
0732:
0733: if (fPerformValidation && fDTDGrammar != null
0734: && fGrammarBucket.getStandalone()) {
0735: checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl,
0736: fErrorReporter);
0737: }
0738: // call handlers
0739: if (fDTDGrammar != null)
0740: fDTDGrammar.startParameterEntity(name, identifier,
0741: encoding, augs);
0742: if (fDTDHandler != null) {
0743: fDTDHandler.startParameterEntity(name, identifier,
0744: encoding, augs);
0745: }
0746: }
0747:
0748: /**
0749: * This method notifies the end of a parameter entity. Parameter entity
0750: * names begin with a '%' character.
0751: *
0752: * @param name The name of the parameter entity.
0753: * @param augs Additional information that may include infoset
0754: * augmentations.
0755: *
0756: * @throws XNIException Thrown by handler to signal an error.
0757: */
0758: public void endParameterEntity(String name, Augmentations augs)
0759: throws XNIException {
0760:
0761: // call handlers
0762: if (fDTDGrammar != null)
0763: fDTDGrammar.endParameterEntity(name, augs);
0764: if (fDTDHandler != null) {
0765: fDTDHandler.endParameterEntity(name, augs);
0766: }
0767: }
0768:
0769: /**
0770: * An element declaration.
0771: *
0772: * @param name The name of the element.
0773: * @param contentModel The element content model.
0774: * @param augs Additional information that may include infoset
0775: * augmentations.
0776: *
0777: * @throws XNIException Thrown by handler to signal an error.
0778: */
0779: public void elementDecl(String name, String contentModel,
0780: Augmentations augs) throws XNIException {
0781:
0782: //check VC: Unique Element Declaration
0783: if (fValidation) {
0784: if (fDTDElementDecls.contains(name)) {
0785: fErrorReporter.reportError(
0786: XMLMessageFormatter.XML_DOMAIN,
0787: "MSG_ELEMENT_ALREADY_DECLARED",
0788: new Object[] { name },
0789: XMLErrorReporter.SEVERITY_ERROR);
0790: } else {
0791: fDTDElementDecls.addElement(name);
0792: }
0793: }
0794:
0795: // call handlers
0796: if (fDTDGrammar != null)
0797: fDTDGrammar.elementDecl(name, contentModel, augs);
0798: if (fDTDHandler != null) {
0799: fDTDHandler.elementDecl(name, contentModel, augs);
0800: }
0801:
0802: } // elementDecl(String,String)
0803:
0804: /**
0805: * The start of an attribute list.
0806: *
0807: * @param elementName The name of the element that this attribute
0808: * list is associated with.
0809: * @param augs Additional information that may include infoset
0810: * augmentations.
0811: *
0812: * @throws XNIException Thrown by handler to signal an error.
0813: */
0814: public void startAttlist(String elementName, Augmentations augs)
0815: throws XNIException {
0816:
0817: // call handlers
0818: if (fDTDGrammar != null)
0819: fDTDGrammar.startAttlist(elementName, augs);
0820: if (fDTDHandler != null) {
0821: fDTDHandler.startAttlist(elementName, augs);
0822: }
0823:
0824: } // startAttlist(String)
0825:
0826: /**
0827: * An attribute declaration.
0828: *
0829: * @param elementName The name of the element that this attribute
0830: * is associated with.
0831: * @param attributeName The name of the attribute.
0832: * @param type The attribute type. This value will be one of
0833: * the following: "CDATA", "ENTITY", "ENTITIES",
0834: * "ENUMERATION", "ID", "IDREF", "IDREFS",
0835: * "NMTOKEN", "NMTOKENS", or "NOTATION".
0836: * @param enumeration If the type has the value "ENUMERATION" or
0837: * "NOTATION", this array holds the allowed attribute
0838: * values; otherwise, this array is null.
0839: * @param defaultType The attribute default type. This value will be
0840: * one of the following: "#FIXED", "#IMPLIED",
0841: * "#REQUIRED", or null.
0842: * @param defaultValue The attribute default value, or null if no
0843: * default value is specified.
0844: * @param nonNormalizedDefaultValue The attribute default value with no normalization
0845: * performed, or null if no default value is specified.
0846: * @param augs Additional information that may include infoset
0847: * augmentations.
0848: *
0849: * @throws XNIException Thrown by handler to signal an error.
0850: */
0851: public void attributeDecl(String elementName, String attributeName,
0852: String type, String[] enumeration, String defaultType,
0853: XMLString defaultValue,
0854: XMLString nonNormalizedDefaultValue, Augmentations augs)
0855: throws XNIException {
0856:
0857: if (type != XMLSymbols.fCDATASymbol && defaultValue != null) {
0858: normalizeDefaultAttrValue(defaultValue);
0859: }
0860:
0861: if (fValidation) {
0862:
0863: boolean duplicateAttributeDef = false;
0864:
0865: //Get Grammar index to grammar array
0866: DTDGrammar grammar = (fDTDGrammar != null ? fDTDGrammar
0867: : fGrammarBucket.getActiveGrammar());
0868: int elementIndex = grammar.getElementDeclIndex(elementName);
0869: if (grammar.getAttributeDeclIndex(elementIndex,
0870: attributeName) != -1) {
0871: //more than one attribute definition is provided for the same attribute of a given element type.
0872: duplicateAttributeDef = true;
0873:
0874: //this feature works only when validation is true.
0875: if (fWarnDuplicateAttdef) {
0876: fErrorReporter
0877: .reportError(
0878: XMLMessageFormatter.XML_DOMAIN,
0879: "MSG_DUPLICATE_ATTRIBUTE_DEFINITION",
0880: new Object[] { elementName,
0881: attributeName },
0882: XMLErrorReporter.SEVERITY_WARNING);
0883: }
0884: }
0885:
0886: //
0887: // a) VC: One ID per Element Type, If duplicate ID attribute
0888: // b) VC: ID attribute Default. if there is a declareared attribute
0889: // default for ID it should be of type #IMPLIED or #REQUIRED
0890: if (type == XMLSymbols.fIDSymbol) {
0891: if (defaultValue != null && defaultValue.length != 0) {
0892: if (defaultType == null
0893: || !(defaultType == XMLSymbols.fIMPLIEDSymbol || defaultType == XMLSymbols.fREQUIREDSymbol)) {
0894: fErrorReporter.reportError(
0895: XMLMessageFormatter.XML_DOMAIN,
0896: "IDDefaultTypeInvalid",
0897: new Object[] { attributeName },
0898: XMLErrorReporter.SEVERITY_ERROR);
0899: }
0900: }
0901:
0902: if (!fTableOfIDAttributeNames.containsKey(elementName)) {
0903: fTableOfIDAttributeNames.put(elementName,
0904: attributeName);
0905: } else {
0906: //we should not report an error, when there is duplicate attribute definition for given element type
0907: //according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given
0908: //element type, the first declaration is binding and later declaration are *ignored*. So processor should
0909: //ignore the second declarations, however an application would be warned of the duplicate attribute defintion
0910: // if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true,
0911: // one typical case where this could be a problem, when any XML file
0912: // provide the ID type information through internal subset so that it is available to the parser which read
0913: //only internal subset. Now that attribute declaration(ID Type) can again be part of external parsed entity
0914: //referenced. At that time if parser doesn't make this distinction it will throw an error for VC One ID per
0915: //Element Type, which (second defintion) actually should be ignored. Application behavior may differ on the
0916: //basis of error or warning thrown. - nb.
0917:
0918: if (!duplicateAttributeDef) {
0919: String previousIDAttributeName = (String) fTableOfIDAttributeNames
0920: .get(elementName);//rule a)
0921: fErrorReporter.reportError(
0922: XMLMessageFormatter.XML_DOMAIN,
0923: "MSG_MORE_THAN_ONE_ID_ATTRIBUTE",
0924: new Object[] { elementName,
0925: previousIDAttributeName,
0926: attributeName },
0927: XMLErrorReporter.SEVERITY_ERROR);
0928: }
0929: }
0930: }
0931:
0932: //
0933: // VC: One Notation Per Element Type, should check if there is a
0934: // duplicate NOTATION attribute
0935:
0936: if (type == XMLSymbols.fNOTATIONSymbol) {
0937: // VC: Notation Attributes: all notation names in the
0938: // (attribute) declaration must be declared.
0939: for (int i = 0; i < enumeration.length; i++) {
0940: fNotationEnumVals
0941: .put(enumeration[i], attributeName);
0942: }
0943:
0944: if (fTableOfNOTATIONAttributeNames
0945: .containsKey(elementName) == false) {
0946: fTableOfNOTATIONAttributeNames.put(elementName,
0947: attributeName);
0948: } else {
0949: //we should not report an error, when there is duplicate attribute definition for given element type
0950: //according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given
0951: //element type, the first declaration is binding and later declaration are *ignored*. So processor should
0952: //ignore the second declarations, however an application would be warned of the duplicate attribute defintion
0953: // if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true, Application behavior may differ on the basis of error or
0954: //warning thrown. - nb.
0955:
0956: if (!duplicateAttributeDef) {
0957:
0958: String previousNOTATIONAttributeName = (String) fTableOfNOTATIONAttributeNames
0959: .get(elementName);
0960: fErrorReporter.reportError(
0961: XMLMessageFormatter.XML_DOMAIN,
0962: "MSG_MORE_THAN_ONE_NOTATION_ATTRIBUTE",
0963: new Object[] { elementName,
0964: previousNOTATIONAttributeName,
0965: attributeName },
0966: XMLErrorReporter.SEVERITY_ERROR);
0967: }
0968: }
0969: }
0970:
0971: // VC: No Duplicate Tokens
0972: // XML 1.0 SE Errata - E2
0973: if (type == XMLSymbols.fENUMERATIONSymbol
0974: || type == XMLSymbols.fNOTATIONSymbol) {
0975: outer: for (int i = 0; i < enumeration.length; ++i) {
0976: for (int j = i + 1; j < enumeration.length; ++j) {
0977: if (enumeration[i].equals(enumeration[j])) {
0978: // Only report the first uniqueness violation. There could be others,
0979: // but additional overhead would be incurred tracking unique tokens
0980: // that have already been encountered. -- mrglavas
0981: fErrorReporter
0982: .reportError(
0983: XMLMessageFormatter.XML_DOMAIN,
0984: type == XMLSymbols.fENUMERATIONSymbol ? "MSG_DISTINCT_TOKENS_IN_ENUMERATION"
0985: : "MSG_DISTINCT_NOTATION_IN_ENUMERATION",
0986: new Object[] { elementName,
0987: enumeration[i],
0988: attributeName },
0989: XMLErrorReporter.SEVERITY_ERROR);
0990: break outer;
0991: }
0992: }
0993: }
0994: }
0995:
0996: // VC: Attribute Default Legal
0997: boolean ok = true;
0998: if (defaultValue != null
0999: && (defaultType == null || (defaultType != null && defaultType == XMLSymbols.fFIXEDSymbol))) {
1000:
1001: String value = defaultValue.toString();
1002: if (type == XMLSymbols.fNMTOKENSSymbol
1003: || type == XMLSymbols.fENTITIESSymbol
1004: || type == XMLSymbols.fIDREFSSymbol) {
1005:
1006: StringTokenizer tokenizer = new StringTokenizer(
1007: value, " ");
1008: if (tokenizer.hasMoreTokens()) {
1009: while (true) {
1010: String nmtoken = tokenizer.nextToken();
1011: if (type == XMLSymbols.fNMTOKENSSymbol) {
1012: if (!isValidNmtoken(nmtoken)) {
1013: ok = false;
1014: break;
1015: }
1016: } else if (type == XMLSymbols.fENTITIESSymbol
1017: || type == XMLSymbols.fIDREFSSymbol) {
1018: if (!isValidName(nmtoken)) {
1019: ok = false;
1020: break;
1021: }
1022: }
1023: if (!tokenizer.hasMoreTokens()) {
1024: break;
1025: }
1026: }
1027: }
1028:
1029: } else {
1030: if (type == XMLSymbols.fENTITYSymbol
1031: || type == XMLSymbols.fIDSymbol
1032: || type == XMLSymbols.fIDREFSymbol
1033: || type == XMLSymbols.fNOTATIONSymbol) {
1034:
1035: if (!isValidName(value)) {
1036: ok = false;
1037: }
1038:
1039: } else if (type == XMLSymbols.fNMTOKENSymbol
1040: || type == XMLSymbols.fENUMERATIONSymbol) {
1041:
1042: if (!isValidNmtoken(value)) {
1043: ok = false;
1044: }
1045: }
1046:
1047: if (type == XMLSymbols.fNOTATIONSymbol
1048: || type == XMLSymbols.fENUMERATIONSymbol) {
1049: ok = false;
1050: for (int i = 0; i < enumeration.length; i++) {
1051: if (defaultValue.equals(enumeration[i])) {
1052: ok = true;
1053: }
1054: }
1055: }
1056:
1057: }
1058: if (!ok) {
1059: fErrorReporter.reportError(
1060: XMLMessageFormatter.XML_DOMAIN,
1061: "MSG_ATT_DEFAULT_INVALID", new Object[] {
1062: attributeName, value },
1063: XMLErrorReporter.SEVERITY_ERROR);
1064: }
1065: }
1066: }
1067:
1068: // call handlers
1069: if (fDTDGrammar != null)
1070: fDTDGrammar.attributeDecl(elementName, attributeName, type,
1071: enumeration, defaultType, defaultValue,
1072: nonNormalizedDefaultValue, augs);
1073: if (fDTDHandler != null) {
1074: fDTDHandler.attributeDecl(elementName, attributeName, type,
1075: enumeration, defaultType, defaultValue,
1076: nonNormalizedDefaultValue, augs);
1077: }
1078:
1079: } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations)
1080:
1081: /**
1082: * The end of an attribute list.
1083: *
1084: * @param augs Additional information that may include infoset
1085: * augmentations.
1086: *
1087: * @throws XNIException Thrown by handler to signal an error.
1088: */
1089: public void endAttlist(Augmentations augs) throws XNIException {
1090:
1091: // call handlers
1092: if (fDTDGrammar != null)
1093: fDTDGrammar.endAttlist(augs);
1094: if (fDTDHandler != null) {
1095: fDTDHandler.endAttlist(augs);
1096: }
1097:
1098: } // endAttlist()
1099:
1100: /**
1101: * An internal entity declaration.
1102: *
1103: * @param name The name of the entity. Parameter entity names start with
1104: * '%', whereas the name of a general entity is just the
1105: * entity name.
1106: * @param text The value of the entity.
1107: * @param nonNormalizedText The non-normalized value of the entity. This
1108: * value contains the same sequence of characters that was in
1109: * the internal entity declaration, without any entity
1110: * references expanded.
1111: * @param augs Additional information that may include infoset
1112: * augmentations.
1113: *
1114: * @throws XNIException Thrown by handler to signal an error.
1115: */
1116: public void internalEntityDecl(String name, XMLString text,
1117: XMLString nonNormalizedText, Augmentations augs)
1118: throws XNIException {
1119:
1120: DTDGrammar grammar = (fDTDGrammar != null ? fDTDGrammar
1121: : fGrammarBucket.getActiveGrammar());
1122: int index = grammar.getEntityDeclIndex(name);
1123:
1124: //If the same entity is declared more than once, the first declaration
1125: //encountered is binding, SAX requires only effective(first) declaration
1126: //to be reported to the application
1127:
1128: //REVISIT: Does it make sense to pass duplicate Entity information across
1129: //the pipeline -- nb?
1130:
1131: //its a new entity and hasn't been declared.
1132: if (index == -1) {
1133: //store internal entity declaration in grammar
1134: if (fDTDGrammar != null)
1135: fDTDGrammar.internalEntityDecl(name, text,
1136: nonNormalizedText, augs);
1137: // call handlers
1138: if (fDTDHandler != null) {
1139: fDTDHandler.internalEntityDecl(name, text,
1140: nonNormalizedText, augs);
1141: }
1142: }
1143:
1144: } // internalEntityDecl(String,XMLString,XMLString)
1145:
1146: /**
1147: * An external entity declaration.
1148: *
1149: * @param name The name of the entity. Parameter entity names start
1150: * with '%', whereas the name of a general entity is just
1151: * the entity name.
1152: * @param identifier An object containing all location information
1153: * pertinent to this external entity.
1154: * @param augs Additional information that may include infoset
1155: * augmentations.
1156: *
1157: * @throws XNIException Thrown by handler to signal an error.
1158: */
1159: public void externalEntityDecl(String name,
1160: XMLResourceIdentifier identifier, Augmentations augs)
1161: throws XNIException {
1162:
1163: DTDGrammar grammar = (fDTDGrammar != null ? fDTDGrammar
1164: : fGrammarBucket.getActiveGrammar());
1165: int index = grammar.getEntityDeclIndex(name);
1166:
1167: //If the same entity is declared more than once, the first declaration
1168: //encountered is binding, SAX requires only effective(first) declaration
1169: //to be reported to the application
1170:
1171: //REVISIT: Does it make sense to pass duplicate entity information across
1172: //the pipeline -- nb?
1173:
1174: //its a new entity and hasn't been declared.
1175: if (index == -1) {
1176: //store external entity declaration in grammar
1177: if (fDTDGrammar != null)
1178: fDTDGrammar.externalEntityDecl(name, identifier, augs);
1179: // call handlers
1180: if (fDTDHandler != null) {
1181: fDTDHandler.externalEntityDecl(name, identifier, augs);
1182: }
1183: }
1184:
1185: } // externalEntityDecl(String,XMLResourceIdentifier, Augmentations)
1186:
1187: /**
1188: * An unparsed entity declaration.
1189: *
1190: * @param name The name of the entity.
1191: * @param identifier An object containing all location information
1192: * pertinent to this entity.
1193: * @param notation The name of the notation.
1194: * @param augs Additional information that may include infoset
1195: * augmentations.
1196: *
1197: * @throws XNIException Thrown by handler to signal an error.
1198: */
1199: public void unparsedEntityDecl(String name,
1200: XMLResourceIdentifier identifier, String notation,
1201: Augmentations augs) throws XNIException {
1202:
1203: // VC: Notation declared, in the production of NDataDecl
1204: if (fValidation) {
1205: fNDataDeclNotations.put(name, notation);
1206: }
1207:
1208: // call handlers
1209: if (fDTDGrammar != null)
1210: fDTDGrammar.unparsedEntityDecl(name, identifier, notation,
1211: augs);
1212: if (fDTDHandler != null) {
1213: fDTDHandler.unparsedEntityDecl(name, identifier, notation,
1214: augs);
1215: }
1216:
1217: } // unparsedEntityDecl(String,XMLResourceIdentifier,String,Augmentations)
1218:
1219: /**
1220: * A notation declaration
1221: *
1222: * @param name The name of the notation.
1223: * @param identifier An object containing all location information
1224: * pertinent to this notation.
1225: * @param augs Additional information that may include infoset
1226: * augmentations.
1227: *
1228: * @throws XNIException Thrown by handler to signal an error.
1229: */
1230: public void notationDecl(String name,
1231: XMLResourceIdentifier identifier, Augmentations augs)
1232: throws XNIException {
1233:
1234: // VC: Unique Notation Name
1235: if (fValidation) {
1236: DTDGrammar grammar = (fDTDGrammar != null ? fDTDGrammar
1237: : fGrammarBucket.getActiveGrammar());
1238: if (grammar.getNotationDeclIndex(name) != -1) {
1239: fErrorReporter.reportError(
1240: XMLMessageFormatter.XML_DOMAIN,
1241: "UniqueNotationName", new Object[] { name },
1242: XMLErrorReporter.SEVERITY_ERROR);
1243: }
1244: }
1245:
1246: // call handlers
1247: if (fDTDGrammar != null)
1248: fDTDGrammar.notationDecl(name, identifier, augs);
1249: if (fDTDHandler != null) {
1250: fDTDHandler.notationDecl(name, identifier, augs);
1251: }
1252:
1253: } // notationDecl(String,XMLResourceIdentifier, Augmentations)
1254:
1255: /**
1256: * The start of a conditional section.
1257: *
1258: * @param type The type of the conditional section. This value will
1259: * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE.
1260: * @param augs Additional information that may include infoset
1261: * augmentations.
1262: *
1263: * @throws XNIException Thrown by handler to signal an error.
1264: *
1265: * @see #CONDITIONAL_INCLUDE
1266: * @see #CONDITIONAL_IGNORE
1267: */
1268: public void startConditional(short type, Augmentations augs)
1269: throws XNIException {
1270:
1271: // set state
1272: fInDTDIgnore = type == XMLDTDHandler.CONDITIONAL_IGNORE;
1273:
1274: // call handlers
1275: if (fDTDGrammar != null)
1276: fDTDGrammar.startConditional(type, augs);
1277: if (fDTDHandler != null) {
1278: fDTDHandler.startConditional(type, augs);
1279: }
1280:
1281: } // startConditional(short)
1282:
1283: /**
1284: * The end of a conditional section.
1285: *
1286: * @param augs Additional information that may include infoset
1287: * augmentations.
1288: *
1289: * @throws XNIException Thrown by handler to signal an error.
1290: */
1291: public void endConditional(Augmentations augs) throws XNIException {
1292:
1293: // set state
1294: fInDTDIgnore = false;
1295:
1296: // call handlers
1297: if (fDTDGrammar != null)
1298: fDTDGrammar.endConditional(augs);
1299: if (fDTDHandler != null) {
1300: fDTDHandler.endConditional(augs);
1301: }
1302:
1303: } // endConditional()
1304:
1305: /**
1306: * The end of the DTD.
1307: *
1308: * @param augs Additional information that may include infoset
1309: * augmentations.
1310: *
1311: * @throws XNIException Thrown by handler to signal an error.
1312: */
1313: public void endDTD(Augmentations augs) throws XNIException {
1314:
1315: // save grammar
1316: if (fDTDGrammar != null) {
1317: fDTDGrammar.endDTD(augs);
1318: if (fGrammarPool != null)
1319: fGrammarPool.cacheGrammars(
1320: XMLGrammarDescription.XML_DTD,
1321: new Grammar[] { fDTDGrammar });
1322: }
1323: if (fValidation) {
1324: DTDGrammar grammar = (fDTDGrammar != null ? fDTDGrammar
1325: : fGrammarBucket.getActiveGrammar());
1326:
1327: // VC : Notation Declared. for external entity declaration [Production 76].
1328: Enumeration entities = fNDataDeclNotations.keys();
1329: while (entities.hasMoreElements()) {
1330: String entity = (String) entities.nextElement();
1331: String notation = (String) fNDataDeclNotations
1332: .get(entity);
1333: if (grammar.getNotationDeclIndex(notation) == -1) {
1334: fErrorReporter
1335: .reportError(
1336: XMLMessageFormatter.XML_DOMAIN,
1337: "MSG_NOTATION_NOT_DECLARED_FOR_UNPARSED_ENTITYDECL",
1338: new Object[] { entity, notation },
1339: XMLErrorReporter.SEVERITY_ERROR);
1340: }
1341: }
1342:
1343: // VC: Notation Attributes:
1344: // all notation names in the (attribute) declaration must be declared.
1345: Enumeration notationVals = fNotationEnumVals.keys();
1346: while (notationVals.hasMoreElements()) {
1347: String notation = (String) notationVals.nextElement();
1348: String attributeName = (String) fNotationEnumVals
1349: .get(notation);
1350: if (grammar.getNotationDeclIndex(notation) == -1) {
1351: fErrorReporter
1352: .reportError(
1353: XMLMessageFormatter.XML_DOMAIN,
1354: "MSG_NOTATION_NOT_DECLARED_FOR_NOTATIONTYPE_ATTRIBUTE",
1355: new Object[] { attributeName,
1356: notation },
1357: XMLErrorReporter.SEVERITY_ERROR);
1358: }
1359: }
1360:
1361: // VC: No Notation on Empty Element
1362: // An attribute of type NOTATION must not be declared on an element declared EMPTY.
1363: Enumeration elementsWithNotations = fTableOfNOTATIONAttributeNames
1364: .keys();
1365: while (elementsWithNotations.hasMoreElements()) {
1366: String elementName = (String) elementsWithNotations
1367: .nextElement();
1368: int elementIndex = grammar
1369: .getElementDeclIndex(elementName);
1370: if (grammar.getContentSpecType(elementIndex) == XMLElementDecl.TYPE_EMPTY) {
1371: String attributeName = (String) fTableOfNOTATIONAttributeNames
1372: .get(elementName);
1373: fErrorReporter.reportError(
1374: XMLMessageFormatter.XML_DOMAIN,
1375: "NoNotationOnEmptyElement", new Object[] {
1376: elementName, attributeName },
1377: XMLErrorReporter.SEVERITY_ERROR);
1378: }
1379: }
1380:
1381: // should be safe to release these references
1382: fTableOfIDAttributeNames = null;
1383: fTableOfNOTATIONAttributeNames = null;
1384:
1385: // check whether each element referenced in a content model is declared
1386: if (fWarnOnUndeclaredElemdef) {
1387: checkDeclaredElements(grammar);
1388: }
1389: }
1390:
1391: // call handlers
1392: if (fDTDHandler != null) {
1393: fDTDHandler.endDTD(augs);
1394: }
1395:
1396: } // endDTD()
1397:
1398: // sets the XMLDTDSource of this handler
1399: public void setDTDSource(XMLDTDSource source) {
1400: fDTDSource = source;
1401: } // setDTDSource(XMLDTDSource)
1402:
1403: // returns the XMLDTDSource of this handler
1404: public XMLDTDSource getDTDSource() {
1405: return fDTDSource;
1406: } // getDTDSource(): XMLDTDSource
1407:
1408: //
1409: // XMLDTDContentModelHandler methods
1410: //
1411:
1412: // sets the XMLContentModelDTDSource of this handler
1413: public void setDTDContentModelSource(XMLDTDContentModelSource source) {
1414: fDTDContentModelSource = source;
1415: } // setDTDContentModelSource(XMLDTDContentModelSource)
1416:
1417: // returns the XMLDTDSource of this handler
1418: public XMLDTDContentModelSource getDTDContentModelSource() {
1419: return fDTDContentModelSource;
1420: } // getDTDContentModelSource(): XMLDTDContentModelSource
1421:
1422: /**
1423: * The start of a content model. Depending on the type of the content
1424: * model, specific methods may be called between the call to the
1425: * startContentModel method and the call to the endContentModel method.
1426: *
1427: * @param elementName The name of the element.
1428: * @param augs Additional information that may include infoset
1429: * augmentations.
1430: *
1431: * @throws XNIException Thrown by handler to signal an error.
1432: */
1433: public void startContentModel(String elementName, Augmentations augs)
1434: throws XNIException {
1435:
1436: if (fValidation) {
1437: fDTDElementDeclName = elementName;
1438: fMixedElementTypes.removeAllElements();
1439: }
1440:
1441: // call handlers
1442: if (fDTDGrammar != null)
1443: fDTDGrammar.startContentModel(elementName, augs);
1444: if (fDTDContentModelHandler != null) {
1445: fDTDContentModelHandler
1446: .startContentModel(elementName, augs);
1447: }
1448:
1449: } // startContentModel(String)
1450:
1451: /**
1452: * A content model of ANY.
1453: *
1454: * @param augs Additional information that may include infoset
1455: * augmentations.
1456: *
1457: * @throws XNIException Thrown by handler to signal an error.
1458: *
1459: * @see #empty
1460: * @see #startGroup
1461: */
1462: public void any(Augmentations augs) throws XNIException {
1463: if (fDTDGrammar != null)
1464: fDTDGrammar.any(augs);
1465: if (fDTDContentModelHandler != null) {
1466: fDTDContentModelHandler.any(augs);
1467: }
1468: } // any()
1469:
1470: /**
1471: * A content model of EMPTY.
1472: *
1473: * @param augs Additional information that may include infoset
1474: * augmentations.
1475: *
1476: * @throws XNIException Thrown by handler to signal an error.
1477: *
1478: * @see #any
1479: * @see #startGroup
1480: */
1481: public void empty(Augmentations augs) throws XNIException {
1482: if (fDTDGrammar != null)
1483: fDTDGrammar.empty(augs);
1484: if (fDTDContentModelHandler != null) {
1485: fDTDContentModelHandler.empty(augs);
1486: }
1487: } // empty()
1488:
1489: /**
1490: * A start of either a mixed or children content model. A mixed
1491: * content model will immediately be followed by a call to the
1492: * <code>pcdata()</code> method. A children content model will
1493: * contain additional groups and/or elements.
1494: *
1495: * @param augs Additional information that may include infoset
1496: * augmentations.
1497: *
1498: * @throws XNIException Thrown by handler to signal an error.
1499: *
1500: * @see #any
1501: * @see #empty
1502: */
1503: public void startGroup(Augmentations augs) throws XNIException {
1504:
1505: fMixed = false;
1506: // call handlers
1507: if (fDTDGrammar != null)
1508: fDTDGrammar.startGroup(augs);
1509: if (fDTDContentModelHandler != null) {
1510: fDTDContentModelHandler.startGroup(augs);
1511: }
1512:
1513: } // startGroup()
1514:
1515: /**
1516: * The appearance of "#PCDATA" within a group signifying a
1517: * mixed content model. This method will be the first called
1518: * following the content model's <code>startGroup()</code>.
1519: *
1520: * @param augs Additional information that may include infoset
1521: * augmentations.
1522: *
1523: * @throws XNIException Thrown by handler to signal an error.
1524: *
1525: * @see #startGroup
1526: */
1527: public void pcdata(Augmentations augs) {
1528: fMixed = true;
1529: if (fDTDGrammar != null)
1530: fDTDGrammar.pcdata(augs);
1531: if (fDTDContentModelHandler != null) {
1532: fDTDContentModelHandler.pcdata(augs);
1533: }
1534: } // pcdata()
1535:
1536: /**
1537: * A referenced element in a mixed or children content model.
1538: *
1539: * @param elementName The name of the referenced element.
1540: * @param augs Additional information that may include infoset
1541: * augmentations.
1542: *
1543: * @throws XNIException Thrown by handler to signal an error.
1544: */
1545: public void element(String elementName, Augmentations augs)
1546: throws XNIException {
1547:
1548: // check VC: No duplicate Types, in a single mixed-content declaration
1549: if (fMixed && fValidation) {
1550: if (fMixedElementTypes.contains(elementName)) {
1551: fErrorReporter.reportError(
1552: XMLMessageFormatter.XML_DOMAIN,
1553: "DuplicateTypeInMixedContent", new Object[] {
1554: fDTDElementDeclName, elementName },
1555: XMLErrorReporter.SEVERITY_ERROR);
1556: } else {
1557: fMixedElementTypes.addElement(elementName);
1558: }
1559: }
1560:
1561: // call handlers
1562: if (fDTDGrammar != null)
1563: fDTDGrammar.element(elementName, augs);
1564: if (fDTDContentModelHandler != null) {
1565: fDTDContentModelHandler.element(elementName, augs);
1566: }
1567:
1568: } // childrenElement(String)
1569:
1570: /**
1571: * The separator between choices or sequences of a mixed or children
1572: * content model.
1573: *
1574: * @param separator The type of children separator.
1575: * @param augs Additional information that may include infoset
1576: * augmentations.
1577: *
1578: * @throws XNIException Thrown by handler to signal an error.
1579: *
1580: * @see #SEPARATOR_CHOICE
1581: * @see #SEPARATOR_SEQUENCE
1582: */
1583: public void separator(short separator, Augmentations augs)
1584: throws XNIException {
1585:
1586: // call handlers
1587: if (fDTDGrammar != null)
1588: fDTDGrammar.separator(separator, augs);
1589: if (fDTDContentModelHandler != null) {
1590: fDTDContentModelHandler.separator(separator, augs);
1591: }
1592:
1593: } // separator(short)
1594:
1595: /**
1596: * The occurrence count for a child in a children content model or
1597: * for the mixed content model group.
1598: *
1599: * @param occurrence The occurrence count for the last element
1600: * or group.
1601: * @param augs Additional information that may include infoset
1602: * augmentations.
1603: *
1604: * @throws XNIException Thrown by handler to signal an error.
1605: *
1606: * @see #OCCURS_ZERO_OR_ONE
1607: * @see #OCCURS_ZERO_OR_MORE
1608: * @see #OCCURS_ONE_OR_MORE
1609: */
1610: public void occurrence(short occurrence, Augmentations augs)
1611: throws XNIException {
1612:
1613: // call handlers
1614: if (fDTDGrammar != null)
1615: fDTDGrammar.occurrence(occurrence, augs);
1616: if (fDTDContentModelHandler != null) {
1617: fDTDContentModelHandler.occurrence(occurrence, augs);
1618: }
1619:
1620: } // occurrence(short)
1621:
1622: /**
1623: * The end of a group for mixed or children content models.
1624: *
1625: * @param augs Additional information that may include infoset
1626: * augmentations.
1627: *
1628: * @throws XNIException Thrown by handler to signal an error.
1629: */
1630: public void endGroup(Augmentations augs) throws XNIException {
1631:
1632: // call handlers
1633: if (fDTDGrammar != null)
1634: fDTDGrammar.endGroup(augs);
1635: if (fDTDContentModelHandler != null) {
1636: fDTDContentModelHandler.endGroup(augs);
1637: }
1638:
1639: } // endGroup()
1640:
1641: /**
1642: * The end of a content model.
1643: *
1644: * @param augs Additional information that may include infoset
1645: * augmentations.
1646: *
1647: * @throws XNIException Thrown by handler to signal an error.
1648: */
1649: public void endContentModel(Augmentations augs) throws XNIException {
1650:
1651: // call handlers
1652: if (fDTDGrammar != null)
1653: fDTDGrammar.endContentModel(augs);
1654: if (fDTDContentModelHandler != null) {
1655: fDTDContentModelHandler.endContentModel(augs);
1656: }
1657:
1658: } // endContentModel()
1659:
1660: //
1661: // Private methods
1662: //
1663:
1664: /**
1665: * Normalize the attribute value of a non CDATA default attribute
1666: * collapsing sequences of space characters (x20)
1667: *
1668: * @param value The value to normalize
1669: * @return Whether the value was changed or not.
1670: */
1671: private boolean normalizeDefaultAttrValue(XMLString value) {
1672:
1673: boolean skipSpace = true; // skip leading spaces
1674: int current = value.offset;
1675: int end = value.offset + value.length;
1676: for (int i = value.offset; i < end; i++) {
1677: if (value.ch[i] == ' ') {
1678: if (!skipSpace) {
1679: // take the first whitespace as a space and skip the others
1680: value.ch[current++] = ' ';
1681: skipSpace = true;
1682: } else {
1683: // just skip it.
1684: }
1685: } else {
1686: // simply shift non space chars if needed
1687: if (current != i) {
1688: value.ch[current] = value.ch[i];
1689: }
1690: current++;
1691: skipSpace = false;
1692: }
1693: }
1694: if (current != end) {
1695: if (skipSpace) {
1696: // if we finished on a space trim it
1697: current--;
1698: }
1699: // set the new value length
1700: value.length = current - value.offset;
1701: return true;
1702: }
1703: return false;
1704: }
1705:
1706: protected boolean isValidNmtoken(String nmtoken) {
1707: return XMLChar.isValidNmtoken(nmtoken);
1708: } // isValidNmtoken(String): boolean
1709:
1710: protected boolean isValidName(String name) {
1711: return XMLChar.isValidName(name);
1712: } // isValidName(String): boolean
1713:
1714: /**
1715: * Checks that all elements referenced in content models have
1716: * been declared. This method calls out to the error handler
1717: * to indicate warnings.
1718: */
1719: private void checkDeclaredElements(DTDGrammar grammar) {
1720: int elementIndex = grammar.getFirstElementDeclIndex();
1721: XMLContentSpec contentSpec = new XMLContentSpec();
1722: while (elementIndex >= 0) {
1723: int type = grammar.getContentSpecType(elementIndex);
1724: if (type == XMLElementDecl.TYPE_CHILDREN
1725: || type == XMLElementDecl.TYPE_MIXED) {
1726: checkDeclaredElements(grammar, elementIndex, grammar
1727: .getContentSpecIndex(elementIndex), contentSpec);
1728: }
1729: elementIndex = grammar
1730: .getNextElementDeclIndex(elementIndex);
1731: }
1732: }
1733:
1734: /**
1735: * Does a recursive (if necessary) check on the specified element's
1736: * content spec to make sure that all children refer to declared
1737: * elements.
1738: */
1739: private void checkDeclaredElements(DTDGrammar grammar,
1740: int elementIndex, int contentSpecIndex,
1741: XMLContentSpec contentSpec) {
1742: grammar.getContentSpec(contentSpecIndex, contentSpec);
1743: if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
1744: String value = (String) contentSpec.value;
1745: if (value != null
1746: && grammar.getElementDeclIndex(value) == -1) {
1747: fErrorReporter
1748: .reportError(
1749: XMLMessageFormatter.XML_DOMAIN,
1750: "UndeclaredElementInContentSpec",
1751: new Object[] {
1752: grammar
1753: .getElementDeclName(elementIndex).rawname,
1754: value },
1755: XMLErrorReporter.SEVERITY_WARNING);
1756: }
1757: }
1758: // It's not a leaf, so we have to recurse its left and maybe right
1759: // nodes. Save both values before we recurse and trash the node.
1760: else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE)
1761: || (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) {
1762: final int leftNode = ((int[]) contentSpec.value)[0];
1763: final int rightNode = ((int[]) contentSpec.otherValue)[0];
1764: // Recurse on both children.
1765: checkDeclaredElements(grammar, elementIndex, leftNode,
1766: contentSpec);
1767: checkDeclaredElements(grammar, elementIndex, rightNode,
1768: contentSpec);
1769: } else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE
1770: || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE
1771: || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) {
1772: final int leftNode = ((int[]) contentSpec.value)[0];
1773: checkDeclaredElements(grammar, elementIndex, leftNode,
1774: contentSpec);
1775: }
1776: }
1777:
1778: } // class XMLDTDProcessor
|