All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xerces.impl.dtd.XMLDTDValidator Maven / Gradle / Ivy

Go to download

Xerces2 is the next generation of high performance, fully compliant XML parsers in the Apache Xerces family. This new version of Xerces introduces the Xerces Native Interface (XNI), a complete framework for building parser components and configurations that is extremely modular and easy to program. The Apache Xerces2 parser is the reference implementation of XNI but other parser components, configurations, and parsers can be written using the Xerces Native Interface. For complete design and implementation documents, refer to the XNI Manual. Xerces2 is a fully conforming XML Schema 1.0 processor. A partial experimental implementation of the XML Schema 1.1 Structures and Datatypes Working Drafts (December 2009) and an experimental implementation of the XML Schema Definition Language (XSD): Component Designators (SCD) Candidate Recommendation (January 2010) are provided for evaluation. For more information, refer to the XML Schema page. Xerces2 also provides a complete implementation of the Document Object Model Level 3 Core and Load/Save W3C Recommendations and provides a complete implementation of the XML Inclusions (XInclude) W3C Recommendation. It also provides support for OASIS XML Catalogs v1.1. Xerces2 is able to parse documents written according to the XML 1.1 Recommendation, except that it does not yet provide an option to enable normalization checking as described in section 2.13 of this specification. It also handles namespaces according to the XML Namespaces 1.1 Recommendation, and will correctly serialize XML 1.1 documents if the DOM level 3 load/save APIs are in use.

There is a newer version: 2.12.2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.xerces.impl.dtd;

import java.util.Iterator;

import org.apache.xerces.impl.Constants;
import org.apache.xerces.impl.RevalidationHandler;
import org.apache.xerces.impl.XMLEntityManager;
import org.apache.xerces.impl.XMLErrorReporter;
import org.apache.xerces.impl.dtd.models.ContentModelValidator;
import org.apache.xerces.impl.dv.DTDDVFactory;
import org.apache.xerces.impl.dv.DatatypeValidator;
import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
import org.apache.xerces.impl.msg.XMLMessageFormatter;
import org.apache.xerces.impl.validation.ValidationManager;
import org.apache.xerces.impl.validation.ValidationState;
import org.apache.xerces.util.SymbolTable;
import org.apache.xerces.util.XMLChar;
import org.apache.xerces.util.XMLSymbols;
import org.apache.xerces.xni.Augmentations;
import org.apache.xerces.xni.NamespaceContext;
import org.apache.xerces.xni.QName;
import org.apache.xerces.xni.XMLAttributes;
import org.apache.xerces.xni.XMLDocumentHandler;
import org.apache.xerces.xni.XMLLocator;
import org.apache.xerces.xni.XMLResourceIdentifier;
import org.apache.xerces.xni.XMLString;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.grammars.Grammar;
import org.apache.xerces.xni.grammars.XMLGrammarDescription;
import org.apache.xerces.xni.grammars.XMLGrammarPool;
import org.apache.xerces.xni.parser.XMLComponent;
import org.apache.xerces.xni.parser.XMLComponentManager;
import org.apache.xerces.xni.parser.XMLConfigurationException;
import org.apache.xerces.xni.parser.XMLDocumentFilter;
import org.apache.xerces.xni.parser.XMLDocumentSource;

