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

org.htmlunit.cyberneko.xerces.parsers.AbstractSAXParser Maven / Gradle / Ivy

/*
 * Copyright (c) 2017-2024 Ronald Brill
 *
 * Licensed 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
 * https://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.htmlunit.cyberneko.xerces.parsers;

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

import org.htmlunit.cyberneko.xerces.util.ErrorHandlerWrapper;
import org.htmlunit.cyberneko.xerces.util.SAXMessageFormatter;
import org.htmlunit.cyberneko.xerces.xni.Augmentations;
import org.htmlunit.cyberneko.xerces.xni.NamespaceContext;
import org.htmlunit.cyberneko.xerces.xni.QName;
import org.htmlunit.cyberneko.xerces.xni.XMLAttributes;
import org.htmlunit.cyberneko.xerces.xni.XMLLocator;
import org.htmlunit.cyberneko.xerces.xni.XMLString;
import org.htmlunit.cyberneko.xerces.xni.XNIException;
import org.htmlunit.cyberneko.xerces.xni.parser.XMLConfigurationException;
import org.htmlunit.cyberneko.xerces.xni.parser.XMLErrorHandler;
import org.htmlunit.cyberneko.xerces.xni.parser.XMLInputSource;
import org.htmlunit.cyberneko.xerces.xni.parser.XMLParseException;
import org.htmlunit.cyberneko.xerces.xni.parser.XMLParserConfiguration;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.Attributes2;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.ext.Locator2;
import org.xml.sax.ext.Locator2Impl;

/**
 * This is the base class of all SAX parsers. It implements both the SAX1 and
 * SAX2 parser functionality, while the actual pipeline is defined in the parser
 * configuration.
 *
 * @author Arnaud Le Hors, IBM
 * @author Andy Clark, IBM
 */
public abstract class AbstractSAXParser extends AbstractXMLDocumentParser implements XMLReader { // SAX2

    // features

    /** Feature identifier: namespaces. */
    protected static final String NAMESPACES = Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;

    /** Recognized features. */
    private static final String[] RECOGNIZED_FEATURES = {NAMESPACES};

    // properties

    /** Property id: lexical handler. */
    protected static final String LEXICAL_HANDLER = Constants.SAX_PROPERTY_PREFIX + Constants.LEXICAL_HANDLER_PROPERTY;

    /** Recognized properties. */
    private static final String[] RECOGNIZED_PROPERTIES = {LEXICAL_HANDLER};

    // features

    /** Namespaces. */
    protected boolean fNamespaces;

    /** Namespace prefixes. */
    protected boolean fNamespacePrefixes = false;

    /** Lexical handler parameter entities. */
    protected boolean fLexicalHandlerParameterEntities = true;

    /** Standalone document declaration. */
    protected boolean fStandalone;

    /** Use EntityResolver2. */
    protected boolean fUseEntityResolver2 = true;

    // parser handlers

    /** Content handler. */
    protected ContentHandler fContentHandler;

    /** Namespace context */
    protected NamespaceContext fNamespaceContext;

    /** DTD handler. */
    protected org.xml.sax.DTDHandler fDTDHandler;

    /** Lexical handler. */
    protected LexicalHandler fLexicalHandler;

    // state

    /**
     * True if a parse is in progress. This state is needed because some
     * features/properties cannot be set while parsing (e.g. validation and
     * namespaces).
     */
    protected final boolean fParseInProgress = false;

    // track the version of the document being parsed
    protected String fVersion;

    // temp vars
    private final AttributesProxy fAttributesProxy = new AttributesProxy();

    // Default constructor.
    protected AbstractSAXParser(final XMLParserConfiguration config) {
        super(config);

        config.addRecognizedFeatures(RECOGNIZED_FEATURES);
        config.addRecognizedProperties(RECOGNIZED_PROPERTIES);
    }

