/*
 * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
 */
/*
 * 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 com.sun.org.apache.xerces.internal.impl.dtd;

import java.util.Iterator;

import com.sun.org.apache.xerces.internal.impl.Constants;
import com.sun.org.apache.xerces.internal.impl.RevalidationHandler;
import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
import com.sun.org.apache.xerces.internal.impl.dtd.models.ContentModelValidator;
import com.sun.org.apache.xerces.internal.impl.dv.DTDDVFactory;
import com.sun.org.apache.xerces.internal.impl.dv.DatatypeValidator;
import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
import com.sun.org.apache.xerces.internal.impl.validation.ValidationState;
import com.sun.org.apache.xerces.internal.util.SymbolTable;
import com.sun.org.apache.xerces.internal.util.XMLChar;
import com.sun.org.apache.xerces.internal.util.XMLSymbols;
import com.sun.org.apache.xerces.internal.xni.Augmentations;
import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
import com.sun.org.apache.xerces.internal.xni.QName;
import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
import com.sun.org.apache.xerces.internal.xni.XMLLocator;
import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
import com.sun.org.apache.xerces.internal.xni.XMLString;
import com.sun.org.apache.xerces.internal.xni.XNIException;
import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter;
import com.sun.org.apache.xerces.internal.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
Author:Eric Ye, IBM, Andy Clark, IBM, Jeffrey Rodriguez IBM, Neil Graham, IBM
@xerces.internal
@LastModified: May 2018
/** * 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. * <p> 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. * <p> * This component requires the following features and properties from the * component manager that uses it: * <ul> * <li>http://xml.org/sax/features/namespaces</li> * <li>http://xml.org/sax/features/validation</li> * <li>http://apache.org/xml/features/validation/dynamic</li> * <li>http://apache.org/xml/properties/internal/symbol-table</li> * <li>http://apache.org/xml/properties/internal/error-reporter</li> * <li>http://apache.org/xml/properties/internal/grammar-pool</li> * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li> * </ul> * * @xerces.internal * * @author Eric Ye, IBM * @author Andy Clark, IBM * @author Jeffrey Rodriguez IBM * @author Neil Graham, IBM * * @LastModified: May 2018 */
public class XMLDTDValidator implements XMLComponent, XMLDocumentFilter, XMLDTDValidatorFilter, RevalidationHandler { // // Constants // // feature identifiers
Feature identifier: namespaces.
/** Feature identifier: namespaces. */
protected static final String NAMESPACES = Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
Feature identifier: validation.
/** Feature identifier: validation. */
protected static final String VALIDATION = Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
Feature identifier: dynamic validation.
/** Feature identifier: dynamic validation. */
protected static final String DYNAMIC_VALIDATION = Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;
Feature identifier: balance syntax trees.
/** 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
/** 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.
/** Property identifier: symbol table. */
protected static final String SYMBOL_TABLE = Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
Property identifier: error reporter.
/** Property identifier: error reporter. */
protected static final String ERROR_REPORTER = Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
Property identifier: grammar pool.
/** Property identifier: grammar pool. */
protected static final String GRAMMAR_POOL = Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
Property identifier: datatype validator factory.
/** 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.
/** Recognized features. */
private static final String[] RECOGNIZED_FEATURES = { NAMESPACES, VALIDATION, DYNAMIC_VALIDATION, BALANCE_SYNTAX_TREES };
Feature defaults.
/** Feature defaults. */
private static final Boolean[] FEATURE_DEFAULTS = { null, null, Boolean.FALSE, Boolean.FALSE, };
Recognized properties.
/** Recognized properties. */
private static final String[] RECOGNIZED_PROPERTIES = { SYMBOL_TABLE, ERROR_REPORTER, GRAMMAR_POOL, DATATYPE_VALIDATOR_FACTORY, VALIDATION_MANAGER };
Property defaults.
/** Property defaults. */
private static final Object[] PROPERTY_DEFAULTS = { null, null, null, null, null, }; // debugging
Compile to true to debug attributes.
/** Compile to true to debug attributes. */
private static final boolean DEBUG_ATTRIBUTES = false;
Compile to true to debug element children.
/** 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.
/** Namespaces. */
protected boolean fNamespaces;
Validation.
/** Validation. */
protected boolean fValidation;
Validation against only DTD
/** 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.
/** * Dynamic validation. This state of this feature is only useful when * the validation feature is set to <code>true</code>. */
protected boolean fDynamicValidation;
Controls whether the DTD grammar produces balanced syntax trees.
/** 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
/** warn on duplicate attribute definition, this feature works only when validation is true */
protected boolean fWarnDuplicateAttdef; // properties
Symbol table.
/** Symbol table. */
protected SymbolTable fSymbolTable;
Error reporter.
/** Error reporter. */
protected XMLErrorReporter fErrorReporter; // the grammar pool protected XMLGrammarPool fGrammarPool;
Grammar bucket.
/** Grammar bucket. */
protected DTDGrammarBucket fGrammarBucket; /* location of the document as passed in from startDocument call */ protected XMLLocator fDocLocation;
Namespace support.
/** Namespace support. */
protected NamespaceContext fNamespaceContext = null;
Datatype validator factory.
/** Datatype validator factory. */
protected DTDDVFactory fDatatypeValidatorFactory; // handlers
Document handler.
/** Document handler. */
protected XMLDocumentHandler fDocumentHandler; protected XMLDocumentSource fDocumentSource; // grammars
DTD Grammar.
/** DTD Grammar. */
protected DTDGrammar fDTDGrammar; // state
True if seen DOCTYPE declaration.
/** True if seen DOCTYPE declaration. */
protected boolean fSeenDoctypeDecl = false;
Perform validation.
/** Perform validation. */
private boolean fPerformValidation;
Schema type: None, DTD, Schema
/** Schema type: None, DTD, Schema */
private String fSchemaType; // information regarding the current element
Current element name.
/** Current element name. */
private final QName fCurrentElement = new QName();
Current element index.
/** Current element index. */
private int fCurrentElementIndex = -1;
Current content spec type.
/** Current content spec type. */
private int fCurrentContentSpecType = -1;
The root element name.
/** The root element name. */
private final QName fRootElement = new QName(); private boolean fInCDATASection = false; // element stack
Element index stack.
/** Element index stack. */
private int[] fElementIndexStack = new int[8];
Content spec type stack.
/** Content spec type stack. */
private int[] fContentSpecTypeStack = new int[8];
Element name stack.
/** 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.

/** * 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. * <p> * <strong>Note:</strong> This is much more efficient use of memory * than creating new arrays for each element depth. * <p> * <strong>Note:</strong> 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.
/** Element children count. */
private int fElementChildrenLength = 0;
Element children offset stack. This stack refers to offsets into the fElementChildren array.
See Also:
  • fElementChildren
/** * Element children offset stack. This stack refers to offsets * into the <code>fElementChildren</code> array. * @see #fElementChildren */
private int[] fElementChildrenOffsetStack = new int[32];
Element depth.
/** Element depth. */
private int fElementDepth = -1; // validation states
True if seen the root element.
/** True if seen the root element. */
private boolean fSeenRootElement = false;
True if inside of element content.
/** True if inside of element content. */
private boolean fInElementContent = false; // temporary variables
Temporary element declaration.
/** Temporary element declaration. */
private final XMLElementDecl fTempElementDecl = new XMLElementDecl();
Temporary atribute declaration.
/** Temporary atribute declaration. */
private final XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl();
Temporary entity declaration.
/** Temporary entity declaration. */
private final XMLEntityDecl fEntityDecl = new XMLEntityDecl();
Temporary qualified name.
/** Temporary qualified name. */
private final QName fTempQName = new QName();
Temporary string buffers.
/** Temporary string buffers. */
private final StringBuilder fBuffer = new StringBuilder(); // symbols: general // attribute validators
Datatype validator: ID.
/** Datatype validator: ID. */
protected DatatypeValidator fValID;
Datatype validator: IDREF.
/** Datatype validator: IDREF. */
protected DatatypeValidator fValIDRef;
Datatype validator: IDREFS.
/** Datatype validator: IDREFS. */
protected DatatypeValidator fValIDRefs;
Datatype validator: ENTITY.
/** Datatype validator: ENTITY. */
protected DatatypeValidator fValENTITY;
Datatype validator: ENTITIES.
/** Datatype validator: ENTITIES. */
protected DatatypeValidator fValENTITIES;
Datatype validator: NMTOKEN.
/** Datatype validator: NMTOKEN. */
protected DatatypeValidator fValNMTOKEN;
Datatype validator: NMTOKENS.
/** Datatype validator: NMTOKENS. */
protected DatatypeValidator fValNMTOKENS;
Datatype validator: NOTATION.
/** Datatype validator: NOTATION. */
protected DatatypeValidator fValNOTATION; // to check for duplicate ID or ANNOTATION attribute declare in // ATTLIST, and misc VCs // // Constructors //
Default constructor.
/** Default constructor. */
public XMLDTDValidator() { // initialize data for (int i = 0; i < fElementQNamePartsStack.length; i++) { fElementQNamePartsStack[i] = new QName(); } fGrammarBucket = new DTDGrammarBucket(); } // <init>() 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 = componentManager.getFeature(PARSER_SETTINGS, true); if (!parser_settings){ // parser settings have not been changed fValidationManager.addValidationState(fValidationState); return; } // sax features fNamespaces = componentManager.getFeature(NAMESPACES, true); fValidation = componentManager.getFeature(VALIDATION, false); fDTDValidation = !(componentManager.getFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE, false)); // Xerces features fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION, false); fBalanceSyntaxTrees = componentManager.getFeature(BALANCE_SYNTAX_TREES, false); fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF, false); fSchemaType = (String)componentManager.getProperty (Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, 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); fGrammarPool= (XMLGrammarPool)componentManager.getProperty(GRAMMAR_POOL, 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.
/** * 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 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.

Params:
  • featureId – The feature identifier.
  • state – The state of the feature.
/** * Sets the state of a feature. This method is called by the component * manager any time after reset when a feature changes state. * <p> * <strong>Note:</strong> 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. */
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.
/** * 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 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.

Params:
  • propertyId – The property identifier.
  • value – The value of the property.
/** * Sets the value of a property. This method is called by the component * manager any time after reset when a property changes value. * <p> * <strong>Note:</strong> 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. */
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.
Params:
  • featureId – The feature identifier.
Since:Xerces 2.2.0
/** * 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.
Params:
  • propertyId – The property identifier.
Since:Xerces 2.2.0
/** * 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.
/** Sets the document handler to receive information about the document. */
public void setDocumentHandler(XMLDocumentHandler documentHandler) { fDocumentHandler = documentHandler; } // setDocumentHandler(XMLDocumentHandler)
Returns the document handler
/** Returns the document handler */
public XMLDocumentHandler getDocumentHandler() { return fDocumentHandler; } // getDocumentHandler(): XMLDocumentHandler // // XMLDocumentHandler methods //
Sets the document source
/** Sets the document source */
public void setDocumentSource(XMLDocumentSource source){ fDocumentSource = source; } // setDocumentSource
Returns the document source
/** Returns the document source */
public XMLDocumentSource getDocumentSource (){ return fDocumentSource; } // getDocumentSource
The start of the document.
Params:
  • locator – The system identifier of the entity if the entity is external, null otherwise.
  • 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).
  • 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.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • version – The XML version.
  • encoding – The IANA encoding name of the document, or null if not specified.
  • standalone – The standalone value, or null if not specified.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • rootElement – The name of the root element.
  • publicId – The public identifier if an external DTD or null if the external DTD is specified using SYSTEM.
  • systemId – The system identifier if an external DTD, null otherwise.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • element – The name of the element.
  • attributes – The element attributes.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • element – The name of the element.
  • attributes – The element attributes.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • text – The content.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • text – The ignorable whitespace.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • element – The name of the element.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.
Params:
  • text – The text in the comment.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * 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.

Params:
  • target – The target.
  • data – The data or null if none specified.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * A processing instruction. Processing instructions consist of a * target name and, optionally, text data. The data is only meaningful * to the application. * <p> * Typically, a processing instruction's data will contain a series * of pseudo-attributes. These pseudo-attributes follow the form of * element attributes but are <strong>not</strong> 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.

Params:
  • name – The name of the general entity.
  • identifier – The resource identifier.
  • 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).
  • augs – Additional information that may include infoset augmentations
