/*
 * 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;

import java.io.CharConversionException;
import java.io.EOFException;
import java.io.IOException;

import org.apache.xerces.impl.io.MalformedByteSequenceException;
import org.apache.xerces.impl.msg.XMLMessageFormatter;
import org.apache.xerces.util.AugmentationsImpl;
import org.apache.xerces.util.XMLAttributesImpl;
import org.apache.xerces.util.XMLChar;
import org.apache.xerces.util.XMLStringBuffer;
import org.apache.xerces.util.XMLSymbols;
import org.apache.xerces.xni.Augmentations;
import org.apache.xerces.xni.QName;
import org.apache.xerces.xni.XMLAttributes;
import org.apache.xerces.xni.XMLDocumentHandler;
import org.apache.xerces.xni.XMLResourceIdentifier;
import org.apache.xerces.xni.XMLString;
import org.apache.xerces.xni.XNIException;
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.XMLDocumentScanner;
import org.apache.xerces.xni.parser.XMLInputSource;

This class is responsible for scanning the structure and content of document fragments. The scanner acts as the source for the document information which is communicated to the document handler.

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

  • http://xml.org/sax/features/validation
  • http://apache.org/xml/features/scanner/notify-char-refs
  • http://apache.org/xml/features/scanner/notify-builtin-refs
  • http://apache.org/xml/properties/internal/symbol-table
  • http://apache.org/xml/properties/internal/error-reporter
  • http://apache.org/xml/properties/internal/entity-manager
Author:Glenn Marcy, IBM, Andy Clark, IBM, Arnaud Le Hors, IBM, Eric Ye, IBM
@xerces.internal
Version:$Id: XMLDocumentFragmentScannerImpl.java 572055 2007-09-02 17:55:43Z mrglavas $
/** * This class is responsible for scanning the structure and content * of document fragments. The scanner acts as the source for the * document information which is communicated to the document handler. * <p> * This component requires the following features and properties from the * component manager that uses it: * <ul> * <li>http://xml.org/sax/features/validation</li> * <li>http://apache.org/xml/features/scanner/notify-char-refs</li> * <li>http://apache.org/xml/features/scanner/notify-builtin-refs</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/entity-manager</li> * </ul> * * @xerces.internal * * @author Glenn Marcy, IBM * @author Andy Clark, IBM * @author Arnaud Le Hors, IBM * @author Eric Ye, IBM * * @version $Id: XMLDocumentFragmentScannerImpl.java 572055 2007-09-02 17:55:43Z mrglavas $ */
public class XMLDocumentFragmentScannerImpl extends XMLScanner implements XMLDocumentScanner, XMLComponent, XMLEntityHandler { // // Constants // // scanner states
Scanner state: start of markup.
/** Scanner state: start of markup. */
protected static final int SCANNER_STATE_START_OF_MARKUP = 1;
Scanner state: comment.
/** Scanner state: comment. */
protected static final int SCANNER_STATE_COMMENT = 2;
Scanner state: processing instruction.
/** Scanner state: processing instruction. */
protected static final int SCANNER_STATE_PI = 3;
Scanner state: DOCTYPE.
/** Scanner state: DOCTYPE. */
protected static final int SCANNER_STATE_DOCTYPE = 4;
Scanner state: root element.
/** Scanner state: root element. */
protected static final int SCANNER_STATE_ROOT_ELEMENT = 6;
Scanner state: content.
/** Scanner state: content. */
protected static final int SCANNER_STATE_CONTENT = 7;
Scanner state: reference.
/** Scanner state: reference. */
protected static final int SCANNER_STATE_REFERENCE = 8;
Scanner state: end of input.
/** Scanner state: end of input. */
protected static final int SCANNER_STATE_END_OF_INPUT = 13;
Scanner state: terminated.
/** Scanner state: terminated. */
protected static final int SCANNER_STATE_TERMINATED = 14;
Scanner state: CDATA section.
/** Scanner state: CDATA section. */
protected static final int SCANNER_STATE_CDATA = 15;
Scanner state: Text declaration.
/** Scanner state: Text declaration. */
protected static final int SCANNER_STATE_TEXT_DECL = 16; // feature identifiers
Feature identifier: namespaces.
/** Feature identifier: namespaces. */
protected static final String NAMESPACES = Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
Feature identifier: notify built-in refereces.
/** Feature identifier: notify built-in refereces. */
protected static final String NOTIFY_BUILTIN_REFS = Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE; // property identifiers
Property identifier: entity resolver.
/** Property identifier: entity resolver. */
protected static final String ENTITY_RESOLVER = Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; // recognized features and properties
Recognized features.
/** Recognized features. */
private static final String[] RECOGNIZED_FEATURES = { NAMESPACES, VALIDATION, NOTIFY_BUILTIN_REFS, NOTIFY_CHAR_REFS, };
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, ENTITY_MANAGER, ENTITY_RESOLVER, };
Property defaults.
/** Property defaults. */
private static final Object[] PROPERTY_DEFAULTS = { null, null, null, null, }; // debugging
Debug scanner state.
/** Debug scanner state. */
private static final boolean DEBUG_SCANNER_STATE = false;
Debug dispatcher.
/** Debug dispatcher. */
private static final boolean DEBUG_DISPATCHER = false;
Debug content dispatcher scanning.
/** Debug content dispatcher scanning. */
protected static final boolean DEBUG_CONTENT_SCANNING = false; // // Data // // protected data
Document handler.
/** Document handler. */
protected XMLDocumentHandler fDocumentHandler;
Entity stack.
/** Entity stack. */
protected int[] fEntityStack = new int[4];
Markup depth.
/** Markup depth. */
protected int fMarkupDepth;
Scanner state.
/** Scanner state. */
protected int fScannerState;
SubScanner state: inside scanContent method.
/** SubScanner state: inside scanContent method. */
protected boolean fInScanContent = false;
has external dtd
/** has external dtd */
protected boolean fHasExternalDTD;
Standalone.
/** Standalone. */
protected boolean fStandalone;
True if [Entity Declared] is a VC; false if it is a WFC.
/** True if [Entity Declared] is a VC; false if it is a WFC. */
protected boolean fIsEntityDeclaredVC;
External subset resolver.
/** External subset resolver. **/
protected ExternalSubsetResolver fExternalSubsetResolver; // element information
Current element.
/** Current element. */
protected QName fCurrentElement;
Element stack.
/** Element stack. */
protected final ElementStack fElementStack = new ElementStack(); // other info /** Document system identifier. * REVISIT: So what's this used for? - NG * protected String fDocumentSystemId; ******/ // features
Notify built-in references.
/** Notify built-in references. */
protected boolean fNotifyBuiltInRefs = false; // dispatchers
Active dispatcher.
/** Active dispatcher. */
protected Dispatcher fDispatcher;
Content dispatcher.
/** Content dispatcher. */
protected final Dispatcher fContentDispatcher = createContentDispatcher(); // temporary variables
Element QName.
/** Element QName. */
protected final QName fElementQName = new QName();
Attribute QName.
/** Attribute QName. */
protected final QName fAttributeQName = new QName();
Element attributes.
/** Element attributes. */
protected final XMLAttributesImpl fAttributes = new XMLAttributesImpl();
String.
/** String. */
protected final XMLString fTempString = new XMLString();
String.
/** String. */
protected final XMLString fTempString2 = new XMLString();
Array of 3 strings.
/** Array of 3 strings. */
private final String[] fStrings = new String[3];
String buffer.
/** String buffer. */
private final XMLStringBuffer fStringBuffer = new XMLStringBuffer();
String buffer.
/** String buffer. */
private final XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
Another QName.
/** Another QName. */
private final QName fQName = new QName();
Single character array.
/** Single character array. */
private final char[] fSingleChar = new char[1];
Saw spaces after element name or between attributes. This is reserved for the case where scanning of a start element spans several methods, as is the case when scanning the start of a root element where a DTD external subset may be read after scanning the element name.
/** * Saw spaces after element name or between attributes. * * This is reserved for the case where scanning of a start element spans * several methods, as is the case when scanning the start of a root element * where a DTD external subset may be read after scanning the element name. */
private boolean fSawSpace;
Reusable Augmentations.
/** Reusable Augmentations. */
private Augmentations fTempAugmentations = null; // // Constructors //
Default constructor.
/** Default constructor. */
public XMLDocumentFragmentScannerImpl() {} // <init>() // // XMLDocumentScanner methods //
Sets the input source.
Params:
  • inputSource – The input source.
Throws:
/** * Sets the input source. * * @param inputSource The input source. * * @throws IOException Thrown on i/o error. */
public void setInputSource(XMLInputSource inputSource) throws IOException { fEntityManager.setEntityHandler(this); fEntityManager.startEntity("$fragment$", inputSource, false, true); //fDocumentSystemId = fEntityManager.expandSystemId(inputSource.getSystemId()); } // setInputSource(XMLInputSource)
Scans a document.
Params:
  • complete – True if the scanner should scan the document completely, pushing all events to the registered document handler. A value of false indicates that that the scanner should only scan the next portion of the document and return. A scanner instance is permitted to completely scan a document if it does not support this "pull" scanning model.
Returns:True if there is more to scan, false otherwise.
/** * Scans a document. * * @param complete True if the scanner should scan the document * completely, pushing all events to the registered * document handler. A value of false indicates that * that the scanner should only scan the next portion * of the document and return. A scanner instance is * permitted to completely scan a document if it does * not support this "pull" scanning model. * * @return True if there is more to scan, false otherwise. */
public boolean scanDocument(boolean complete) throws IOException, XNIException { // reset entity scanner fEntityScanner = fEntityManager.getEntityScanner(); // keep dispatching "events" fEntityManager.setEntityHandler(this); do { if (!fDispatcher.dispatch(complete)) { return false; } } while (complete); // return success return true; } // scanDocument(boolean):boolean // // XMLComponent methods //
Resets the component. The component can query the component manager about any features and properties that affect the operation of the component.
Params:
  • componentManager – The component manager.
Throws:
  • SAXException – Thrown by component on initialization 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.
/** * 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 initialization 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 { super.reset(componentManager); // other settings //fDocumentSystemId = null; // sax features fAttributes.setNamespaces(fNamespaces); // initialize vars fMarkupDepth = 0; fCurrentElement = null; fElementStack.clear(); fHasExternalDTD = false; fStandalone = false; fIsEntityDeclaredVC = false; fInScanContent = false; // setup dispatcher setScannerState(SCANNER_STATE_CONTENT); setDispatcher(fContentDispatcher); if (fParserSettings) { // parser settings have changed. reset them. // xerces features try { fNotifyBuiltInRefs = componentManager.getFeature(NOTIFY_BUILTIN_REFS); } catch (XMLConfigurationException e) { fNotifyBuiltInRefs = false; } // xerces properties try { Object resolver = componentManager.getProperty(ENTITY_RESOLVER); fExternalSubsetResolver = (resolver instanceof ExternalSubsetResolver) ? (ExternalSubsetResolver) resolver : null; } catch (XMLConfigurationException e) { fExternalSubsetResolver = null; } } } // 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 (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.

Params:
  • featureId – The feature identifier.
  • state – The state of the feature.
Throws:
  • SAXNotRecognizedException – The component should not throw this exception.
  • SAXNotSupportedException – The component should not throw this exception.
/** * 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. * * @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 { super.setFeature(featureId, state); // Xerces properties if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); if (suffixLength == Constants.NOTIFY_BUILTIN_REFS_FEATURE.length() && featureId.endsWith(Constants.NOTIFY_BUILTIN_REFS_FEATURE)) { fNotifyBuiltInRefs = state; } } } // 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 (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.

Params:
  • propertyId – The property identifier.
  • value – The value of the property.
Throws:
  • SAXNotRecognizedException – The component should not throw this exception.
  • SAXNotSupportedException – The component should not throw this exception.
/** * 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. * * @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 { super.setProperty(propertyId, value); // Xerces properties if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) { final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length(); if (suffixLength == Constants.ENTITY_MANAGER_PROPERTY.length() && propertyId.endsWith(Constants.ENTITY_MANAGER_PROPERTY)) { fEntityManager = (XMLEntityManager)value; return; } if (suffixLength == Constants.ENTITY_RESOLVER_PROPERTY.length() && propertyId.endsWith(Constants.ENTITY_RESOLVER_PROPERTY)) { fExternalSubsetResolver = (value instanceof ExternalSubsetResolver) ? (ExternalSubsetResolver) value : null; return; } } } // 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 //
setDocumentHandler
Params:
  • documentHandler –
/** * setDocumentHandler * * @param documentHandler */
public void setDocumentHandler(XMLDocumentHandler documentHandler) { fDocumentHandler = documentHandler; } // setDocumentHandler(XMLDocumentHandler)
Returns the document handler
/** Returns the document handler */
public XMLDocumentHandler getDocumentHandler(){ return fDocumentHandler; } // // XMLEntityHandler methods //
This method notifies of the start of an entity. The DTD has the pseudo-name of "[dtd]" parameter entity names start with '%'; and general entities are just specified by their name.
Params:
  • name – The name of the 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 of the start of an entity. The DTD has the * pseudo-name of "[dtd]" parameter entity names start with '%'; and * general entities are just specified by their name. * * @param name The name of the 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 * * @throws XNIException Thrown by handler to signal an error. */
public void startEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs) throws XNIException { // keep track of this entity before fEntityDepth is increased if (fEntityDepth == fEntityStack.length) { int[] entityarray = new int[fEntityStack.length * 2]; System.arraycopy(fEntityStack, 0, entityarray, 0, fEntityStack.length); fEntityStack = entityarray; } fEntityStack[fEntityDepth] = fMarkupDepth; super.startEntity(name, identifier, encoding, augs); // WFC: entity declared in external subset in standalone doc if(fStandalone && fEntityManager.isEntityDeclInExternalSubset(name)) { reportFatalError("MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", new Object[]{name}); } // call handler if (fDocumentHandler != null && !fScanningAttribute) { if (!name.equals("[xml]")) { fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); } } } // startEntity(String,XMLResourceIdentifier,String)
This method notifies the end of an entity. The DTD has the pseudo-name of "[dtd]" parameter entity names start with '%'; and general entities are just specified by their name.
Params:
  • name – The name of the entity.
  • augs – Additional information that may include infoset augmentations
Throws:
/** * This method notifies the end of an entity. The DTD has the pseudo-name * of "[dtd]" parameter entity names start with '%'; and general entities * are just specified by their name. * * @param name The name of the entity. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */
public void endEntity(String name, Augmentations augs) throws XNIException { // flush possible pending output buffer - see scanContent if (fInScanContent && fStringBuffer.length != 0 && fDocumentHandler != null) { fDocumentHandler.characters(fStringBuffer, null); fStringBuffer.length = 0; // make sure we know it's been flushed } super.endEntity(name, augs); // make sure markup is properly balanced if (fMarkupDepth != fEntityStack[fEntityDepth]) { reportFatalError("MarkupEntityMismatch", null); } // call handler if (fDocumentHandler != null && !fScanningAttribute) { if (!name.equals("[xml]")) { fDocumentHandler.endGeneralEntity(name, augs); } } } // endEntity(String) // // Protected methods // // dispatcher factory methods
Creates a content dispatcher.
/** Creates a content dispatcher. */
protected Dispatcher createContentDispatcher() { return new FragmentContentDispatcher(); } // createContentDispatcher():Dispatcher // scanning methods
Scans an XML or text declaration.

[23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
[24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
[80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
[81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
[32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
                | ('"' ('yes' | 'no') '"'))
[77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
Params:
  • scanningTextDecl – True if a text declaration is to be scanned instead of an XML declaration.
/** * Scans an XML or text declaration. * <p> * <pre> * [23] XMLDecl ::= '&lt;?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ") * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") * | ('"' ('yes' | 'no') '"')) * * [77] TextDecl ::= '&lt;?xml' VersionInfo? EncodingDecl S? '?>' * </pre> * * @param scanningTextDecl True if a text declaration is to * be scanned instead of an XML * declaration. */
protected void scanXMLDeclOrTextDecl(boolean scanningTextDecl) throws IOException, XNIException { // scan decl super.scanXMLDeclOrTextDecl(scanningTextDecl, fStrings); fMarkupDepth--; // pseudo-attribute values String version = fStrings[0]; String encoding = fStrings[1]; String standalone = fStrings[2]; // set standalone fStandalone = standalone != null && standalone.equals("yes"); fEntityManager.setStandalone(fStandalone); // set version on reader fEntityScanner.setXMLVersion(version); // call handler if (fDocumentHandler != null) { if (scanningTextDecl) { fDocumentHandler.textDecl(version, encoding, null); } else { fDocumentHandler.xmlDecl(version, encoding, standalone, null); } } // set encoding on reader if (encoding != null && !fEntityScanner.fCurrentEntity.isEncodingExternallySpecified()) { fEntityScanner.setEncoding(encoding); } } // scanXMLDeclOrTextDecl(boolean)
Scans a processing data. This is needed to handle the situation where a document starts with a processing instruction whose target name starts with "xml". (e.g. xmlfoo)
Params:
  • target – The PI target
  • data – The string to fill in with the data
/** * Scans a processing data. This is needed to handle the situation * where a document starts with a processing instruction whose * target name <em>starts with</em> "xml". (e.g. xmlfoo) * * @param target The PI target * @param data The string to fill in with the data */
protected void scanPIData(String target, XMLString data) throws IOException, XNIException { super.scanPIData(target, data); fMarkupDepth--; // call handler if (fDocumentHandler != null) { fDocumentHandler.processingInstruction(target, data, null); } } // scanPIData(String)
Scans a comment.

[15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'

Note: Called after scanning past '<!--'

/** * Scans a comment. * <p> * <pre> * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->' * </pre> * <p> * <strong>Note:</strong> Called after scanning past '&lt;!--' */
protected void scanComment() throws IOException, XNIException { scanComment(fStringBuffer); fMarkupDepth--; // call handler if (fDocumentHandler != null) { fDocumentHandler.comment(fStringBuffer, null); } } // scanComment()
Scans a start element. This method will handle the binding of namespace information and notifying the handler of the start of the element.

[44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
[40] STag ::= '<' Name (S Attribute)* S? '>'

Note: This method assumes that the leading '<' character has been consumed.

Note: This method uses the fElementQName and fAttributes variables. The contents of these variables will be destroyed. The caller should copy important information out of these variables before calling this method.

Returns:True if element is empty. (i.e. It matches production [44].
/** * Scans a start element. This method will handle the binding of * namespace information and notifying the handler of the start * of the element. * <p> * <pre> * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>' * [40] STag ::= '&lt;' Name (S Attribute)* S? '>' * </pre> * <p> * <strong>Note:</strong> This method assumes that the leading * '&lt;' character has been consumed. * <p> * <strong>Note:</strong> This method uses the fElementQName and * fAttributes variables. The contents of these variables will be * destroyed. The caller should copy important information out of * these variables before calling this method. * * @return True if element is empty. (i.e. It matches * production [44]. */
protected boolean scanStartElement() throws IOException, XNIException { if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanStartElement()"); // name if (fNamespaces) { fEntityScanner.scanQName(fElementQName); } else { String name = fEntityScanner.scanName(); fElementQName.setValues(null, name, name, null); } String rawname = fElementQName.rawname; // push element stack fCurrentElement = fElementStack.pushElement(fElementQName); // attributes boolean empty = false; fAttributes.removeAllAttributes(); do { // spaces boolean sawSpace = fEntityScanner.skipSpaces(); // end tag? int c = fEntityScanner.peekChar(); if (c == '>') { fEntityScanner.scanChar(); break; } else if (c == '/') { fEntityScanner.scanChar(); if (!fEntityScanner.skipChar('>')) { reportFatalError("ElementUnterminated", new Object[]{rawname}); } empty = true; break; } else if (!isValidNameStartChar(c) || !sawSpace) { // Second chance. Check if this character is a high // surrogate of a valid name start character. if (!isValidNameStartHighSurrogate(c) || !sawSpace) { reportFatalError("ElementUnterminated", new Object[] { rawname }); } } // attributes scanAttribute(fAttributes); } while (true); // call handler if (fDocumentHandler != null) { if (empty) { //decrease the markup depth.. fMarkupDepth--; // check that this element was opened in the same entity if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { reportFatalError("ElementEntityMismatch", new Object[]{fCurrentElement.rawname}); } fDocumentHandler.emptyElement(fElementQName, fAttributes, null); //pop the element off the stack.. fElementStack.popElement(fElementQName); } else { fDocumentHandler.startElement(fElementQName, fAttributes, null); } } if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElement(): "+empty); return empty; } // scanStartElement():boolean
Scans the name of an element in a start or empty tag.
See Also:
  • scanStartElement()
/** * Scans the name of an element in a start or empty tag. * * @see #scanStartElement() */
protected void scanStartElementName () throws IOException, XNIException { // name if (fNamespaces) { fEntityScanner.scanQName(fElementQName); } else { String name = fEntityScanner.scanName(); fElementQName.setValues(null, name, name, null); } // Must skip spaces here because the DTD scanner // would consume them at the end of the external subset. fSawSpace = fEntityScanner.skipSpaces(); } // scanStartElementName()
Scans the remainder of a start or empty tag after the element name.
See Also:
  • scanStartElement
Returns:True if element is empty.
/** * Scans the remainder of a start or empty tag after the element name. * * @see #scanStartElement * @return True if element is empty. */
protected boolean scanStartElementAfterName() throws IOException, XNIException { String rawname = fElementQName.rawname; // push element stack fCurrentElement = fElementStack.pushElement(fElementQName); // attributes boolean empty = false; fAttributes.removeAllAttributes(); do { // end tag? int c = fEntityScanner.peekChar(); if (c == '>') { fEntityScanner.scanChar(); break; } else if (c == '/') { fEntityScanner.scanChar(); if (!fEntityScanner.skipChar('>')) { reportFatalError("ElementUnterminated", new Object[]{rawname}); } empty = true; break; } else if (!isValidNameStartChar(c) || !fSawSpace) { // Second chance. Check if this character is a high // surrogate of a valid name start character. if (!isValidNameStartHighSurrogate(c) || !fSawSpace) { reportFatalError("ElementUnterminated", new Object[] { rawname }); } } // attributes scanAttribute(fAttributes); // spaces fSawSpace = fEntityScanner.skipSpaces(); } while (true); // call handler if (fDocumentHandler != null) { if (empty) { //decrease the markup depth.. fMarkupDepth--; // check that this element was opened in the same entity if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { reportFatalError("ElementEntityMismatch", new Object[]{fCurrentElement.rawname}); } fDocumentHandler.emptyElement(fElementQName, fAttributes, null); //pop the element off the stack.. fElementStack.popElement(fElementQName); } else { fDocumentHandler.startElement(fElementQName, fAttributes, null); } } if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElementAfterName(): "+empty); return empty; } // scanStartElementAfterName()
Scans an attribute.

[41] Attribute ::= Name Eq AttValue

Note: This method assumes that the next character on the stream is the first character of the attribute name.

Note: This method uses the fAttributeQName and fQName variables. The contents of these variables will be destroyed.

Params:
  • attributes – The attributes list for the scanned attribute.
/** * Scans an attribute. * <p> * <pre> * [41] Attribute ::= Name Eq AttValue * </pre> * <p> * <strong>Note:</strong> This method assumes that the next * character on the stream is the first character of the attribute * name. * <p> * <strong>Note:</strong> This method uses the fAttributeQName and * fQName variables. The contents of these variables will be * destroyed. * * @param attributes The attributes list for the scanned attribute. */
protected void scanAttribute(XMLAttributes attributes) throws IOException, XNIException { if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanAttribute()"); // name if (fNamespaces) { fEntityScanner.scanQName(fAttributeQName); } else { String name = fEntityScanner.scanName(); fAttributeQName.setValues(null, name, name, null); } // equals fEntityScanner.skipSpaces(); if (!fEntityScanner.skipChar('=')) { reportFatalError("EqRequiredInAttribute", new Object[]{fCurrentElement.rawname,fAttributeQName.rawname}); } fEntityScanner.skipSpaces(); // content int oldLen = attributes.getLength(); int attrIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null); // WFC: Unique Att Spec if (oldLen == attributes.getLength()) { reportFatalError("AttributeNotUnique", new Object[]{fCurrentElement.rawname, fAttributeQName.rawname}); } // Scan attribute value and return true if the un-normalized and normalized value are the same boolean isSameNormalizedAttr = scanAttributeValue(fTempString, fTempString2, fAttributeQName.rawname, fIsEntityDeclaredVC, fCurrentElement.rawname); attributes.setValue(attrIndex, fTempString.toString()); // If the non-normalized and normalized value are the same, avoid creating a new string. if (!isSameNormalizedAttr) { attributes.setNonNormalizedValue(attrIndex, fTempString2.toString()); } attributes.setSpecified(attrIndex, true); if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanAttribute()"); } // scanAttribute(XMLAttributes)
Scans element content.
Returns:Returns the next character on the stream.
/** * Scans element content. * * @return Returns the next character on the stream. */
protected int scanContent() throws IOException, XNIException { XMLString content = fTempString; int c = fEntityScanner.scanContent(content); if (c == '\r') { // happens when there is the character reference &#13; fEntityScanner.scanChar(); fStringBuffer.clear(); fStringBuffer.append(fTempString); fStringBuffer.append((char)c); content = fStringBuffer; c = -1; } if (fDocumentHandler != null && content.length > 0) { fDocumentHandler.characters(content, null); } if (c == ']' && fTempString.length == 0) { fStringBuffer.clear(); fStringBuffer.append((char)fEntityScanner.scanChar()); // remember where we are in case we get an endEntity before we // could flush the buffer out - this happens when we're parsing an // entity which ends with a ] fInScanContent = true; // // We work on a single character basis to handle cases such as: // ']]]>' which we might otherwise miss. // if (fEntityScanner.skipChar(']')) { fStringBuffer.append(']'); while (fEntityScanner.skipChar(']')) { fStringBuffer.append(']'); } if (fEntityScanner.skipChar('>')) { reportFatalError("CDEndInContent", null); } } if (fDocumentHandler != null && fStringBuffer.length != 0) { fDocumentHandler.characters(fStringBuffer, null); } fInScanContent = false; c = -1; } return c; } // scanContent():int
Scans a CDATA section.

Note: This method uses the fTempString and fStringBuffer variables.

Params:
  • complete – True if the CDATA section is to be scanned completely.
Returns:True if CDATA is completely scanned.
/** * Scans a CDATA section. * <p> * <strong>Note:</strong> This method uses the fTempString and * fStringBuffer variables. * * @param complete True if the CDATA section is to be scanned * completely. * * @return True if CDATA is completely scanned. */
protected boolean scanCDATASection(boolean complete) throws IOException, XNIException { // call handler if (fDocumentHandler != null) { fDocumentHandler.startCDATA(null); } while (true) { fStringBuffer.clear(); if (!fEntityScanner.scanData("]]", fStringBuffer)) { if (fDocumentHandler != null && fStringBuffer.length > 0) { fDocumentHandler.characters(fStringBuffer, null); } int brackets = 0; while (fEntityScanner.skipChar(']')) { brackets++; } if (fDocumentHandler != null && brackets > 0) { fStringBuffer.clear(); if (brackets > XMLEntityManager.DEFAULT_BUFFER_SIZE) { // Handle large sequences of ']' int chunks = brackets / XMLEntityManager.DEFAULT_BUFFER_SIZE; int remainder = brackets % XMLEntityManager.DEFAULT_BUFFER_SIZE; for (int i = 0; i < XMLEntityManager.DEFAULT_BUFFER_SIZE; i++) { fStringBuffer.append(']'); } for (int i = 0; i < chunks; i++) { fDocumentHandler.characters(fStringBuffer, null); } if (remainder != 0) { fStringBuffer.length = remainder; fDocumentHandler.characters(fStringBuffer, null); } } else { for (int i = 0; i < brackets; i++) { fStringBuffer.append(']'); } fDocumentHandler.characters(fStringBuffer, null); } } if (fEntityScanner.skipChar('>')) { break; } if (fDocumentHandler != null) { fStringBuffer.clear(); fStringBuffer.append("]]"); fDocumentHandler.characters(fStringBuffer, null); } } else { if (fDocumentHandler != null) { fDocumentHandler.characters(fStringBuffer, null); } int c = fEntityScanner.peekChar(); if (c != -1 && isInvalidLiteral(c)) { if (XMLChar.isHighSurrogate(c)) { fStringBuffer.clear(); scanSurrogates(fStringBuffer); if (fDocumentHandler != null) { fDocumentHandler.characters(fStringBuffer, null); } } else { reportFatalError("InvalidCharInCDSect", new Object[]{Integer.toString(c,16)}); fEntityScanner.scanChar(); } } } } fMarkupDepth--; // call handler if (fDocumentHandler != null) { fDocumentHandler.endCDATA(null); } return true; } // scanCDATASection(boolean):boolean
Scans an end element.

[42] ETag ::= '</' Name S? '>'

Note: This method uses the fElementQName variable. The contents of this variable will be destroyed. The caller should copy the needed information out of this variable before calling this method.

Returns:The element depth.
/** * Scans an end element. * <p> * <pre> * [42] ETag ::= '&lt;/' Name S? '>' * </pre> * <p> * <strong>Note:</strong> This method uses the fElementQName variable. * The contents of this variable will be destroyed. The caller should * copy the needed information out of this variable before calling * this method. * * @return The element depth. */
protected int scanEndElement() throws IOException, XNIException { if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanEndElement()"); fElementStack.popElement(fElementQName) ; // Take advantage of the fact that next string _should_ be "fElementQName.rawName", //In scanners most of the time is consumed on checks done for XML characters, we can // optimize on it and avoid the checks done for endElement, //we will also avoid symbol table lookup - neeraj.bajaj@sun.com // this should work both for namespace processing true or false... //REVISIT: if the string is not the same as expected.. we need to do better error handling.. //We can skip this for now... In any case if the string doesn't match -- document is not well formed. if (!fEntityScanner.skipString(fElementQName.rawname)) { reportFatalError("ETagRequired", new Object[]{fElementQName.rawname}); } // end fEntityScanner.skipSpaces(); if (!fEntityScanner.skipChar('>')) { reportFatalError("ETagUnterminated", new Object[]{fElementQName.rawname}); } fMarkupDepth--; //we have increased the depth for two markup "<" characters fMarkupDepth--; // check that this element was opened in the same entity if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { reportFatalError("ElementEntityMismatch", new Object[]{fCurrentElement.rawname}); } // call handler if (fDocumentHandler != null ) { fDocumentHandler.endElement(fElementQName, null); } return fMarkupDepth; } // scanEndElement():int
Scans a character reference.

[66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
/** * Scans a character reference. * <p> * <pre> * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';' * </pre> */
protected void scanCharReference() throws IOException, XNIException { fStringBuffer2.clear(); int ch = scanCharReferenceValue(fStringBuffer2, null); fMarkupDepth--; if (ch != -1) { // call handler if (fDocumentHandler != null) { if (fNotifyCharRefs) { fDocumentHandler.startGeneralEntity(fCharRefLiteral, null, null, null); } Augmentations augs = null; if (fValidation && ch <= 0x20) { if (fTempAugmentations != null) { fTempAugmentations.removeAllItems(); } else { fTempAugmentations = new AugmentationsImpl(); } augs = fTempAugmentations; augs.putItem(Constants.CHAR_REF_PROBABLE_WS, Boolean.TRUE); } fDocumentHandler.characters(fStringBuffer2, augs); if (fNotifyCharRefs) { fDocumentHandler.endGeneralEntity(fCharRefLiteral, null); } } } } // scanCharReference()
Scans an entity reference.
Throws:
  • IOException – Thrown if i/o error occurs.
  • XNIException – Thrown if handler throws exception upon notification.
/** * Scans an entity reference. * * @throws IOException Thrown if i/o error occurs. * @throws XNIException Thrown if handler throws exception upon * notification. */
protected void scanEntityReference() throws IOException, XNIException { // name String name = fEntityScanner.scanName(); if (name == null) { reportFatalError("NameRequiredInReference", null); return; } // end if (!fEntityScanner.skipChar(';')) { reportFatalError("SemicolonRequiredInReference", new Object []{name}); } fMarkupDepth--; // handle built-in entities if (name == fAmpSymbol) { handleCharacter('&', fAmpSymbol); } else if (name == fLtSymbol) { handleCharacter('<', fLtSymbol); } else if (name == fGtSymbol) { handleCharacter('>', fGtSymbol); } else if (name == fQuotSymbol) { handleCharacter('"', fQuotSymbol); } else if (name == fAposSymbol) { handleCharacter('\'', fAposSymbol); } // start general entity else if (fEntityManager.isUnparsedEntity(name)) { reportFatalError("ReferenceToUnparsedEntity", new Object[]{name}); } else { if (!fEntityManager.isDeclaredEntity(name)) { if (fIsEntityDeclaredVC) { if (fValidation) fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared", new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR); } else { reportFatalError("EntityNotDeclared", new Object[]{name}); } } fEntityManager.startEntity(name, false); } } // scanEntityReference() // utility methods
Calls document handler with a single character resulting from built-in entity resolution.
Params:
  • c –
  • entity – built-in name
/** * Calls document handler with a single character resulting from * built-in entity resolution. * * @param c * @param entity built-in name */
private void handleCharacter(char c, String entity) throws XNIException { if (fDocumentHandler != null) { if (fNotifyBuiltInRefs) { fDocumentHandler.startGeneralEntity(entity, null, null, null); } fSingleChar[0] = c; fTempString.setValues(fSingleChar, 0, 1); fDocumentHandler.characters(fTempString, null); if (fNotifyBuiltInRefs) { fDocumentHandler.endGeneralEntity(entity, null); } } } // handleCharacter(char)
Handles the end element. This method will make sure that the end element name matches the current element and notify the handler about the end of the element and the end of any relevent prefix mappings.

Note: This method uses the fQName variable. The contents of this variable will be destroyed.

Params:
  • element – The element.
Throws:
  • XNIException – Thrown if the handler throws a SAX exception upon notification.
Returns:The element depth.
/** * Handles the end element. This method will make sure that * the end element name matches the current element and notify * the handler about the end of the element and the end of any * relevent prefix mappings. * <p> * <strong>Note:</strong> This method uses the fQName variable. * The contents of this variable will be destroyed. * * @param element The element. * * @return The element depth. * * @throws XNIException Thrown if the handler throws a SAX exception * upon notification. * */
// REVISIT: need to remove this method. It's not called anymore, because // the handling is done when the end tag is scanned. - SG protected int handleEndElement(QName element, boolean isEmpty) throws XNIException { fMarkupDepth--; // check that this element was opened in the same entity if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) { reportFatalError("ElementEntityMismatch", new Object[]{fCurrentElement.rawname}); } // make sure the elements match QName startElement = fQName; fElementStack.popElement(startElement); if (element.rawname != startElement.rawname) { reportFatalError("ETagRequired", new Object[]{startElement.rawname}); } // bind namespaces if (fNamespaces) { element.uri = startElement.uri; } // call handler if (fDocumentHandler != null && !isEmpty) { fDocumentHandler.endElement(element, null); } return fMarkupDepth; } // callEndElement(QName,boolean):int // helper methods
Sets the scanner state.
Params:
  • state – The new scanner state.
/** * Sets the scanner state. * * @param state The new scanner state. */
protected final void setScannerState(int state) { fScannerState = state; if (DEBUG_SCANNER_STATE) { System.out.print("### setScannerState: "); System.out.print(getScannerStateName(state)); System.out.println(); } } // setScannerState(int)
Sets the dispatcher.
Params:
  • dispatcher – The new dispatcher.
/** * Sets the dispatcher. * * @param dispatcher The new dispatcher. */
protected final void setDispatcher(Dispatcher dispatcher) { fDispatcher = dispatcher; if (DEBUG_DISPATCHER) { System.out.print("%%% setDispatcher: "); System.out.print(getDispatcherName(dispatcher)); System.out.println(); } } // // Private methods //
Returns the scanner state name.
/** Returns the scanner state name. */
protected String getScannerStateName(int state) { switch (state) { case SCANNER_STATE_DOCTYPE: return "SCANNER_STATE_DOCTYPE"; case SCANNER_STATE_ROOT_ELEMENT: return "SCANNER_STATE_ROOT_ELEMENT"; case SCANNER_STATE_START_OF_MARKUP: return "SCANNER_STATE_START_OF_MARKUP"; case SCANNER_STATE_COMMENT: return "SCANNER_STATE_COMMENT"; case SCANNER_STATE_PI: return "SCANNER_STATE_PI"; case SCANNER_STATE_CONTENT: return "SCANNER_STATE_CONTENT"; case SCANNER_STATE_REFERENCE: return "SCANNER_STATE_REFERENCE"; case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT"; case SCANNER_STATE_TERMINATED: return "SCANNER_STATE_TERMINATED"; case SCANNER_STATE_CDATA: return "SCANNER_STATE_CDATA"; case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL"; } return "??? ("+state+')'; } // getScannerStateName(int):String
Returns the dispatcher name.
/** Returns the dispatcher name. */
public String getDispatcherName(Dispatcher dispatcher) { if (DEBUG_DISPATCHER) { if (dispatcher != null) { String name = dispatcher.getClass().getName(); int index = name.lastIndexOf('.'); if (index != -1) { name = name.substring(index + 1); index = name.lastIndexOf('$'); if (index != -1) { name = name.substring(index + 1); } } return name; } } return "null"; } // getDispatcherName():String // // Classes //
Element stack. This stack operates without synchronization, error checking, and it re-uses objects instead of throwing popped items away.
Author:Andy Clark, IBM
/** * Element stack. This stack operates without synchronization, error * checking, and it re-uses objects instead of throwing popped items * away. * * @author Andy Clark, IBM */
protected static class ElementStack { // // Data //
The stack data.
/** The stack data. */
protected QName[] fElements;
The size of the stack.
/** The size of the stack. */
protected int fSize; // // Constructors //
Default constructor.
/** Default constructor. */
public ElementStack() { fElements = new QName[10]; for (int i = 0; i < fElements.length; i++) { fElements[i] = new QName(); } } // <init>() // // Public methods //
Pushes an element on the stack.

Note: The QName values are copied into the stack. In other words, the caller does not orphan the element to the stack. Also, the QName object returned is not orphaned to the caller. It should be considered read-only.

Params:
  • element – The element to push onto the stack.
Returns:Returns the actual QName object that stores the
/** * Pushes an element on the stack. * <p> * <strong>Note:</strong> The QName values are copied into the * stack. In other words, the caller does <em>not</em> orphan * the element to the stack. Also, the QName object returned * is <em>not</em> orphaned to the caller. It should be * considered read-only. * * @param element The element to push onto the stack. * * @return Returns the actual QName object that stores the */
public QName pushElement(QName element) { if (fSize == fElements.length) { QName[] array = new QName[fElements.length * 2]; System.arraycopy(fElements, 0, array, 0, fSize); fElements = array; for (int i = fSize; i < fElements.length; i++) { fElements[i] = new QName(); } } fElements[fSize].setValues(element); return fElements[fSize++]; } // pushElement(QName):QName
Pops an element off of the stack by setting the values of the specified QName.

Note: The object returned is not orphaned to the caller. Therefore, the caller should consider the object to be read-only.

/** * Pops an element off of the stack by setting the values of * the specified QName. * <p> * <strong>Note:</strong> The object returned is <em>not</em> * orphaned to the caller. Therefore, the caller should consider * the object to be read-only. */
public void popElement(QName element) { element.setValues(fElements[--fSize]); } // popElement(QName)
Clears the stack without throwing away existing QName objects.
/** Clears the stack without throwing away existing QName objects. */
public void clear() { fSize = 0; } // clear() } // class ElementStack
This interface defines an XML "event" dispatching model. Classes that implement this interface are responsible for scanning parts of the XML document and dispatching callbacks.
Author:Glenn Marcy, IBM
@xerces.internal
/** * This interface defines an XML "event" dispatching model. Classes * that implement this interface are responsible for scanning parts * of the XML document and dispatching callbacks. * * @xerces.internal * * @author Glenn Marcy, IBM */
protected interface Dispatcher { // // Dispatcher methods //
Dispatch an XML "event".
Params:
  • complete – True if this dispatcher is intended to scan and dispatch as much as possible.
Throws:
Returns:True if there is more to dispatch either from this or a another dispatcher.
/** * Dispatch an XML "event". * * @param complete True if this dispatcher is intended to scan * and dispatch as much as possible. * * @return True if there is more to dispatch either from this * or a another dispatcher. * * @throws IOException Thrown on i/o error. * @throws XNIException Thrown on parse error. */
public boolean dispatch(boolean complete) throws IOException, XNIException; } // interface Dispatcher
Dispatcher to handle content scanning.
Author:Andy Clark, IBM, Eric Ye, IBM
/** * Dispatcher to handle content scanning. * * @author Andy Clark, IBM * @author Eric Ye, IBM */
protected class FragmentContentDispatcher implements Dispatcher { // // Dispatcher methods //
Dispatch an XML "event".
Params:
  • complete – True if this dispatcher is intended to scan and dispatch as much as possible.
Throws:
Returns:True if there is more to dispatch either from this or a another dispatcher.
/** * Dispatch an XML "event". * * @param complete True if this dispatcher is intended to scan * and dispatch as much as possible. * * @return True if there is more to dispatch either from this * or a another dispatcher. * * @throws IOException Thrown on i/o error. * @throws XNIException Thrown on parse error. */
public boolean dispatch(boolean complete) throws IOException, XNIException { try { boolean again; do { again = false; switch (fScannerState) { case SCANNER_STATE_CONTENT: { if (fEntityScanner.skipChar('<')) { setScannerState(SCANNER_STATE_START_OF_MARKUP); again = true; } else if (fEntityScanner.skipChar('&')) { setScannerState(SCANNER_STATE_REFERENCE); again = true; } else { do { int c = scanContent(); if (c == '<') { fEntityScanner.scanChar(); setScannerState(SCANNER_STATE_START_OF_MARKUP); break; } else if (c == '&') { fEntityScanner.scanChar(); setScannerState(SCANNER_STATE_REFERENCE); break; } else if (c != -1 && isInvalidLiteral(c)) { if (XMLChar.isHighSurrogate(c)) { // special case: surrogates fStringBuffer.clear(); if (scanSurrogates(fStringBuffer)) { // call handler if (fDocumentHandler != null) { fDocumentHandler.characters(fStringBuffer, null); } } } else { reportFatalError("InvalidCharInContent", new Object[] { Integer.toString(c, 16)}); fEntityScanner.scanChar(); } } } while (complete); } break; } case SCANNER_STATE_START_OF_MARKUP: { fMarkupDepth++; if (fEntityScanner.skipChar('/')) { if (scanEndElement() == 0) { if (elementDepthIsZeroHook()) { return true; } } setScannerState(SCANNER_STATE_CONTENT); } else if (isValidNameStartChar(fEntityScanner.peekChar())) { scanStartElement(); setScannerState(SCANNER_STATE_CONTENT); } else if (fEntityScanner.skipChar('!')) { if (fEntityScanner.skipChar('-')) { if (!fEntityScanner.skipChar('-')) { reportFatalError("InvalidCommentStart", null); } setScannerState(SCANNER_STATE_COMMENT); again = true; } else if (fEntityScanner.skipString("[CDATA[")) { setScannerState(SCANNER_STATE_CDATA); again = true; } else if (!scanForDoctypeHook()) { reportFatalError("MarkupNotRecognizedInContent", null); } } else if (fEntityScanner.skipChar('?')) { setScannerState(SCANNER_STATE_PI); again = true; } else if (isValidNameStartHighSurrogate(fEntityScanner.peekChar())) { scanStartElement(); setScannerState(SCANNER_STATE_CONTENT); } else { reportFatalError("MarkupNotRecognizedInContent", null); setScannerState(SCANNER_STATE_CONTENT); } break; } case SCANNER_STATE_COMMENT: { scanComment(); setScannerState(SCANNER_STATE_CONTENT); break; } case SCANNER_STATE_PI: { scanPI(); setScannerState(SCANNER_STATE_CONTENT); break; } case SCANNER_STATE_CDATA: { scanCDATASection(complete); setScannerState(SCANNER_STATE_CONTENT); break; } case SCANNER_STATE_REFERENCE: { fMarkupDepth++; // NOTE: We need to set the state beforehand // because the XMLEntityHandler#startEntity // callback could set the state to // SCANNER_STATE_TEXT_DECL and we don't want // to override that scanner state. setScannerState(SCANNER_STATE_CONTENT); if (fEntityScanner.skipChar('#')) { scanCharReference(); } else { scanEntityReference(); } break; } case SCANNER_STATE_TEXT_DECL: { // scan text decl if (fEntityScanner.skipString("<?xml")) { fMarkupDepth++; // NOTE: special case where entity starts with a PI // whose name starts with "xml" (e.g. "xmlfoo") if (isValidNameChar(fEntityScanner.peekChar())) { fStringBuffer.clear(); fStringBuffer.append("xml"); if (fNamespaces) { while (isValidNCName(fEntityScanner.peekChar())) { fStringBuffer.append((char)fEntityScanner.scanChar()); } } else { while (isValidNameChar(fEntityScanner.peekChar())) { fStringBuffer.append((char)fEntityScanner.scanChar()); } } String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length); scanPIData(target, fTempString); } // standard text declaration else { scanXMLDeclOrTextDecl(true); } } // now that we've straightened out the readers, we can read in chunks: fEntityManager.fCurrentEntity.mayReadChunks = true; setScannerState(SCANNER_STATE_CONTENT); break; } case SCANNER_STATE_ROOT_ELEMENT: { if (scanRootElementHook()) { return true; } setScannerState(SCANNER_STATE_CONTENT); break; } case SCANNER_STATE_DOCTYPE: { reportFatalError("DoctypeIllegalInContent", null); setScannerState(SCANNER_STATE_CONTENT); } } } while (complete || again); } // encoding errors catch (MalformedByteSequenceException e) { fErrorReporter.reportError(e.getDomain(), e.getKey(), e.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, e); return false; } catch (CharConversionException e) { fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, "CharConversionFailure", null, XMLErrorReporter.SEVERITY_FATAL_ERROR, e); return false; } // premature end of file catch (EOFException e) { endOfFileHook(e); return false; } return true; } // dispatch(boolean):boolean // // Protected methods // // hooks // NOTE: These hook methods are added so that the full document // scanner can share the majority of code with this class.
Scan for DOCTYPE hook. This method is a hook for subclasses to add code to handle scanning for a the "DOCTYPE" string after the string "
Returns:True if the "DOCTYPE" was scanned; false if "DOCTYPE" was not scanned.
/** * Scan for DOCTYPE hook. This method is a hook for subclasses * to add code to handle scanning for a the "DOCTYPE" string * after the string "<!" has been scanned. * * @return True if the "DOCTYPE" was scanned; false if "DOCTYPE" * was not scanned. */
protected boolean scanForDoctypeHook() throws IOException, XNIException { return false; } // scanForDoctypeHook():boolean
Element depth iz zero. This methos is a hook for subclasses to add code to handle when the element depth hits zero. When scanning a document fragment, an element depth of zero is normal. However, when scanning a full XML document, the scanner must handle the trailing miscellanous section of the document after the end of the document's root element.
Returns:True if the caller should stop and return true which allows the scanner to switch to a new scanning dispatcher. A return value of false indicates that the content dispatcher should continue as normal.
/** * Element depth iz zero. This methos is a hook for subclasses * to add code to handle when the element depth hits zero. When * scanning a document fragment, an element depth of zero is * normal. However, when scanning a full XML document, the * scanner must handle the trailing miscellanous section of * the document after the end of the document's root element. * * @return True if the caller should stop and return true which * allows the scanner to switch to a new scanning * dispatcher. A return value of false indicates that * the content dispatcher should continue as normal. */
protected boolean elementDepthIsZeroHook() throws IOException, XNIException { return false; } // elementDepthIsZeroHook():boolean
Scan for root element hook. This method is a hook for subclasses to add code that handles scanning for the root element. When scanning a document fragment, there is no "root" element. However, when scanning a full XML document, the scanner must handle the root element specially.
Returns:True if the caller should stop and return true which allows the scanner to switch to a new scanning dispatcher. A return value of false indicates that the content dispatcher should continue as normal.
/** * Scan for root element hook. This method is a hook for * subclasses to add code that handles scanning for the root * element. When scanning a document fragment, there is no * "root" element. However, when scanning a full XML document, * the scanner must handle the root element specially. * * @return True if the caller should stop and return true which * allows the scanner to switch to a new scanning * dispatcher. A return value of false indicates that * the content dispatcher should continue as normal. */
protected boolean scanRootElementHook() throws IOException, XNIException { return false; } // scanRootElementHook():boolean
End of file hook. This method is a hook for subclasses to add code that handles the end of file. The end of file in a document fragment is OK if the markup depth is zero. However, when scanning a full XML document, an end of file is always premature.
/** * End of file hook. This method is a hook for subclasses to * add code that handles the end of file. The end of file in * a document fragment is OK if the markup depth is zero. * However, when scanning a full XML document, an end of file * is always premature. */
protected void endOfFileHook(EOFException e) throws IOException, XNIException { // NOTE: An end of file is only only an error if we were // in the middle of scanning some markup. -Ac if (fMarkupDepth != 0) { reportFatalError("PrematureEOF", null); } } // endOfFileHook() } // class FragmentContentDispatcher } // class XMLDocumentFragmentScannerImpl