/**
 * The DTD validator. The validator implements a document
 * filter: receiving document events from the scanner; validating
 * the content and structure; augmenting the InfoSet, if applicable;
 * and notifying the parser of the information resulting from the
 * validation process.
 * 

Formerly, this component also handled DTD events and grammar construction. * To facilitate the development of a meaningful DTD grammar caching/preparsing * framework, this functionality has been moved into the XMLDTDLoader * class. Therefore, this class no longer implements the DTDFilter * or DTDContentModelFilter interfaces. *

* This component requires the following features and properties from the * component manager that uses it: *

    *
  • http://xml.org/sax/features/namespaces
  • *
  • http://xml.org/sax/features/validation
  • *
  • http://apache.org/xml/features/validation/dynamic
  • *
  • http://apache.org/xml/properties/internal/symbol-table
  • *
  • http://apache.org/xml/properties/internal/error-reporter
  • *
  • http://apache.org/xml/properties/internal/grammar-pool
  • *
  • http://apache.org/xml/properties/internal/datatype-validator-factory
  • *
* * @xerces.internal * * @author Eric Ye, IBM * @author Andy Clark, IBM * @author Jeffrey Rodriguez IBM * @author Neil Graham, IBM * * @version $Id: XMLDTDValidator.java 1380445 2012-09-04 04:43:34Z mrglavas $ */ public class XMLDTDValidator implements XMLComponent, XMLDocumentFilter, XMLDTDValidatorFilter, RevalidationHandler { // // Constants // /** Symbol: "<<datatypes>>". */ /** Top level scope (-1). */ private static final int TOP_LEVEL_SCOPE = -1; // feature identifiers /** Feature identifier: namespaces. */ protected static final String NAMESPACES = Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; /** Feature identifier: validation. */ protected static final String VALIDATION = Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; /** Feature identifier: dynamic validation. */ protected static final String DYNAMIC_VALIDATION = Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE; /** Feature identifier: balance syntax trees. */ protected static final String BALANCE_SYNTAX_TREES = Constants.XERCES_FEATURE_PREFIX + Constants.BALANCE_SYNTAX_TREES; /** Feature identifier: warn on duplicate attdef */ protected static final String WARN_ON_DUPLICATE_ATTDEF = Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; protected static final String PARSER_SETTINGS = Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; // property identifiers /** Property identifier: symbol table. */ protected static final String SYMBOL_TABLE = Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; /** Property identifier: error reporter. */ protected static final String ERROR_REPORTER = Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; /** Property identifier: grammar pool. */ protected static final String GRAMMAR_POOL = Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; /** Property identifier: datatype validator factory. */ protected static final String DATATYPE_VALIDATOR_FACTORY = Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; // property identifier: ValidationManager protected static final String VALIDATION_MANAGER = Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; // recognized features and properties /** Recognized features. */ private static final String[] RECOGNIZED_FEATURES = { NAMESPACES, VALIDATION, DYNAMIC_VALIDATION, BALANCE_SYNTAX_TREES }; /** Feature defaults. */ private static final Boolean[] FEATURE_DEFAULTS = { null, null, Boolean.FALSE, Boolean.FALSE, }; /** Recognized properties. */ private static final String[] RECOGNIZED_PROPERTIES = { SYMBOL_TABLE, ERROR_REPORTER, GRAMMAR_POOL, DATATYPE_VALIDATOR_FACTORY, VALIDATION_MANAGER }; /** Property defaults. */ private static final Object[] PROPERTY_DEFAULTS = { null, null, null, null, null, }; // debugging /** Compile to true to debug attributes. */ private static final boolean DEBUG_ATTRIBUTES = false; /** Compile to true to debug element children. */ private static final boolean DEBUG_ELEMENT_CHILDREN = false; // // Data // // updated during reset protected ValidationManager fValidationManager = null; // validation state protected final ValidationState fValidationState = new ValidationState(); // features /** Namespaces. */ protected boolean fNamespaces; /** Validation. */ protected boolean fValidation; /** Validation against only DTD */ protected boolean fDTDValidation; /** * Dynamic validation. This state of this feature is only useful when * the validation feature is set to true. */ protected boolean fDynamicValidation; /** Controls whether the DTD grammar produces balanced syntax trees. */ protected boolean fBalanceSyntaxTrees; /** warn on duplicate attribute definition, this feature works only when validation is true */ protected boolean fWarnDuplicateAttdef; // properties /** Symbol table. */ protected SymbolTable fSymbolTable; /** Error reporter. */ protected XMLErrorReporter fErrorReporter; // the grammar pool protected XMLGrammarPool fGrammarPool; /** Grammar bucket. */ protected DTDGrammarBucket fGrammarBucket; /* location of the document as passed in from startDocument call */ protected XMLLocator fDocLocation; /** Namespace support. */ protected NamespaceContext fNamespaceContext = null; /** Datatype validator factory. */ protected DTDDVFactory fDatatypeValidatorFactory; // handlers /** Document handler. */ protected XMLDocumentHandler fDocumentHandler; protected XMLDocumentSource fDocumentSource; // grammars /** DTD Grammar. */ protected DTDGrammar fDTDGrammar; // state /** True if seen DOCTYPE declaration. */ protected boolean fSeenDoctypeDecl = false; /** Perform validation. */ private boolean fPerformValidation; /** Schema type: None, DTD, Schema */ private String fSchemaType; // information regarding the current element /** Current element name. */ private final QName fCurrentElement = new QName(); /** Current element index. */ private int fCurrentElementIndex = -1; /** Current content spec type. */ private int fCurrentContentSpecType = -1; /** The root element name. */ private final QName fRootElement = new QName(); private boolean fInCDATASection = false; // element stack /** Element index stack. */ private int[] fElementIndexStack = new int[8]; /** Content spec type stack. */ private int[] fContentSpecTypeStack = new int[8]; /** Element name stack. */ private QName[] fElementQNamePartsStack = new QName[8]; // children list and offset stack /** * Element children. This data structure is a growing stack that * holds the children of elements from the root to the current * element depth. This structure never gets "deeper" than the * deepest element. Space is re-used once each element is closed. *

* Note: This is much more efficient use of memory * than creating new arrays for each element depth. *

* Note: The use of this data structure is for * validation "on the way out". If the validation model changes to * "on the way in", then this data structure is not needed. */ private QName[] fElementChildren = new QName[32]; /** Element children count. */ private int fElementChildrenLength = 0; /** * Element children offset stack. This stack refers to offsets * into the fElementChildren array. * @see #fElementChildren */ private int[] fElementChildrenOffsetStack = new int[32]; /** Element depth. */ private int fElementDepth = -1; // validation states /** True if seen the root element. */ private boolean fSeenRootElement = false; /** True if inside of element content. */ private boolean fInElementContent = false; // temporary variables /** Temporary element declaration. */ private final XMLElementDecl fTempElementDecl = new XMLElementDecl(); /** Temporary atribute declaration. */ private final XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl(); /** Temporary entity declaration. */ private final XMLEntityDecl fEntityDecl = new XMLEntityDecl(); /** Temporary qualified name. */ private final QName fTempQName = new QName(); /** Temporary string buffers. */ private final StringBuffer fBuffer = new StringBuffer(); // symbols: general // attribute validators /** Datatype validator: ID. */ protected DatatypeValidator fValID; /** Datatype validator: IDREF. */ protected DatatypeValidator fValIDRef; /** Datatype validator: IDREFS. */ protected DatatypeValidator fValIDRefs; /** Datatype validator: ENTITY. */ protected DatatypeValidator fValENTITY; /** Datatype validator: ENTITIES. */ protected DatatypeValidator fValENTITIES; /** Datatype validator: NMTOKEN. */ protected DatatypeValidator fValNMTOKEN; /** Datatype validator: NMTOKENS. */ protected DatatypeValidator fValNMTOKENS; /** Datatype validator: NOTATION. */ protected DatatypeValidator fValNOTATION; // to check for duplicate ID or ANNOTATION attribute declare in // ATTLIST, and misc VCs // // Constructors // /** Default constructor. */ public XMLDTDValidator() { // initialize data for (int i = 0; i < fElementQNamePartsStack.length; i++) { fElementQNamePartsStack[i] = new QName(); } fGrammarBucket = new DTDGrammarBucket(); } // () DTDGrammarBucket getGrammarBucket() { return fGrammarBucket; } // getGrammarBucket(): DTDGrammarBucket // // XMLComponent methods // /* * Resets the component. The component can query the component manager * about any features and properties that affect the operation of the * component. * * @param componentManager The component manager. * * @throws SAXException Thrown by component on finitialization error. * For example, if a feature or property is * required for the operation of the component, the * component manager may throw a * SAXNotRecognizedException or a * SAXNotSupportedException. */ public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { // clear grammars fDTDGrammar = null; fSeenDoctypeDecl = false; fInCDATASection = false; // initialize state fSeenRootElement = false; fInElementContent = false; fCurrentElementIndex = -1; fCurrentContentSpecType = -1; fRootElement.clear(); fValidationState.resetIDTables(); fGrammarBucket.clear(); fElementDepth = -1; fElementChildrenLength = 0; boolean parser_settings; try { parser_settings = componentManager.getFeature(PARSER_SETTINGS); } catch (XMLConfigurationException e){ parser_settings = true; } if (!parser_settings){ // parser settings have not been changed fValidationManager.addValidationState(fValidationState); return; } // sax features try { fNamespaces = componentManager.getFeature(NAMESPACES); } catch (XMLConfigurationException e) { fNamespaces = true; } try { fValidation = componentManager.getFeature(VALIDATION); } catch (XMLConfigurationException e) { fValidation = false; } try { fDTDValidation = !(componentManager.getFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE)); } catch (XMLConfigurationException e) { // must be in a schema-less configuration! fDTDValidation = true; } // Xerces features try { fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION); } catch (XMLConfigurationException e) { fDynamicValidation = false; } try { fBalanceSyntaxTrees = componentManager.getFeature(BALANCE_SYNTAX_TREES); } catch (XMLConfigurationException e) { fBalanceSyntaxTrees = false; } try { fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF); } catch (XMLConfigurationException e) { fWarnDuplicateAttdef = false; } try { fSchemaType = (String)componentManager.getProperty (Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE); } catch (XMLConfigurationException e){ fSchemaType = null; } fValidationManager= (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER); fValidationManager.addValidationState(fValidationState); fValidationState.setUsingNamespaces(fNamespaces); // get needed components fErrorReporter = (XMLErrorReporter)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.ERROR_REPORTER_PROPERTY); fSymbolTable = (SymbolTable)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.SYMBOL_TABLE_PROPERTY); try { fGrammarPool= (XMLGrammarPool)componentManager.getProperty(GRAMMAR_POOL); } catch (XMLConfigurationException e) { fGrammarPool = null; } fDatatypeValidatorFactory = (DTDDVFactory)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY); init(); } // reset(XMLComponentManager) /** * Returns a list of feature identifiers that are recognized by * this component. This method may return null if no features * are recognized by this component. */ public String[] getRecognizedFeatures() { return (String[])(RECOGNIZED_FEATURES.clone()); } // getRecognizedFeatures():String[] /** * Sets the state of a feature. This method is called by the component * manager any time after reset when a feature changes state. *

* Note: Components should silently ignore features * that do not affect the operation of the component. * * @param featureId The feature identifier. * @param state The state of the feature. * * @throws SAXNotRecognizedException The component should not throw * this exception. * @throws SAXNotSupportedException The component should not throw * this exception. */ public void setFeature(String featureId, boolean state) throws XMLConfigurationException { } // setFeature(String,boolean) /** * Returns a list of property identifiers that are recognized by * this component. This method may return null if no properties * are recognized by this component. */ public String[] getRecognizedProperties() { return (String[])(RECOGNIZED_PROPERTIES.clone()); } // getRecognizedProperties():String[] /** * Sets the value of a property. This method is called by the component * manager any time after reset when a property changes value. *

* Note: Components should silently ignore properties * that do not affect the operation of the component. * * @param propertyId The property identifier. * @param value The value of the property. * * @throws SAXNotRecognizedException The component should not throw * this exception. * @throws SAXNotSupportedException The component should not throw * this exception. */ public void setProperty(String propertyId, Object value) throws XMLConfigurationException { } // setProperty(String,Object) /** * Returns the default state for a feature, or null if this * component does not want to report a default value for this * feature. * * @param featureId The feature identifier. * * @since Xerces 2.2.0 */ public Boolean getFeatureDefault(String featureId) { for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { if (RECOGNIZED_FEATURES[i].equals(featureId)) { return FEATURE_DEFAULTS[i]; } } return null; } // getFeatureDefault(String):Boolean /** * Returns the default state for a property, or null if this * component does not want to report a default value for this * property. * * @param propertyId The property identifier. * * @since Xerces 2.2.0 */ public Object getPropertyDefault(String propertyId) { for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { return PROPERTY_DEFAULTS[i]; } } return null; } // getPropertyDefault(String):Object // // XMLDocumentSource methods // /** Sets the document handler to receive information about the document. */ public void setDocumentHandler(XMLDocumentHandler documentHandler) { fDocumentHandler = documentHandler; } // setDocumentHandler(XMLDocumentHandler) /** Returns the document handler */ public XMLDocumentHandler getDocumentHandler() { return fDocumentHandler; } // getDocumentHandler(): XMLDocumentHandler // // XMLDocumentHandler methods // /** Sets the document source */ public void setDocumentSource(XMLDocumentSource source){ fDocumentSource = source; } // setDocumentSource /** Returns the document source */ public XMLDocumentSource getDocumentSource (){ return fDocumentSource; } // getDocumentSource /** * The start of the document. * * @param locator The system identifier of the entity if the entity * is external, null otherwise. * @param encoding The auto-detected IANA encoding name of the entity * stream. This value will be null in those situations * where the entity encoding is not auto-detected (e.g. * internal entities or a document entity that is * parsed from a java.io.Reader). * @param namespaceContext * The namespace context in effect at the * start of this document. * This object represents the current context. * Implementors of this class are responsible * for copying the namespace bindings from the * the current context (and its parent contexts) * if that information is important. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void startDocument(XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs) throws XNIException { // call handlers // get initial grammars if (fGrammarPool != null) { Grammar [] grammars = fGrammarPool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_DTD); final int length = (grammars != null) ? grammars.length : 0; for (int i = 0; i < length; ++i) { fGrammarBucket.putGrammar((DTDGrammar)grammars[i]); } } fDocLocation = locator; fNamespaceContext = namespaceContext; if (fDocumentHandler != null) { fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); } } // startDocument(XMLLocator,String) /** * Notifies of the presence of an XMLDecl line in the document. If * present, this method will be called immediately following the * startDocument call. * * @param version The XML version. * @param encoding The IANA encoding name of the document, or null if * not specified. * @param standalone The standalone value, or null if not specified. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) throws XNIException { // save standalone state fGrammarBucket.setStandalone(standalone != null && standalone.equals("yes")); // call handlers if (fDocumentHandler != null) { fDocumentHandler.xmlDecl(version, encoding, standalone, augs); } } // xmlDecl(String,String,String) /** * Notifies of the presence of the DOCTYPE line in the document. * * @param rootElement The name of the root element. * @param publicId The public identifier if an external DTD or null * if the external DTD is specified using SYSTEM. * @param systemId The system identifier if an external DTD, null * otherwise. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs) throws XNIException { // save root element state fSeenDoctypeDecl = true; fRootElement.setValues(null, rootElement, rootElement, null); // find or create grammar: String eid = null; try { eid = XMLEntityManager.expandSystemId(systemId, fDocLocation.getExpandedSystemId(), false); } catch (java.io.IOException e) { } XMLDTDDescription grammarDesc = new XMLDTDDescription(publicId, systemId, fDocLocation.getExpandedSystemId(), eid, rootElement); fDTDGrammar = fGrammarBucket.getGrammar(grammarDesc); if(fDTDGrammar == null) { // give grammar pool a chance... // // Do not bother checking the pool if no public or system identifier was provided. // Since so many different DTDs have roots in common, using only a root name as the // key may cause an unexpected grammar to be retrieved from the grammar pool. This scenario // would occur when an ExternalSubsetResolver has been queried and the // XMLInputSource returned contains an input stream but no external identifier. // This can never happen when the instance document specified a DOCTYPE. -- mrglavas if (fGrammarPool != null && (systemId != null || publicId != null)) { fDTDGrammar = (DTDGrammar)fGrammarPool.retrieveGrammar(grammarDesc); } } if(fDTDGrammar == null) { // we'll have to create it... if (!fBalanceSyntaxTrees) { fDTDGrammar = new DTDGrammar(fSymbolTable, grammarDesc); } else { fDTDGrammar = new BalancedDTDGrammar(fSymbolTable, grammarDesc); } } else { // we've found a cached one;so let's make sure not to read // any external subset! fValidationManager.setCachedDTD(true); } fGrammarBucket.setActiveGrammar(fDTDGrammar); // call handlers if (fDocumentHandler != null) { fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); } } // doctypeDecl(String,String,String, Augmentations) /** * The start of an element. * * @param element The name of the element. * @param attributes The element attributes. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { handleStartElement(element, attributes, augs); // call handlers if (fDocumentHandler != null) { fDocumentHandler.startElement(element, attributes, augs); } } // startElement(QName,XMLAttributes) /** * An empty element. * * @param element The name of the element. * @param attributes The element attributes. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { boolean removed = handleStartElement(element, attributes, augs); if (fDocumentHandler !=null) { fDocumentHandler.emptyElement(element, attributes, augs); } if (!removed) { handleEndElement(element, augs, true); } } // emptyElement(QName,XMLAttributes) /** * Character content. * * @param text The content. * * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void characters(XMLString text, Augmentations augs) throws XNIException { boolean callNextCharacters = true; // REVISIT: [Q] Is there a more efficient way of doing this? // Perhaps if the scanner told us so we don't have to // look at the characters again. -Ac boolean allWhiteSpace = true; for (int i=text.offset; i< text.offset+text.length; i++) { if (!isSpace(text.ch[i])) { allWhiteSpace = false; break; } } // call the ignoreableWhiteSpace callback // never call ignorableWhitespace if we are in cdata section if (fInElementContent && allWhiteSpace && !fInCDATASection) { if (fDocumentHandler != null) { fDocumentHandler.ignorableWhitespace(text, augs); callNextCharacters = false; } } // validate if (fPerformValidation) { if (fInElementContent) { if (fGrammarBucket.getStandalone() && fDTDGrammar.getElementDeclIsExternal(fCurrentElementIndex)) { if (allWhiteSpace) { fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, "MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE", null, XMLErrorReporter.SEVERITY_ERROR); } } if (!allWhiteSpace) { charDataInContent(); } // For E15.2 if (augs != null && augs.getItem(Constants.CHAR_REF_PROBABLE_WS) == Boolean.TRUE) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_CONTENT_INVALID_SPECIFIED", new Object[]{ fCurrentElement.rawname, fDTDGrammar.getContentSpecAsString(fElementDepth), "character reference"}, XMLErrorReporter.SEVERITY_ERROR); } } if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) { charDataInContent(); } } // call handlers if (callNextCharacters && fDocumentHandler != null) { fDocumentHandler.characters(text, augs); } } // characters(XMLString) /** * Ignorable whitespace. For this method to be called, the document * source must have some way of determining that the text containing * only whitespace characters should be considered ignorable. For * example, the validator can determine if a length of whitespace * characters in the document are ignorable based on the element * content model. * * @param text The ignorable whitespace. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.ignorableWhitespace(text, augs); } } // ignorableWhitespace(XMLString) /** * The end of an element. * * @param element The name of the element. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void endElement(QName element, Augmentations augs) throws XNIException { handleEndElement(element, augs, false); } // endElement(QName) /** * The start of a CDATA section. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void startCDATA(Augmentations augs) throws XNIException { if (fPerformValidation && fInElementContent) { charDataInContent(); } fInCDATASection = true; // call handlers if (fDocumentHandler != null) { fDocumentHandler.startCDATA(augs); } } // startCDATA() /** * The end of a CDATA section. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void endCDATA(Augmentations augs) throws XNIException { fInCDATASection = false; // call handlers if (fDocumentHandler != null) { fDocumentHandler.endCDATA(augs); } } // endCDATA() /** * The end of the document. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void endDocument(Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.endDocument(augs); } } // endDocument() /** * A comment. * * @param text The text in the comment. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by application to signal an error. */ public void comment(XMLString text, Augmentations augs) throws XNIException { // fixes E15.1 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_CONTENT_INVALID_SPECIFIED", new Object[]{ fCurrentElement.rawname, "EMPTY", "comment"}, XMLErrorReporter.SEVERITY_ERROR); } } // call handlers if (fDocumentHandler != null) { fDocumentHandler.comment(text, augs); } } // comment(XMLString) /** * A processing instruction. Processing instructions consist of a * target name and, optionally, text data. The data is only meaningful * to the application. *

* Typically, a processing instruction's data will contain a series * of pseudo-attributes. These pseudo-attributes follow the form of * element attributes but are not parsed or presented * to the application as anything other than text. The application is * responsible for parsing the data. * * @param target The target. * @param data The data or null if none specified. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void processingInstruction(String target, XMLString data, Augmentations augs) throws XNIException { // fixes E15.1 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_CONTENT_INVALID_SPECIFIED", new Object[]{ fCurrentElement.rawname, "EMPTY", "processing instruction"}, XMLErrorReporter.SEVERITY_ERROR); } } // call handlers if (fDocumentHandler != null) { fDocumentHandler.processingInstruction(target, data, augs); } } // processingInstruction(String,XMLString) /** * This method notifies the start of a general entity. *

* Note: This method is not called for entity references * appearing as part of attribute values. * * @param name The name of the general entity. * @param identifier The resource identifier. * @param encoding The auto-detected IANA encoding name of the entity * stream. This value will be null in those situations * where the entity encoding is not auto-detected (e.g. * internal entities or a document entity that is * parsed from a java.io.Reader). * @param augs Additional information that may include infoset augmentations * * @exception XNIException Thrown by handler to signal an error. */ public void startGeneralEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs) throws XNIException { if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); // fixes E15.1 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_CONTENT_INVALID_SPECIFIED", new Object[]{ fCurrentElement.rawname, "EMPTY", "ENTITY"}, XMLErrorReporter.SEVERITY_ERROR); } if (fGrammarBucket.getStandalone()) { XMLDTDLoader.checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter); } } if (fDocumentHandler != null) { fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); } } /** * This method notifies the end of a general entity. *