Throws:
/** * This method notifies the start of a general entity. * <p> * <strong>Note:</strong> 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.

Params:
  • name – The name of the entity.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * This method notifies the end of a general entity. * <p> * <strong>Note:</strong> 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.

Params:
  • version – The XML version, or null if not specified.
  • encoding – The IANA encoding name of the entity.
  • augs – Additional information that may include infoset augmentations.
Throws:
/** * Notifies of the presence of a TextDecl line in an entity. If present, * this method will be called immediately following the startParameterEntity call. * <p> * <strong>Note:</strong> 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.
/** 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); 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 // startEntity, 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 position = fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); while (position != -1) { fDTDGrammar.getAttributeDecl(position, fTempAttDecl); if (fTempAttDecl.name.rawname == attrRawName) { // found the match att decl, 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.
/** 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.
/** * 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) { StringBuilder enumValueString = new StringBuilder(); 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.
/** 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)
Params:
  • attributes – The list of attributes
  • index – The index of the attribute to normalize
/** * 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; 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 { 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); } String newValue = fBuffer.toString(); attributes.setValue(index, newValue); return ! attrValue.equals(newValue); }
Root element specified.
/** 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.

Params:
  • elementIndex – The index within the ElementDeclPool of this element.
  • childCount – The number of entries in the children array.
  • children – The children of this element.
Throws:
Returns: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.
/** * Check that the content of an element is valid. * <p> * This is the method of primary concern to the validator. This method is called * upon the scanner reaching the end tag of an element. At that time, the * element's children must be structurally validated, so it calls this method. * The index of the element being checked (in the decl pool), is provided as * well as an array of element name indexes of the children. The validator must * confirm that this element can have these children in this order. * <p> * This can also be called to do 'what if' testing of content models just to see * if they would be valid. * <p> * Note that the element index is an index into the element decl pool, whereas * the children indexes are name indexes, i.e. into the string pool. * <p> * A value of -1 in the children array indicates a PCDATA node. All other * indexes will be positive and represent child elements. The count can be * zero, since some elements have the EMPTY content model and that must be * confirmed. * * @param elementIndex The index within the <code>ElementDeclPool</code> of this * element. * @param childCount The number of entries in the <code>children</code> array. * @param children The children of this element. * * @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 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
Character data in content.
/** 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
/** 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: { int totalLength = 2; for (int i = 0; i < attrDecl.simpleType.enumeration.length; i++) { totalLength += attrDecl.simpleType.enumeration[i].length() + 1; } StringBuilder buffer = new StringBuilder(totalLength); buffer.append('('); for (int i=0; i<attrDecl.simpleType.enumeration.length ; i++) { if (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
/** 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
/** 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
Returns:true if validator is removed from the pipeline
/** 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.
/** 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<String> 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