    /**
     * The start of the document.
     *
     * @param locator          The document locator, or null if the document
     *                         location cannot be reported during the parsing of
     *                         this document. However, it is strongly
     *                         recommended that a locator be supplied that can at
     *                         least report the system identifier of the document.
     * @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.
     */
    @Override
    public void startDocument(final XMLLocator locator, final String encoding, final NamespaceContext namespaceContext, final Augmentations augs) throws XNIException {

        fNamespaceContext = namespaceContext;

        try {
            // SAX2
            if (fContentHandler != null) {
                if (locator != null) {
                    fContentHandler.setDocumentLocator(new LocatorProxy(locator));
                }
                // The application may have set the ContentHandler to null
                // within setDocumentLocator() so we need to check again.
                if (fContentHandler != null) {
                    fContentHandler.startDocument();
                }
            }
        }
        catch (final SAXException e) {
            throw new XNIException(e);
        }
    }

    /**
     * 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.
     */
    @Override
    public void xmlDecl(final String version, final String encoding, final String standalone, final Augmentations augs) throws XNIException {
        // the version need only be set once; if
        // document's XML 1.0|1.1, that's how it'll stay
        fVersion = version;
        fStandalone = "yes".equals(standalone);
    }

    /**
     * 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.
     */
    @Override
    public void doctypeDecl(final String rootElement, final String publicId, final String systemId, final Augmentations augs)
            throws XNIException {

        try {
            // SAX2 extension
            if (fLexicalHandler != null) {
                fLexicalHandler.startDTD(rootElement, publicId, systemId);
            }
        }
        catch (final SAXException e) {
            throw new XNIException(e);
        }
    }