* Note: This method is not called for entity references * appearing as part of attribute values. * * @param name The name of the entity. * @param augs Additional information that may include infoset augmentations * * @exception XNIException * Thrown by handler to signal an error. */ public void endGeneralEntity(String name, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.endGeneralEntity(name, augs); } } // endEntity(String) /** * Notifies of the presence of a TextDecl line in an entity. If present, * this method will be called immediately following the startParameterEntity call. *

* Note: This method is only called for external * parameter entities referenced in the DTD. * * @param version The XML version, or null if not specified. * @param encoding The IANA encoding name of the entity. * @param augs Additional information that may include infoset * augmentations. * * @throws XNIException Thrown by handler to signal an error. */ public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.textDecl(version, encoding, augs); } } public final boolean hasGrammar(){ return (fDTDGrammar != null); } public final boolean validate(){ // Do validation if all of the following are true: // 1. The JAXP Schema Language property is not XML Schema // REVISIT: since only DTD and Schema are supported at this time, // such checking is sufficient. but if more schema types // are introduced in the future, we'll need to change it // to something like // (fSchemaType == null || fSchemaType == NS_XML_DTD) // 2. One of the following is true (validation features) // 2.1 Dynamic validation is off, and validation is on // 2.2 Dynamic validation is on, and DOCTYPE was seen // 3 Xerces schema validation feature is off, or DOCTYPE was seen. return (fSchemaType != Constants.NS_XMLSCHEMA) && (!fDynamicValidation && fValidation || fDynamicValidation && fSeenDoctypeDecl) && (fDTDValidation || fSeenDoctypeDecl); } //REVISIT:we can convert into functions.. adding default attribute values.. and one validating. /** Add default attributes and validate. */ protected void addDTDDefaultAttrsAndValidate(QName elementName, int elementIndex, XMLAttributes attributes) throws XNIException { // is there anything to do? if (elementIndex == -1 || fDTDGrammar == null) { return; } // // Check after all specified attrs are scanned // (1) report error for REQUIRED attrs that are missing (V_TAGc) // (2) add default attrs (FIXED and NOT_FIXED) // int attlistIndex = fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); while (attlistIndex != -1) { fDTDGrammar.getAttributeDecl(attlistIndex, fTempAttDecl); if (DEBUG_ATTRIBUTES) { if (fTempAttDecl != null) { XMLElementDecl elementDecl = new XMLElementDecl(); fDTDGrammar.getElementDecl(elementIndex, elementDecl); System.out.println("element: "+(elementDecl.name.localpart)); System.out.println("attlistIndex " + attlistIndex + "\n"+ "attName : '"+(fTempAttDecl.name.localpart) + "'\n" + "attType : "+fTempAttDecl.simpleType.type + "\n" + "attDefaultType : "+fTempAttDecl.simpleType.defaultType + "\n" + "attDefaultValue : '"+fTempAttDecl.simpleType.defaultValue + "'\n" + attributes.getLength() +"\n" ); } } String attPrefix = fTempAttDecl.name.prefix; String attLocalpart = fTempAttDecl.name.localpart; String attRawName = fTempAttDecl.name.rawname; String attType = getAttributeTypeName(fTempAttDecl); int attDefaultType =fTempAttDecl.simpleType.defaultType; String attValue = null; if (fTempAttDecl.simpleType.defaultValue != null) { attValue = fTempAttDecl.simpleType.defaultValue; } boolean specified = false; boolean required = attDefaultType == XMLSimpleType.DEFAULT_TYPE_REQUIRED; boolean cdata = attType == XMLSymbols.fCDATASymbol; if (!cdata || required || attValue != null) { int attrCount = attributes.getLength(); for (int i = 0; i < attrCount; i++) { if (attributes.getQName(i) == attRawName) { specified = true; break; } } } if (!specified) { if (required) { if (fPerformValidation) { Object[] args = {elementName.localpart, attRawName}; fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED", args, XMLErrorReporter.SEVERITY_ERROR); } } else if (attValue != null) { if (fPerformValidation && fGrammarBucket.getStandalone()) { if (fDTDGrammar.getAttributeDeclIsExternal(attlistIndex)) { Object[] args = { elementName.localpart, attRawName}; fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED", args, XMLErrorReporter.SEVERITY_ERROR); } } // add namespace information if (fNamespaces) { int index = attRawName.indexOf(':'); if (index != -1) { attPrefix = attRawName.substring(0, index); attPrefix = fSymbolTable.addSymbol(attPrefix); attLocalpart = attRawName.substring(index + 1); attLocalpart = fSymbolTable.addSymbol(attLocalpart); } } // add attribute fTempQName.setValues(attPrefix, attLocalpart, attRawName, fTempAttDecl.name.uri); int newAttr = attributes.addAttribute(fTempQName, attType, attValue); } } // get next att decl in the Grammar for this element attlistIndex = fDTDGrammar.getNextAttributeDeclIndex(attlistIndex); } // now iterate through the expanded attributes for // 1. if every attribute seen is declared in the DTD // 2. check if the VC: default_fixed holds // 3. validate every attribute. int attrCount = attributes.getLength(); for (int i = 0; i < attrCount; i++) { String attrRawName = attributes.getQName(i); boolean declared = false; if (fPerformValidation) { if (fGrammarBucket.getStandalone()) { // check VC: Standalone Document Declaration, entities // references appear in the document. // REVISIT: this can be combined to a single check in // startEntity if we add one more argument in // startEnity, inAttrValue String nonNormalizedValue = attributes.getNonNormalizedValue(i); if (nonNormalizedValue != null) { String entityName = getExternalEntityRefInAttrValue(nonNormalizedValue); if (entityName != null) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", new Object[]{entityName}, XMLErrorReporter.SEVERITY_ERROR); } } } } int attDefIndex = -1; int position = fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); while (position != -1) { fDTDGrammar.getAttributeDecl(position, fTempAttDecl); if (fTempAttDecl.name.rawname == attrRawName) { // found the match att decl, attDefIndex = position; declared = true; break; } position = fDTDGrammar.getNextAttributeDeclIndex(position); } if (!declared) { if (fPerformValidation) { // REVISIT - cache the elem/attr tuple so that we only // give this error once for each unique occurrence Object[] args = { elementName.rawname, attrRawName}; fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_ATTRIBUTE_NOT_DECLARED", args,XMLErrorReporter.SEVERITY_ERROR); } continue; } // attribute is declared // fTempAttDecl should have the right value set now, so // the following is not needed // fGrammar.getAttributeDecl(attDefIndex,fTempAttDecl); String type = getAttributeTypeName(fTempAttDecl); attributes.setType(i, type); attributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE); boolean changedByNormalization = false; String oldValue = attributes.getValue(i); String attrValue = oldValue; if (attributes.isSpecified(i) && type != XMLSymbols.fCDATASymbol) { changedByNormalization = normalizeAttrValue(attributes, i); attrValue = attributes.getValue(i); if (fPerformValidation && fGrammarBucket.getStandalone() && changedByNormalization && fDTDGrammar.getAttributeDeclIsExternal(position) ) { // check VC: Standalone Document Declaration fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE", new Object[]{attrRawName, oldValue, attrValue}, XMLErrorReporter.SEVERITY_ERROR); } } if (!fPerformValidation) { continue; } if (fTempAttDecl.simpleType.defaultType == XMLSimpleType.DEFAULT_TYPE_FIXED) { String defaultValue = fTempAttDecl.simpleType.defaultValue; if (!attrValue.equals(defaultValue)) { Object[] args = {elementName.localpart, attrRawName, attrValue, defaultValue}; fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_FIXED_ATTVALUE_INVALID", args, XMLErrorReporter.SEVERITY_ERROR); } } if (fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENTITY || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENUMERATION || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ID || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_IDREF || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NMTOKEN || fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NOTATION ) { validateDTDattribute(elementName, attrValue, fTempAttDecl); } } // for all attributes } // addDTDDefaultAttrsAndValidate(int,XMLAttrList) /** Checks entities in attribute values for standalone VC. */ protected String getExternalEntityRefInAttrValue(String nonNormalizedValue) { int valLength = nonNormalizedValue.length(); int ampIndex = nonNormalizedValue.indexOf('&'); while (ampIndex != -1) { if (ampIndex + 1 < valLength && nonNormalizedValue.charAt(ampIndex+1) != '#') { int semicolonIndex = nonNormalizedValue.indexOf(';', ampIndex+1); String entityName = nonNormalizedValue.substring(ampIndex+1, semicolonIndex); entityName = fSymbolTable.addSymbol(entityName); int entIndex = fDTDGrammar.getEntityDeclIndex(entityName); if (entIndex > -1) { fDTDGrammar.getEntityDecl(entIndex, fEntityDecl); if (fEntityDecl.inExternal || (entityName = getExternalEntityRefInAttrValue(fEntityDecl.value)) != null) { return entityName; } } } ampIndex = nonNormalizedValue.indexOf('&', ampIndex+1); } return null; } // isExternalEntityRefInAttrValue(String):String /** * Validate attributes in DTD fashion. */ protected void validateDTDattribute(QName element, String attValue, XMLAttributeDecl attributeDecl) throws XNIException { switch (attributeDecl.simpleType.type) { case XMLSimpleType.TYPE_ENTITY: { // NOTE: Save this information because invalidStandaloneAttDef boolean isAlistAttribute = attributeDecl.simpleType.list; try { if (isAlistAttribute) { fValENTITIES.validate(attValue, fValidationState); } else { fValENTITY.validate(attValue, fValidationState); } } catch (InvalidDatatypeValueException ex) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, ex.getKey(), ex.getArgs(), XMLErrorReporter.SEVERITY_ERROR ); } break; } case XMLSimpleType.TYPE_NOTATION: case XMLSimpleType.TYPE_ENUMERATION: { boolean found = false; String [] enumVals = attributeDecl.simpleType.enumeration; if (enumVals == null) { found = false; } else for (int i = 0; i < enumVals.length; i++) { if (attValue == enumVals[i] || attValue.equals(enumVals[i])) { found = true; break; } } if (!found) { StringBuffer enumValueString = new StringBuffer(); if (enumVals != null) for (int i = 0; i < enumVals.length; i++) { enumValueString.append(enumVals[i]+" "); } fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_ATTRIBUTE_VALUE_NOT_IN_LIST", new Object[]{attributeDecl.name.rawname, attValue, enumValueString}, XMLErrorReporter.SEVERITY_ERROR); } break; } case XMLSimpleType.TYPE_ID: { try { fValID.validate(attValue, fValidationState); } catch (InvalidDatatypeValueException ex) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, ex.getKey(), ex.getArgs(), XMLErrorReporter.SEVERITY_ERROR ); } break; } case XMLSimpleType.TYPE_IDREF: { boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef try { if (isAlistAttribute) { fValIDRefs.validate(attValue, fValidationState); } else { fValIDRef.validate(attValue, fValidationState); } } catch (InvalidDatatypeValueException ex) { if (isAlistAttribute) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "IDREFSInvalid", new Object[]{attValue}, XMLErrorReporter.SEVERITY_ERROR ); } else { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, ex.getKey(), ex.getArgs(), XMLErrorReporter.SEVERITY_ERROR ); } } break; } case XMLSimpleType.TYPE_NMTOKEN: { boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef //changes fTempAttDef try { if (isAlistAttribute) { fValNMTOKENS.validate(attValue, fValidationState); } else { fValNMTOKEN.validate(attValue, fValidationState); } } catch (InvalidDatatypeValueException ex) { if (isAlistAttribute) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "NMTOKENSInvalid", new Object[] { attValue}, XMLErrorReporter.SEVERITY_ERROR); } else { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "NMTOKENInvalid", new Object[] { attValue}, XMLErrorReporter.SEVERITY_ERROR); } } break; } } // switch } // validateDTDattribute(QName,String,XMLAttributeDecl) /** Returns true if invalid standalone attribute definition. */ protected boolean invalidStandaloneAttDef(QName element, QName attribute) { // REVISIT: This obviously needs to be fixed! -Ac boolean state = true; /* if (fStandaloneReader == -1) { return false; } // we are normalizing a default att value... this ok? if (element.rawname == -1) { return false; } return getAttDefIsExternal(element, attribute); */ return state; } // // Private methods // /** * Normalize the attribute value of a non CDATA attributes collapsing * sequences of space characters (x20) * * @param attributes The list of attributes * @param index The index of the attribute to normalize */ private boolean normalizeAttrValue(XMLAttributes attributes, int index) { // vars boolean leadingSpace = true; boolean spaceStart = false; boolean readingNonSpace = false; int count = 0; int eaten = 0; String attrValue = attributes.getValue(index); char[] attValue = new char[attrValue.length()]; fBuffer.setLength(0); attrValue.getChars(0, attrValue.length(), attValue, 0); for (int i = 0; i < attValue.length; i++) { if (attValue[i] == ' ') { // now the tricky part if (readingNonSpace) { spaceStart = true; readingNonSpace = false; } if (spaceStart && !leadingSpace) { spaceStart = false; fBuffer.append(attValue[i]); count++; } else { if (leadingSpace || !spaceStart) { eaten ++; /*** BUG #3512 *** int entityCount = attributes.getEntityCount(index); for (int j = 0; j < entityCount; j++) { int offset = attributes.getEntityOffset(index, j); int length = attributes.getEntityLength(index, j); if (offset <= i-eaten+1) { if (offset+length >= i-eaten+1) { if (length > 0) length--; } } else { if (offset > 0) offset--; } attributes.setEntityOffset(index, j, offset); attributes.setEntityLength(index, j, length); } /***/ } } } else { readingNonSpace = true; spaceStart = false; leadingSpace = false; fBuffer.append(attValue[i]); count++; } } // check if the last appended character is a space. if (count > 0 && fBuffer.charAt(count-1) == ' ') { fBuffer.setLength(count-1); /*** BUG #3512 *** int entityCount = attributes.getEntityCount(index); for (int j=0; j < entityCount; j++) { int offset = attributes.getEntityOffset(index, j); int length = attributes.getEntityLength(index, j); if (offset < count-1) { if (offset+length == count) { length--; } } else { offset--; } attributes.setEntityOffset(index, j, offset); attributes.setEntityLength(index, j, length); } /***/ } String newValue = fBuffer.toString(); attributes.setValue(index, newValue); return ! attrValue.equals(newValue); } /** Root element specified. */ private final void rootElementSpecified(QName rootElement) throws XNIException { if (fPerformValidation) { String root1 = fRootElement.rawname; String root2 = rootElement.rawname; if (root1 == null || !root1.equals(root2)) { fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, "RootElementTypeMustMatchDoctypedecl", new Object[]{root1, root2}, XMLErrorReporter.SEVERITY_ERROR); } } } // rootElementSpecified(QName) /** * Check that the content of an element is valid. *

* This is the method of primary concern to the validator. This method is called * upon the scanner reaching the end tag of an element. At that time, the * element's children must be structurally validated, so it calls this method. * The index of the element being checked (in the decl pool), is provided as * well as an array of element name indexes of the children. The validator must * confirm that this element can have these children in this order. *

* This can also be called to do 'what if' testing of content models just to see * if they would be valid. *

* Note that the element index is an index into the element decl pool, whereas * the children indexes are name indexes, i.e. into the string pool. *

* A value of -1 in the children array indicates a PCDATA node. All other * indexes will be positive and represent child elements. The count can be * zero, since some elements have the EMPTY content model and that must be * confirmed. * * @param elementIndex The index within the ElementDeclPool of this * element. * @param childCount The number of entries in the children array. * @param children The children of this element. * * @return The value -1 if fully valid, else the 0 based index of the child * that first failed. If the value returned is equal to the number * of children, then additional content is required to reach a valid * ending state. * * @exception Exception Thrown on error. */ private int checkContent(int elementIndex, QName[] children, int childOffset, int childCount) throws XNIException { fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl); // Get the element name index from the element final String elementType = fCurrentElement.rawname; // Get out the content spec for this element final int contentType = fCurrentContentSpecType; // // Deal with the possible types of content. We try to optimized here // by dealing specially with content models that don't require the // full DFA treatment. // if (contentType == XMLElementDecl.TYPE_EMPTY) { // // If the child count is greater than zero, then this is // an error right off the bat at index 0. // if (childCount != 0) { return 0; } } else if (contentType == XMLElementDecl.TYPE_ANY) { // // This one is open game so we don't pass any judgement on it // at all. Its assumed to fine since it can hold anything. // } else if (contentType == XMLElementDecl.TYPE_MIXED || contentType == XMLElementDecl.TYPE_CHILDREN) { // Get the content model for this element, faulting it in if needed ContentModelValidator cmElem = null; cmElem = fTempElementDecl.contentModelValidator; int result = cmElem.validate(children, childOffset, childCount); return result; } else if (contentType == -1) { //REVISIT /**** reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED, XMLMessages.VC_ELEMENT_VALID, elementType); /****/ } else if (contentType == XMLElementDecl.TYPE_SIMPLE) { //REVISIT // this should never be reached in the case of DTD validation. } else { //REVISIT /**** fErrorReporter.reportError(fErrorReporter.getLocator(), ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN, ImplementationMessages.VAL_CST, 0, null, XMLErrorReporter.ERRORTYPE_FATAL_ERROR); /****/ } // We succeeded return -1; } // checkContent(int,int,QName[]):int /** Returns the content spec type for an element index. */ private int getContentSpecType(int elementIndex) { int contentSpecType = -1; if (elementIndex > -1) { if (fDTDGrammar.getElementDecl(elementIndex,fTempElementDecl)) { contentSpecType = fTempElementDecl.type; } } return contentSpecType; } /** Character data in content. */ private void charDataInContent() { if (DEBUG_ELEMENT_CHILDREN) { System.out.println("charDataInContent()"); } if (fElementChildren.length <= fElementChildrenLength) { QName[] newarray = new QName[fElementChildren.length * 2]; System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length); fElementChildren = newarray; } QName qname = fElementChildren[fElementChildrenLength]; if (qname == null) { for (int i = fElementChildrenLength; i < fElementChildren.length; i++) { fElementChildren[i] = new QName(); } qname = fElementChildren[fElementChildrenLength]; } qname.clear(); fElementChildrenLength++; } // charDataInCount() /** convert attribute type from ints to strings */ private String getAttributeTypeName(XMLAttributeDecl attrDecl) { switch (attrDecl.simpleType.type) { case XMLSimpleType.TYPE_ENTITY: { return attrDecl.simpleType.list ? XMLSymbols.fENTITIESSymbol : XMLSymbols.fENTITYSymbol; } case XMLSimpleType.TYPE_ENUMERATION: { StringBuffer buffer = new StringBuffer(); buffer.append('('); for (int i=0; i 0) { buffer.append('|'); } buffer.append(attrDecl.simpleType.enumeration[i]); } buffer.append(')'); return fSymbolTable.addSymbol(buffer.toString()); } case XMLSimpleType.TYPE_ID: { return XMLSymbols.fIDSymbol; } case XMLSimpleType.TYPE_IDREF: { return attrDecl.simpleType.list ? XMLSymbols.fIDREFSSymbol : XMLSymbols.fIDREFSymbol; } case XMLSimpleType.TYPE_NMTOKEN: { return attrDecl.simpleType.list ? XMLSymbols.fNMTOKENSSymbol : XMLSymbols.fNMTOKENSymbol; } case XMLSimpleType.TYPE_NOTATION: { return XMLSymbols.fNOTATIONSymbol; } } return XMLSymbols.fCDATASymbol; } // getAttributeTypeName(XMLAttributeDecl):String /** initialization */ protected void init() { // datatype validators if (fValidation || fDynamicValidation) { try { //REVISIT: datatypeRegistry + initialization of datatype // why do we cast to ListDatatypeValidator? fValID = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDSymbol); fValIDRef = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSymbol); fValIDRefs = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSSymbol); fValENTITY = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITYSymbol); fValENTITIES = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITIESSymbol); fValNMTOKEN = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSymbol); fValNMTOKENS = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSSymbol); fValNOTATION = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNOTATIONSymbol); } catch (Exception e) { // should never happen e.printStackTrace(System.err); } } } // init() /** ensure element stack capacity */ private void ensureStackCapacity (int newElementDepth) { if (newElementDepth == fElementQNamePartsStack.length) { QName[] newStackOfQueue = new QName[newElementDepth * 2]; System.arraycopy(this.fElementQNamePartsStack, 0, newStackOfQueue, 0, newElementDepth ); fElementQNamePartsStack = newStackOfQueue; QName qname = fElementQNamePartsStack[newElementDepth]; if (qname == null) { for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) { fElementQNamePartsStack[i] = new QName(); } } int[] newStack = new int[newElementDepth * 2]; System.arraycopy(fElementIndexStack, 0, newStack, 0, newElementDepth); fElementIndexStack = newStack; newStack = new int[newElementDepth * 2]; System.arraycopy(fContentSpecTypeStack, 0, newStack, 0, newElementDepth); fContentSpecTypeStack = newStack; } } // ensureStackCapacity // // Protected methods // /** Handle element * @return true if validator is removed from the pipeline */ protected boolean handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { // VC: Root Element Type // see if the root element's name matches the one in DoctypeDecl if (!fSeenRootElement) { // REVISIT: Here are current assumptions about validation features // given that XMLSchema validator is in the pipeline // // http://xml.org/sax/features/validation = true // http://apache.org/xml/features/validation/schema = true // // [1] XML instance document only has reference to a DTD // Outcome: report validation errors only against dtd. // // [2] XML instance document has only XML Schema grammars: // Outcome: report validation errors only against schemas (no errors produced from DTD validator) // // [3] XML instance document has DTD and XML schemas: // [a] if schema language is not set outcome - validation errors reported against both grammars: DTD and schemas. // [b] if schema language is set to XML Schema - do not report validation errors // // if dynamic validation is on // validate only against grammar we've found (depending on settings // for schema feature) // // fPerformValidation = validate(); fSeenRootElement = true; fValidationManager.setEntityState(fDTDGrammar); fValidationManager.setGrammarFound(fSeenDoctypeDecl); rootElementSpecified(element); } if (fDTDGrammar == null) { if (!fPerformValidation) { fCurrentElementIndex = -1; fCurrentContentSpecType = -1; fInElementContent = false; } if (fPerformValidation) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_GRAMMAR_NOT_FOUND", new Object[]{ element.rawname}, XMLErrorReporter.SEVERITY_ERROR); } // modify pipeline if (fDocumentSource !=null ) { fDocumentSource.setDocumentHandler(fDocumentHandler); if (fDocumentHandler != null) fDocumentHandler.setDocumentSource(fDocumentSource); return true; } } else { // resolve the element fCurrentElementIndex = fDTDGrammar.getElementDeclIndex(element); //changed here.. new function for getContentSpecType fCurrentContentSpecType = fDTDGrammar.getContentSpecType(fCurrentElementIndex); if (fCurrentContentSpecType == -1 && fPerformValidation) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_ELEMENT_NOT_DECLARED", new Object[]{ element.rawname}, XMLErrorReporter.SEVERITY_ERROR); } // 0. insert default attributes // 1. normalize the attributes // 2. validate the attrivute list. // TO DO: //changed here.. also pass element name, addDTDDefaultAttrsAndValidate(element, fCurrentElementIndex, attributes); } // set element content state fInElementContent = fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN; // increment the element depth, add this element's // QName to its enclosing element 's children list fElementDepth++; if (fPerformValidation) { // push current length onto stack if (fElementChildrenOffsetStack.length <= fElementDepth) { int newarray[] = new int[fElementChildrenOffsetStack.length * 2]; System.arraycopy(fElementChildrenOffsetStack, 0, newarray, 0, fElementChildrenOffsetStack.length); fElementChildrenOffsetStack = newarray; } fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength; // add this element to children if (fElementChildren.length <= fElementChildrenLength) { QName[] newarray = new QName[fElementChildrenLength * 2]; System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length); fElementChildren = newarray; } QName qname = fElementChildren[fElementChildrenLength]; if (qname == null) { for (int i = fElementChildrenLength; i < fElementChildren.length; i++) { fElementChildren[i] = new QName(); } qname = fElementChildren[fElementChildrenLength]; } qname.setValues(element); fElementChildrenLength++; } // save current element information fCurrentElement.setValues(element); ensureStackCapacity(fElementDepth); fElementQNamePartsStack[fElementDepth].setValues(fCurrentElement); fElementIndexStack[fElementDepth] = fCurrentElementIndex; fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType; startNamespaceScope(element, attributes, augs); return false; } // handleStartElement(QName,XMLAttributes) protected void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs){ } /** Handle end element. */ protected void handleEndElement(QName element, Augmentations augs, boolean isEmpty) throws XNIException { // decrease element depth fElementDepth--; // validate if (fPerformValidation) { int elementIndex = fCurrentElementIndex; if (elementIndex != -1 && fCurrentContentSpecType != -1) { QName children[] = fElementChildren; int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1; int childrenLength = fElementChildrenLength - childrenOffset; int result = checkContent(elementIndex, children, childrenOffset, childrenLength); if (result != -1) { fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl); if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "MSG_CONTENT_INVALID", new Object[]{ element.rawname, "EMPTY"}, XMLErrorReporter.SEVERITY_ERROR); } else { String messageKey = result != childrenLength ? "MSG_CONTENT_INVALID" : "MSG_CONTENT_INCOMPLETE"; fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, messageKey, new Object[]{ element.rawname, fDTDGrammar.getContentSpecAsString(elementIndex)}, XMLErrorReporter.SEVERITY_ERROR); } } } fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1; } endNamespaceScope(fCurrentElement, augs, isEmpty); // now pop this element off the top of the element stack if (fElementDepth < -1) { throw new RuntimeException("FWK008 Element stack underflow"); } if (fElementDepth < 0) { fCurrentElement.clear(); fCurrentElementIndex = -1; fCurrentContentSpecType = -1; fInElementContent = false; // TO DO : fix this // // Check after document is fully parsed // (1) check that there was an element with a matching id for every // IDREF and IDREFS attr (V_IDREF0) // if (fPerformValidation) { Iterator invIdRefs = fValidationState.checkIDRefID(); if (invIdRefs != null) { while (invIdRefs.hasNext()) { fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, "MSG_ELEMENT_WITH_ID_REQUIRED", new Object[]{invIdRefs.next()}, XMLErrorReporter.SEVERITY_ERROR ); } } } return; } // If Namespace enable then localName != rawName fCurrentElement.setValues(fElementQNamePartsStack[fElementDepth]); fCurrentElementIndex = fElementIndexStack[fElementDepth]; fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth]; fInElementContent = (fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN); } // handleEndElement(QName,boolean) protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty){ // call handlers if (fDocumentHandler != null && !isEmpty) { // NOTE: The binding of the element doesn't actually happen // yet because the namespace binder does that. However, // if it does it before this point, then the endPrefix- // Mapping calls get made too soon! As long as the // rawnames match, we know it'll have a good binding, // so we can just use the current element. -Ac fDocumentHandler.endElement(fCurrentElement, augs); } } // returns whether a character is space according to the // version of XML this validator supports. protected boolean isSpace(int c) { return XMLChar.isSpace(c); } // isSpace(int): boolean public boolean characterData(String data, Augmentations augs) { characters(new XMLString(data.toCharArray(), 0, data.length()), augs); return true; } } // class XMLDTDValidator





© 2015 - 2024 Weber Informatics LLC | Privacy Policy