    /**
     * This method notifies of the start of an entity. The DTD has the pseudo-name
     * of "[dtd]" parameter entity names start with '%'; and general entity names
     * are just the entity name.
     * 

* Note: Since the document is an entity, the handler will be * notified of the start of the document entity by calling the startEntity * method with the entity name "[xml]" before calling the startDocument * method. When exposing entity boundaries through the SAX API, the document * entity is never reported, however. *

* Note: This method is not called for entity references * appearing as part of attribute values. * * @param name The name of the entity. * @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 parameter * entities). * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ @Override public void startGeneralEntity(final String name, final String encoding, final Augmentations augs) throws XNIException { try { // SAX2 extension if (fLexicalHandler != null) { fLexicalHandler.startEntity(name); } } catch (final SAXException e) { throw new XNIException(e); } } /** * This method notifies the end of an entity. The DTD has the pseudo-name of * "[dtd]" parameter entity names start with '%'; and general entity names are * just the entity name. *

* Note: Since the document is an entity, the handler will be * notified of the end of the document entity by calling the endEntity method * with the entity name "[xml]" after calling the endDocument method. * When exposing entity boundaries through the SAX API, the document entity is * never reported, however. *

* Note: This method is not called for entity references * appearing as part of attribute values. * * @param name The name of the entity. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ @Override public void endGeneralEntity(final String name, final Augmentations augs) throws XNIException { try { // SAX2 extension if (fLexicalHandler != null) { fLexicalHandler.endEntity(name); } } catch (final SAXException e) { throw new XNIException(e); } } /** * The start of an element. If the document specifies the start element by using * an empty tag, then the startElement method will immediately be followed by * the endElement method, with no intervening methods. * * @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. */ @Override public void startElement(final QName element, final XMLAttributes attributes, final Augmentations augs) throws XNIException { try { // SAX2 if (fContentHandler != null) { if (fNamespaces) { // send prefix mapping events startNamespaceMapping(); } final String uri = element.getUri() != null ? element.getUri() : ""; final String localpart = fNamespaces ? element.getLocalpart() : ""; fAttributesProxy.setAttributes(attributes); fContentHandler.startElement(uri, localpart, element.getRawname(), fAttributesProxy); } } catch (final SAXException e) { throw new XNIException(e); } } /** * Character content. * * @param text The content. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ @Override public void characters(final XMLString text, final Augmentations augs) throws XNIException { // if type is union (XML Schema) it is possible that we receive // character call with empty data if (text.length() == 0) { return; } try { // SAX2 if (fContentHandler != null) { text.characters(fContentHandler); } } catch (final SAXException e) { throw new XNIException(e); } } /** * 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. */ @Override public void ignorableWhitespace(final XMLString text, final Augmentations augs) throws XNIException { try { // SAX2 if (fContentHandler != null) { text.ignorableWhitespace(fContentHandler); } } catch (final SAXException e) { throw new XNIException(e); } } /** * 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. */ @Override public void endElement(final QName element, final Augmentations augs) throws XNIException { try { // SAX2 if (fContentHandler != null) { final String uri = element.getUri() != null ? element.getUri() : ""; final String localpart = fNamespaces ? element.getLocalpart() : ""; fContentHandler.endElement(uri, localpart, element.getRawname()); if (fNamespaces) { endNamespaceMapping(); } } } catch (final SAXException e) { throw new XNIException(e); } } /** * The start of a CDATA section. * * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ @Override public void startCDATA(final Augmentations augs) throws XNIException { try { // SAX2 extension if (fLexicalHandler != null) { fLexicalHandler.startCDATA(); } } catch (final SAXException e) { throw new XNIException(e); } } /** * The end of a CDATA section. * * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ @Override public void endCDATA(final Augmentations augs) throws XNIException { try { // SAX2 extension if (fLexicalHandler != null) { fLexicalHandler.endCDATA(); } } catch (final SAXException e) { throw new XNIException(e); } } /** * 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. */ @Override public void comment(final XMLString text, final Augmentations augs) throws XNIException { try { // SAX2 extension if (fLexicalHandler != null) { text.comment(fLexicalHandler); } } catch (final SAXException e) { throw new XNIException(e); } } /** * A processing instruction. Processing instructions consist of a target name * and, optionally, text data. The data is only meaningful to the application. *

* Typically, a processing instruction's data will contain a series of * pseudo-attributes. These pseudo-attributes follow the form of element * attributes but are not parsed or presented to the * application as anything other than text. The application is responsible for * parsing the data. * * @param target The target. * @param data The data or null if none specified. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ @Override public void processingInstruction(final String target, final XMLString data, final Augmentations augs) throws XNIException { // REVISIT - I keep running into SAX apps that expect // null data to be an empty string, which is contrary // to the comment for this method in the SAX API. try { // SAX2 if (fContentHandler != null) { fContentHandler.processingInstruction(target, data.toString()); } } catch (final SAXException e) { throw new XNIException(e); } } /** * The end of the document. * * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ @Override public void endDocument(final Augmentations augs) throws XNIException { try { // SAX2 if (fContentHandler != null) { fContentHandler.endDocument(); } } catch (final SAXException e) { throw new XNIException(e); } } /** * Parses the input source specified by the given system identifier. *

* This method is equivalent to the following: * *

     * parse(new InputSource(systemId));
     * 
* * @param systemId The system identifier (URI). * * @exception org.xml.sax.SAXException Throws exception on SAX error. * @exception java.io.IOException Throws exception on i/o error. */ @Override public void parse(final String systemId) throws SAXException, IOException { // parse document final XMLInputSource source = new XMLInputSource(null, systemId, null); try { parse(source); } // wrap XNI exceptions as SAX exceptions catch (final XMLParseException e) { final Exception ex = e.getException(); if (ex == null || ex instanceof CharConversionException) { // must be a parser exception; mine it for locator info // and throw a SAXParseException final Locator2Impl locatorImpl = new Locator2Impl(); // since XMLParseExceptions know nothing about encoding, // we cannot return anything meaningful in this context. // We *could* consult the LocatorProxy, but the // application can do this itself if it wishes to possibly // be mislead. locatorImpl.setXMLVersion(fVersion); locatorImpl.setPublicId(e.getPublicId()); locatorImpl.setSystemId(e.getExpandedSystemId()); locatorImpl.setLineNumber(e.getLineNumber()); locatorImpl.setColumnNumber(e.getColumnNumber()); throw (ex == null) ? new SAXParseException(e.getMessage(), locatorImpl) : new SAXParseException(e.getMessage(), locatorImpl, ex); } if (ex instanceof SAXException) { // why did we create an XMLParseException? throw (SAXException) ex; } if (ex instanceof IOException) { throw (IOException) ex; } throw new SAXException(ex); } catch (final XNIException e) { final Exception ex = e.getException(); if (ex == null) { throw new SAXException(e.getMessage()); } if (ex instanceof SAXException) { throw (SAXException) ex; } if (ex instanceof IOException) { throw (IOException) ex; } throw new SAXException(ex); } } /** * {@inheritDoc} */ @Override public void parse(final InputSource inputSource) throws SAXException, IOException { // parse document try { final XMLInputSource xmlInputSource = new XMLInputSource(inputSource.getPublicId(), inputSource.getSystemId(), null); xmlInputSource.setByteStream(inputSource.getByteStream()); xmlInputSource.setCharacterStream(inputSource.getCharacterStream()); xmlInputSource.setEncoding(inputSource.getEncoding()); parse(xmlInputSource); } // wrap XNI exceptions as SAX exceptions catch (final XMLParseException e) { final Exception ex = e.getException(); if (ex == null || ex instanceof CharConversionException) { // must be a parser exception; mine it for locator info // and throw a SAXParseException final Locator2Impl locatorImpl = new Locator2Impl(); // since XMLParseExceptions know nothing about encoding, // we cannot return anything meaningful in this context. // We *could* consult the LocatorProxy, but the // application can do this itself if it wishes to possibly // be mislead. locatorImpl.setXMLVersion(fVersion); locatorImpl.setPublicId(e.getPublicId()); locatorImpl.setSystemId(e.getExpandedSystemId()); locatorImpl.setLineNumber(e.getLineNumber()); locatorImpl.setColumnNumber(e.getColumnNumber()); throw (ex == null) ? new SAXParseException(e.getMessage(), locatorImpl) : new SAXParseException(e.getMessage(), locatorImpl, ex); } if (ex instanceof SAXException) { // why did we create an XMLParseException? throw (SAXException) ex; } if (ex instanceof IOException) { throw (IOException) ex; } throw new SAXException(ex); } catch (final XNIException e) { final Exception ex = e.getException(); if (ex == null) { throw new SAXException(e.getMessage()); } if (ex instanceof SAXException) { throw (SAXException) ex; } if (ex instanceof IOException) { throw (IOException) ex; } throw new SAXException(ex); } } /** * {@inheritDoc} */ @Override public void setEntityResolver(final EntityResolver resolver) { } /** * Return the current entity resolver. * * @return The current entity resolver, or null if none has been registered. * @see #setEntityResolver */ @Override public EntityResolver getEntityResolver() { return null; } /** * Allow an application to register an error event handler. * *

* If the application does not register an error handler, all error events * reported by the SAX parser will be silently ignored; however, normal * processing may not continue. It is highly recommended that all SAX * applications implement an error handler to avoid unexpected bugs. *

* *

* Applications may register a new or different handler in the middle of a * parse, and the SAX parser must begin using the new handler immediately. *

* * @param errorHandler The error handler. * @see #getErrorHandler */ @Override public void setErrorHandler(final ErrorHandler errorHandler) { try { final XMLErrorHandler xeh = (XMLErrorHandler) parserConfiguration_.getProperty(ERROR_HANDLER); if (xeh instanceof ErrorHandlerWrapper) { final ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh; ehw.setErrorHandler(errorHandler); } else { parserConfiguration_.setProperty(ERROR_HANDLER, new ErrorHandlerWrapper(errorHandler)); } } catch (final XMLConfigurationException e) { // do nothing } } /** * Return the current error handler. * * @return The current error handler, or null if none has been registered. * @see #setErrorHandler */ @Override public ErrorHandler getErrorHandler() { ErrorHandler errorHandler = null; try { final XMLErrorHandler xmlErrorHandler = (XMLErrorHandler) parserConfiguration_.getProperty(ERROR_HANDLER); if (xmlErrorHandler != null && xmlErrorHandler instanceof ErrorHandlerWrapper) { errorHandler = ((ErrorHandlerWrapper) xmlErrorHandler).getErrorHandler(); } } catch (final XMLConfigurationException e) { // do nothing } return errorHandler; } /** * Allow an application to register a DTD event handler. *

* If the application does not register a DTD handler, all DTD events reported * by the SAX parser will be silently ignored. *

* Applications may register a new or different handler in the middle of a * parse, and the SAX parser must begin using the new handler immediately. * * @param dtdHandler The DTD handler. * @see #getDTDHandler */ @Override public void setDTDHandler(final DTDHandler dtdHandler) { fDTDHandler = dtdHandler; } /** * Allow an application to register a content event handler. *

* If the application does not register a content handler, all content events * reported by the SAX parser will be silently ignored. *

* Applications may register a new or different handler in the middle of a * parse, and the SAX parser must begin using the new handler immediately. * * @param contentHandler The content handler. * * @see #getContentHandler */ @Override public void setContentHandler(final ContentHandler contentHandler) { fContentHandler = contentHandler; } /** * Return the current content handler. * * @return The current content handler, or null if none has been registered. * * @see #setContentHandler */ @Override public ContentHandler getContentHandler() { return fContentHandler; } /** * Return the current DTD handler. * * @return The current DTD handler, or null if none has been registered. * @see #setDTDHandler */ @Override public DTDHandler getDTDHandler() { return fDTDHandler; } /** * Set the state of any feature in a SAX2 parser. The parser might not recognize * the feature, and if it does recognize it, it might not be able to fulfill the * request. * * @param featureId The unique identifier (URI) of the feature. * @param state The requested state of the feature (true or false). * * @exception SAXNotRecognizedException If the requested feature is not known. * @exception SAXNotSupportedException If the requested feature is known, but * the requested state is not supported. */ @Override public void setFeature(final String featureId, final boolean state) throws SAXNotRecognizedException, SAXNotSupportedException { try { if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) { final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length(); // http://xml.org/sax/features/namespaces if (suffixLength == Constants.NAMESPACES_FEATURE.length() && featureId.endsWith(Constants.NAMESPACES_FEATURE)) { parserConfiguration_.setFeature(featureId, state); fNamespaces = state; return; } // http://xml.org/sax/features/namespace-prefixes // controls the reporting of raw prefixed names and Namespace // declarations (xmlns* attributes): when this feature is false // (the default), raw prefixed names may optionally be reported, // and xmlns* attributes must not be reported. // if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() && featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) { fNamespacePrefixes = state; return; } // http://xml.org/sax/features/lexical-handler/parameter-entities // controls whether the beginning and end of parameter entities // will be reported to the LexicalHandler. // if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() && featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) { fLexicalHandlerParameterEntities = state; return; } // http://xml.org/sax/features/unicode-normalization-checking // controls whether Unicode normalization checking is performed // as per Appendix B of the XML 1.1 specification if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() && featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) { // REVISIT: Allow this feature to be set once Unicode normalization // checking is supported -- mrglavas. if (state) { throw new SAXNotSupportedException( SAXMessageFormatter.formatMessage("true-not-supported", new Object[] {featureId})); } return; } } parserConfiguration_.setFeature(featureId, state); } catch (final XMLConfigurationException e) { final String identifier = e.getIdentifier(); if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { throw new SAXNotRecognizedException( SAXMessageFormatter.formatMessage("feature-not-recognized", new Object[] {identifier})); } throw new SAXNotSupportedException( SAXMessageFormatter.formatMessage("feature-not-supported", new Object[] {identifier})); } } /** * Query the state of a feature. *

* Query the current state of any feature in a SAX2 parser. The parser might not * recognize the feature. * * @param featureId The unique identifier (URI) of the feature being set. * @return The current state of the feature. * @exception org.xml.sax.SAXNotRecognizedException If the requested feature is * not known. * @exception SAXNotSupportedException If the requested feature is * known but not supported. */ @Override public boolean getFeature(final String featureId) throws SAXNotRecognizedException, SAXNotSupportedException { try { if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) { final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length(); // http://xml.org/sax/features/namespace-prefixes // controls the reporting of raw prefixed names and Namespace // declarations (xmlns* attributes): when this feature is false // (the default), raw prefixed names may optionally be reported, // and xmlns* attributes must not be reported. // if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() && featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) { return fNamespacePrefixes; } // http://xml.org/sax/features/lexical-handler/parameter-entities // controls whether the beginning and end of parameter entities // will be reported to the LexicalHandler. // if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() && featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) { return fLexicalHandlerParameterEntities; } // http://xml.org/sax/features/unicode-normalization-checking // controls whether Unicode normalization checking is performed // as per Appendix B of the XML 1.1 specification // if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() && featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) { // REVISIT: Allow this feature to be set once Unicode normalization // checking is supported -- mrglavas. return false; } } return parserConfiguration_.getFeature(featureId); } catch (final XMLConfigurationException e) { final String identifier = e.getIdentifier(); if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { throw new SAXNotRecognizedException( SAXMessageFormatter.formatMessage("feature-not-recognized", new Object[] {identifier})); } throw new SAXNotSupportedException( SAXMessageFormatter.formatMessage("feature-not-supported", new Object[] {identifier})); } } /** * Set the value of any property in a SAX2 parser. The parser might not * recognize the property, and if it does recognize it, it might not support the * requested value. * * @param propertyId The unique identifier (URI) of the property being set. * @param value The value to which the property is being set. * * @exception SAXNotRecognizedException If the requested property is not known. * @exception SAXNotSupportedException If the requested property is known, but * the requested value is not supported. */ @Override public void setProperty(final String propertyId, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException { try { if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); // // http://xml.org/sax/properties/lexical-handler // Value type: org.xml.sax.ext.LexicalHandler // Access: read/write, pre-parse only // Set the lexical event handler. // if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() && propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) { try { setLexicalHandler((LexicalHandler) value); } catch (final ClassCastException e) { throw new SAXNotSupportedException(SAXMessageFormatter.formatMessage("incompatible-class", new Object[] {propertyId, "org.xml.sax.ext.LexicalHandler"})); } return; } } parserConfiguration_.setProperty(propertyId, value); } catch (final XMLConfigurationException e) { final String identifier = e.getIdentifier(); if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { throw new SAXNotRecognizedException( SAXMessageFormatter.formatMessage("property-not-recognized", new Object[] {identifier})); } throw new SAXNotSupportedException( SAXMessageFormatter.formatMessage("property-not-supported", new Object[] {identifier})); } } /** * Query the value of a property. *

* Return the current value of a property in a SAX2 parser. The parser might not * recognize the property. * * @param propertyId The unique identifier (URI) of the property being set. * @return The current value of the property. * @exception org.xml.sax.SAXNotRecognizedException If the requested property is * not known. * @exception SAXNotSupportedException If the requested property is * known but not supported. */ @Override public Object getProperty(final String propertyId) throws SAXNotRecognizedException, SAXNotSupportedException { try { // // SAX2 core properties // if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); // // http://xml.org/sax/properties/document-xml-version // Value type: java.lang.String // Access: read-only // The literal string describing the actual XML version of the document. // if (suffixLength == Constants.DOCUMENT_XML_VERSION_PROPERTY.length() && propertyId.endsWith(Constants.DOCUMENT_XML_VERSION_PROPERTY)) { return fVersion; } // // http://xml.org/sax/properties/lexical-handler // Value type: org.xml.sax.ext.LexicalHandler // Access: read/write, pre-parse only // Set the lexical event handler. // if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() && propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) { return getLexicalHandler(); } } return parserConfiguration_.getProperty(propertyId); } catch (final XMLConfigurationException e) { final String identifier = e.getIdentifier(); if (e.getType() == XMLConfigurationException.NOT_RECOGNIZED) { throw new SAXNotRecognizedException( SAXMessageFormatter.formatMessage("property-not-recognized", new Object[] {identifier})); } throw new SAXNotSupportedException( SAXMessageFormatter.formatMessage("property-not-supported", new Object[] {identifier})); } } // SAX2 core properties /** * Set the lexical event handler. *

* This method is the equivalent to the property: * *

     * http://xml.org/sax/properties/lexical-handler
     * 
* * @param handler lexical event handler * @throws SAXNotSupportedException on error * * @see #getLexicalHandler() * @see #setProperty(String, Object) */ protected void setLexicalHandler(final LexicalHandler handler) throws SAXNotSupportedException { if (fParseInProgress) { throw new SAXNotSupportedException(SAXMessageFormatter.formatMessage("property-not-parsing-supported", new Object[] {"http://xml.org/sax/properties/lexical-handler"})); } fLexicalHandler = handler; } /** * @return the lexical handler. * * @see #setLexicalHandler(LexicalHandler) */ protected LexicalHandler getLexicalHandler() { return fLexicalHandler; } /** * Send startPrefixMapping events * * @throws SAXException on error */ protected final void startNamespaceMapping() throws SAXException { final int count = fNamespaceContext.getDeclaredPrefixCount(); if (count > 0) { String prefix; String uri; for (int i = 0; i < count; i++) { prefix = fNamespaceContext.getDeclaredPrefixAt(i); uri = fNamespaceContext.getURI(prefix); fContentHandler.startPrefixMapping(prefix, (uri == null) ? "" : uri); } } } /** * Send endPrefixMapping events * * @throws SAXException on error */ protected final void endNamespaceMapping() throws SAXException { final int count = fNamespaceContext.getDeclaredPrefixCount(); if (count > 0) { for (int i = 0; i < count; i++) { fContentHandler.endPrefixMapping(fNamespaceContext.getDeclaredPrefixAt(i)); } } } /** * Reset all components before parsing. * * @throws XNIException Thrown if an error occurs during initialization. */ @Override public void reset() throws XNIException { super.reset(); // reset state fVersion = "1.0"; fStandalone = false; // features fNamespaces = parserConfiguration_.getFeature(NAMESPACES); } protected static final class LocatorProxy implements Locator2 { /** XML locator. */ private final XMLLocator fLocator; // Constructs an XML locator proxy. public LocatorProxy(final XMLLocator locator) { fLocator = locator; } /** * {@inheritDoc} */ @Override public String getPublicId() { return fLocator.getPublicId(); } /** * {@inheritDoc} */ @Override public String getSystemId() { return fLocator.getExpandedSystemId(); } /** * {@inheritDoc} */ @Override public int getLineNumber() { return fLocator.getLineNumber(); } /** * {@inheritDoc} */ @Override public int getColumnNumber() { return fLocator.getColumnNumber(); } /** * {@inheritDoc} */ @Override public String getXMLVersion() { return fLocator.getXMLVersion(); } /** * {@inheritDoc} */ @Override public String getEncoding() { return fLocator.getEncoding(); } } protected static final class AttributesProxy implements Attributes2 { /** XML attributes. */ private XMLAttributes fAttributes; // Sets the XML attributes. public void setAttributes(final XMLAttributes attributes) { fAttributes = attributes; } @Override public int getLength() { return fAttributes.getLength(); } @Override public String getQName(final int index) { return fAttributes.getQName(index); } @Override public String getURI(final int index) { // REVISIT: this hides the fact that internally we use // null instead of empty string // SAX requires URI to be a string or an empty string final String uri = fAttributes.getURI(index); return uri != null ? uri : ""; } @Override public String getLocalName(final int index) { return fAttributes.getLocalName(index); } @Override public String getType(final int i) { return fAttributes.getType(i); } @Override public String getType(final String name) { return fAttributes.getType(name); } @Override public String getType(final String uri, final String localName) { return uri.length() == 0 ? fAttributes.getType(null, localName) : fAttributes.getType(uri, localName); } @Override public String getValue(final int i) { return fAttributes.getValue(i); } @Override public String getValue(final String name) { return fAttributes.getValue(name); } @Override public String getValue(final String uri, final String localName) { return uri.length() == 0 ? fAttributes.getValue(null, localName) : fAttributes.getValue(uri, localName); } @Override public int getIndex(final String qName) { return fAttributes.getIndex(qName); } @Override public int getIndex(final String uri, final String localPart) { return uri.length() == 0 ? fAttributes.getIndex(null, localPart) : fAttributes.getIndex(uri, localPart); } // Attributes2 methods // REVISIT: Localize exception messages. -- mrglavas @Override public boolean isDeclared(final int index) { return false; } @Override public boolean isDeclared(final String qName) { return false; } @Override public boolean isDeclared(final String uri, final String localName) { return false; } @Override public boolean isSpecified(final int index) { if (index < 0 || index >= fAttributes.getLength()) { throw new ArrayIndexOutOfBoundsException(index); } return fAttributes.isSpecified(index); } @Override public boolean isSpecified(final String qName) { final int index = getIndex(qName); if (index == -1) { throw new IllegalArgumentException(qName); } return fAttributes.isSpecified(index); } @Override public boolean isSpecified(final String uri, final String localName) { final int index = getIndex(uri, localName); if (index == -1) { throw new IllegalArgumentException(localName); } return fAttributes.isSpecified(index); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy