| /* |
| * Copyright 2001-2006 The Apache Software Foundation. |
| * |
| * 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 |
| * |
| * 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.parsers; |
| |
| import java.util.Locale; |
| import java.util.Stack; |
| |
| import org.apache.xerces.dom.AttrImpl; |
| import org.apache.xerces.dom.CoreDocumentImpl; |
| import org.apache.xerces.dom.DOMErrorImpl; |
| import org.apache.xerces.dom.DOMMessageFormatter; |
| import org.apache.xerces.dom.DeferredDocumentImpl; |
| import org.apache.xerces.dom.DocumentImpl; |
| import org.apache.xerces.dom.DocumentTypeImpl; |
| import org.apache.xerces.dom.ElementDefinitionImpl; |
| import org.apache.xerces.dom.ElementImpl; |
| import org.apache.xerces.dom.ElementNSImpl; |
| import org.apache.xerces.dom.EntityImpl; |
| import org.apache.xerces.dom.EntityReferenceImpl; |
| import org.apache.xerces.dom.NodeImpl; |
| import org.apache.xerces.dom.NotationImpl; |
| import org.apache.xerces.dom.PSVIAttrNSImpl; |
| import org.apache.xerces.dom.PSVIDocumentImpl; |
| import org.apache.xerces.dom.PSVIElementNSImpl; |
| import org.apache.xerces.dom.TextImpl; |
| import org.apache.xerces.impl.Constants; |
| import org.apache.xerces.impl.dv.XSSimpleType; |
| import org.apache.xerces.util.DOMErrorHandlerWrapper; |
| import org.apache.xerces.xni.Augmentations; |
| import org.apache.xerces.xni.NamespaceContext; |
| import org.apache.xerces.xni.QName; |
| import org.apache.xerces.xni.XMLAttributes; |
| import org.apache.xerces.xni.XMLLocator; |
| import org.apache.xerces.xni.XMLResourceIdentifier; |
| import org.apache.xerces.xni.XMLString; |
| import org.apache.xerces.xni.XNIException; |
| import org.apache.xerces.xni.parser.XMLParserConfiguration; |
| import org.apache.xerces.xs.AttributePSVI; |
| import org.apache.xerces.xs.ElementPSVI; |
| import org.apache.xerces.xs.XSTypeDefinition; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.CDATASection; |
| import org.w3c.dom.Comment; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.DocumentType; |
| import org.w3c.dom.DOMError; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.EntityReference; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.w3c.dom.ProcessingInstruction; |
| import org.w3c.dom.Text; |
| import org.w3c.dom.ls.LSParserFilter; |
| import org.w3c.dom.traversal.NodeFilter; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * This is the base class of all DOM parsers. It implements the XNI |
| * callback methods to create the DOM tree. After a successful parse of |
| * an XML document, the DOM Document object can be queried using the |
| * <code>getDocument</code> method. The actual pipeline is defined in |
| * parser configuration. |
| * |
| * @author Arnaud Le Hors, IBM |
| * @author Andy Clark, IBM |
| * @author Elena Litani, IBM |
| * |
| * @version $Id$ |
| */ |
| public class AbstractDOMParser extends AbstractXMLDocumentParser { |
| |
| // |
| // Constants |
| // |
| |
| // feature ids |
| |
| /** Feature id: namespace. */ |
| protected static final String NAMESPACES = |
| Constants.SAX_FEATURE_PREFIX+Constants.NAMESPACES_FEATURE; |
| |
| /** Feature id: create entity ref nodes. */ |
| protected static final String CREATE_ENTITY_REF_NODES = |
| Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE; |
| |
| /** Feature id: include comments. */ |
| protected static final String INCLUDE_COMMENTS_FEATURE = |
| Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE; |
| |
| /** Feature id: create cdata nodes. */ |
| protected static final String CREATE_CDATA_NODES_FEATURE = |
| Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE; |
| |
| /** Feature id: include ignorable whitespace. */ |
| protected static final String INCLUDE_IGNORABLE_WHITESPACE = |
| Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE; |
| |
| /** Feature id: defer node expansion. */ |
| protected static final String DEFER_NODE_EXPANSION = |
| Constants.XERCES_FEATURE_PREFIX + Constants.DEFER_NODE_EXPANSION_FEATURE; |
| |
| |
| /** Recognized features. */ |
| private static final String[] RECOGNIZED_FEATURES = { |
| NAMESPACES, |
| CREATE_ENTITY_REF_NODES, |
| INCLUDE_COMMENTS_FEATURE, |
| CREATE_CDATA_NODES_FEATURE, |
| INCLUDE_IGNORABLE_WHITESPACE, |
| DEFER_NODE_EXPANSION |
| }; |
| |
| // property ids |
| |
| /** Property id: document class name. */ |
| protected static final String DOCUMENT_CLASS_NAME = |
| Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_CLASS_NAME_PROPERTY; |
| |
| protected static final String CURRENT_ELEMENT_NODE= |
| Constants.XERCES_PROPERTY_PREFIX + Constants.CURRENT_ELEMENT_NODE_PROPERTY; |
| |
| // protected static final String GRAMMAR_POOL = |
| // Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; |
| |
| /** Recognized properties. */ |
| private static final String[] RECOGNIZED_PROPERTIES = { |
| DOCUMENT_CLASS_NAME, |
| CURRENT_ELEMENT_NODE, |
| }; |
| |
| // other |
| |
| /** Default document class name. */ |
| protected static final String DEFAULT_DOCUMENT_CLASS_NAME = |
| "org.apache.xerces.dom.DocumentImpl"; |
| |
| protected static final String CORE_DOCUMENT_CLASS_NAME = |
| "org.apache.xerces.dom.CoreDocumentImpl"; |
| |
| protected static final String PSVI_DOCUMENT_CLASS_NAME = |
| "org.apache.xerces.dom.PSVIDocumentImpl"; |
| |
| /** |
| * If the user stops the process, this exception will be thrown. |
| */ |
| public static final RuntimeException abort = new RuntimeException(); |
| |
| // debugging |
| |
| private static final boolean DEBUG_EVENTS = false; |
| private static final boolean DEBUG_BASEURI = false; |
| |
| // |
| // Data |
| // |
| |
| /** DOM L3 error handler */ |
| protected DOMErrorHandlerWrapper fErrorHandler = null; |
| |
| /** True if inside DTD. */ |
| protected boolean fInDTD; |
| |
| // features |
| |
| /** Create entity reference nodes. */ |
| protected boolean fCreateEntityRefNodes; |
| |
| /** Include ignorable whitespace. */ |
| protected boolean fIncludeIgnorableWhitespace; |
| |
| /** Include Comments. */ |
| protected boolean fIncludeComments; |
| |
| /** Create cdata nodes. */ |
| protected boolean fCreateCDATANodes; |
| |
| // dom information |
| |
| /** The document. */ |
| protected Document fDocument; |
| |
| /** The default Xerces document implementation, if used. */ |
| protected CoreDocumentImpl fDocumentImpl; |
| |
| /** Whether to store PSVI information in DOM tree. */ |
| protected boolean fStorePSVI; |
| |
| /** The document class name to use. */ |
| protected String fDocumentClassName; |
| |
| /** The document type node. */ |
| protected DocumentType fDocumentType; |
| |
| /** Current node. */ |
| protected Node fCurrentNode; |
| protected CDATASection fCurrentCDATASection; |
| protected EntityImpl fCurrentEntityDecl; |
| protected int fDeferredEntityDecl; |
| |
| /** Character buffer */ |
| protected final StringBuffer fStringBuffer = new StringBuffer (50); |
| |
| // internal subset |
| |
| /** Internal subset buffer. */ |
| protected StringBuffer fInternalSubset; |
| |
| // deferred expansion data |
| |
| protected boolean fDeferNodeExpansion; |
| protected boolean fNamespaceAware; |
| protected DeferredDocumentImpl fDeferredDocumentImpl; |
| protected int fDocumentIndex; |
| protected int fDocumentTypeIndex; |
| protected int fCurrentNodeIndex; |
| protected int fCurrentCDATASectionIndex; |
| |
| // state |
| |
| /** True if inside DTD external subset. */ |
| protected boolean fInDTDExternalSubset; |
| |
| /** Root element name */ |
| protected QName fRoot = new QName(); |
| |
| /** True if inside CDATA section. */ |
| protected boolean fInCDATASection; |
| |
| /** True if saw the first chunk of characters*/ |
| protected boolean fFirstChunk = false; |
| |
| |
| /** LSParserFilter: specifies that element with given QNAME and all its children |
| * must be rejected */ |
| protected boolean fFilterReject = false; |
| |
| // data |
| |
| /** Base uri stack*/ |
| protected Stack fBaseURIStack = new Stack (); |
| |
| /** LSParserFilter: the QNAME of rejected element*/ |
| protected final QName fRejectedElement = new QName (); |
| |
| /** LSParserFilter: store qnames of skipped elements*/ |
| protected Stack fSkippedElemStack = null; |
| |
| /** LSParserFilter: true if inside entity reference */ |
| protected boolean fInEntityRef = false; |
| |
| /** Attribute QName. */ |
| private QName fAttrQName = new QName (); |
| |
| /** Document locator. */ |
| private XMLLocator fLocator; |
| |
| // handlers |
| |
| protected LSParserFilter fDOMFilter = null; |
| |
| // |
| // Constructors |
| // |
| |
| /** Default constructor. */ |
| protected AbstractDOMParser (XMLParserConfiguration config) { |
| |
| super (config); |
| |
| |
| // add recognized features |
| fConfiguration.addRecognizedFeatures (RECOGNIZED_FEATURES); |
| |
| // set default values |
| fConfiguration.setFeature (CREATE_ENTITY_REF_NODES, true); |
| fConfiguration.setFeature (INCLUDE_IGNORABLE_WHITESPACE, true); |
| fConfiguration.setFeature (DEFER_NODE_EXPANSION, true); |
| fConfiguration.setFeature (INCLUDE_COMMENTS_FEATURE, true); |
| fConfiguration.setFeature (CREATE_CDATA_NODES_FEATURE, true); |
| |
| // add recognized properties |
| fConfiguration.addRecognizedProperties (RECOGNIZED_PROPERTIES); |
| |
| // set default values |
| fConfiguration.setProperty (DOCUMENT_CLASS_NAME, |
| DEFAULT_DOCUMENT_CLASS_NAME); |
| |
| } // <init>(XMLParserConfiguration) |
| |
| /** |
| * This method retreives the name of current document class. |
| */ |
| protected String getDocumentClassName () { |
| return fDocumentClassName; |
| } |
| |
| /** |
| * This method allows the programmer to decide which document |
| * factory to use when constructing the DOM tree. However, doing |
| * so will lose the functionality of the default factory. Also, |
| * a document class other than the default will lose the ability |
| * to defer node expansion on the DOM tree produced. |
| * |
| * @param documentClassName The fully qualified class name of the |
| * document factory to use when constructing |
| * the DOM tree. |
| * |
| * @see #getDocumentClassName |
| * @see #DEFAULT_DOCUMENT_CLASS_NAME |
| */ |
| protected void setDocumentClassName (String documentClassName) { |
| |
| // normalize class name |
| if (documentClassName == null) { |
| documentClassName = DEFAULT_DOCUMENT_CLASS_NAME; |
| } |
| |
| if (!documentClassName.equals(DEFAULT_DOCUMENT_CLASS_NAME) && |
| !documentClassName.equals(PSVI_DOCUMENT_CLASS_NAME)) { |
| // verify that this class exists and is of the right type |
| try { |
| Class _class = ObjectFactory.findProviderClass (documentClassName, |
| ObjectFactory.findClassLoader (), true); |
| //if (!_class.isAssignableFrom(Document.class)) { |
| if (!Document.class.isAssignableFrom (_class)) { |
| throw new IllegalArgumentException ( |
| DOMMessageFormatter.formatMessage( |
| DOMMessageFormatter.DOM_DOMAIN, |
| "InvalidDocumentClassName", new Object [] {documentClassName})); |
| } |
| } |
| catch (ClassNotFoundException e) { |
| throw new IllegalArgumentException ( |
| DOMMessageFormatter.formatMessage( |
| DOMMessageFormatter.DOM_DOMAIN, |
| "MissingDocumentClassName", new Object [] {documentClassName})); |
| } |
| } |
| |
| // set document class name |
| fDocumentClassName = documentClassName; |
| if (!documentClassName.equals (DEFAULT_DOCUMENT_CLASS_NAME)) { |
| fDeferNodeExpansion = false; |
| } |
| |
| } // setDocumentClassName(String) |
| |
| // |
| // Public methods |
| // |
| |
| /** Returns the DOM document object. */ |
| public Document getDocument () { |
| return fDocument; |
| } // getDocument():Document |
| |
| // |
| // XMLDocumentParser methods |
| // |
| |
| /** |
| * Resets the parser state. |
| * |
| * @throws SAXException Thrown on initialization error. |
| */ |
| public void reset () throws XNIException { |
| super.reset (); |
| |
| |
| // get feature state |
| fCreateEntityRefNodes = |
| fConfiguration.getFeature (CREATE_ENTITY_REF_NODES); |
| |
| fIncludeIgnorableWhitespace = |
| fConfiguration.getFeature (INCLUDE_IGNORABLE_WHITESPACE); |
| |
| fDeferNodeExpansion = |
| fConfiguration.getFeature (DEFER_NODE_EXPANSION); |
| |
| fNamespaceAware = fConfiguration.getFeature (NAMESPACES); |
| |
| fIncludeComments = fConfiguration.getFeature (INCLUDE_COMMENTS_FEATURE); |
| |
| fCreateCDATANodes = fConfiguration.getFeature (CREATE_CDATA_NODES_FEATURE); |
| |
| // get property |
| setDocumentClassName ((String) |
| fConfiguration.getProperty (DOCUMENT_CLASS_NAME)); |
| |
| // reset dom information |
| fDocument = null; |
| fDocumentImpl = null; |
| fStorePSVI = false; |
| fDocumentType = null; |
| fDocumentTypeIndex = -1; |
| fDeferredDocumentImpl = null; |
| fCurrentNode = null; |
| |
| // reset string buffer |
| fStringBuffer.setLength (0); |
| |
| // reset state information |
| fRoot.clear(); |
| fInDTD = false; |
| fInDTDExternalSubset = false; |
| fInCDATASection = false; |
| fFirstChunk = false; |
| fCurrentCDATASection = null; |
| fCurrentCDATASectionIndex = -1; |
| |
| fBaseURIStack.removeAllElements (); |
| |
| |
| } // reset() |
| |
| /** |
| * Set the locale to use for messages. |
| * |
| * @param locale The locale object to use for localization of messages. |
| * |
| */ |
| public void setLocale (Locale locale) { |
| fConfiguration.setLocale (locale); |
| |
| } // setLocale(Locale) |
| |
| // |
| // XMLDocumentHandler methods |
| // |
| |
| /** |
| * This method notifies the start of a general entity. |
| * <p> |
| * <strong>Note:</strong> This method is not called for entity references |
| * appearing as part of attribute values. |
| * |
| * @param name The name of the general entity. |
| * @param identifier The resource identifier. |
| * @param encoding The auto-detected IANA encoding name of the entity |
| * stream. This value will be null in those situations |
| * where the entity encoding is not auto-detected (e.g. |
| * internal entities or a document entity that is |
| * parsed from a java.io.Reader). |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @exception XNIException Thrown by handler to signal an error. |
| */ |
| public void startGeneralEntity (String name, |
| XMLResourceIdentifier identifier, |
| String encoding, Augmentations augs) |
| throws XNIException { |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>startGeneralEntity ("+name+")"); |
| if (DEBUG_BASEURI) { |
| System.out.println (" expandedSystemId( **baseURI): "+identifier.getExpandedSystemId ()); |
| System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); |
| } |
| } |
| |
| // Always create entity reference nodes to be able to recreate |
| // entity as a part of doctype |
| if (!fDeferNodeExpansion) { |
| if (fFilterReject) { |
| return; |
| } |
| setCharacterData (true); |
| EntityReference er = fDocument.createEntityReference (name); |
| if (fDocumentImpl != null) { |
| // REVISIT: baseURI/actualEncoding |
| // remove dependency on our implementation when DOM L3 is REC |
| // |
| |
| EntityReferenceImpl erImpl =(EntityReferenceImpl)er; |
| |
| // set base uri |
| erImpl.setBaseURI (identifier.getExpandedSystemId ()); |
| if (fDocumentType != null) { |
| // set actual encoding |
| NamedNodeMap entities = fDocumentType.getEntities (); |
| fCurrentEntityDecl = (EntityImpl) entities.getNamedItem (name); |
| if (fCurrentEntityDecl != null) { |
| fCurrentEntityDecl.setInputEncoding (encoding); |
| } |
| |
| } |
| // we don't need synchronization now, because entity ref will be |
| // expanded anyway. Synch only needed when user creates entityRef node |
| erImpl.needsSyncChildren (false); |
| } |
| fInEntityRef = true; |
| fCurrentNode.appendChild (er); |
| fCurrentNode = er; |
| } |
| else { |
| |
| int er = |
| fDeferredDocumentImpl.createDeferredEntityReference (name, identifier.getExpandedSystemId ()); |
| if (fDocumentTypeIndex != -1) { |
| // find corresponding Entity decl |
| int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); |
| while (node != -1) { |
| short nodeType = fDeferredDocumentImpl.getNodeType (node, false); |
| if (nodeType == Node.ENTITY_NODE) { |
| String nodeName = |
| fDeferredDocumentImpl.getNodeName (node, false); |
| if (nodeName.equals (name)) { |
| fDeferredEntityDecl = node; |
| fDeferredDocumentImpl.setInputEncoding (node, encoding); |
| break; |
| } |
| } |
| node = fDeferredDocumentImpl.getRealPrevSibling (node, false); |
| } |
| } |
| fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, er); |
| fCurrentNodeIndex = er; |
| } |
| |
| } // startGeneralEntity(String,XMLResourceIdentifier, Augmentations) |
| |
| /** |
| * Notifies of the presence of a TextDecl line in an entity. If present, |
| * this method will be called immediately following the startEntity call. |
| * <p> |
| * <strong>Note:</strong> This method will never be called for the |
| * document entity; it is only called for external general entities |
| * referenced in document content. |
| * <p> |
| * <strong>Note:</strong> This method is not called for entity references |
| * appearing as part of attribute values. |
| * |
| * @param version The XML version, or null if not specified. |
| * @param encoding The IANA encoding name of the entity. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void textDecl (String version, String encoding, Augmentations augs) throws XNIException { |
| if (fInDTD){ |
| return; |
| } |
| if (!fDeferNodeExpansion) { |
| if (fCurrentEntityDecl != null && !fFilterReject) { |
| fCurrentEntityDecl.setXmlEncoding (encoding); |
| if (version != null) |
| fCurrentEntityDecl.setXmlVersion (version); |
| } |
| } |
| else { |
| if (fDeferredEntityDecl !=-1) { |
| fDeferredDocumentImpl.setEntityInfo (fDeferredEntityDecl, version, encoding); |
| } |
| } |
| } // textDecl(String,String) |
| |
| /** |
| * A comment. |
| * |
| * @param text The text in the comment. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by application to signal an error. |
| */ |
| public void comment (XMLString text, Augmentations augs) throws XNIException { |
| if (fInDTD) { |
| if (fInternalSubset != null && !fInDTDExternalSubset) { |
| fInternalSubset.append ("<!-- "); |
| if (text.length > 0) { |
| fInternalSubset.append (text.ch, text.offset, text.length); |
| } |
| fInternalSubset.append (" -->"); |
| } |
| return; |
| } |
| if (!fIncludeComments || fFilterReject) { |
| return; |
| } |
| if (!fDeferNodeExpansion) { |
| Comment comment = fDocument.createComment (text.toString ()); |
| |
| setCharacterData (false); |
| fCurrentNode.appendChild (comment); |
| if (fDOMFilter !=null && !fInEntityRef && |
| (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_COMMENT)!= 0) { |
| short code = fDOMFilter.acceptNode (comment); |
| switch (code) { |
| case LSParserFilter.FILTER_INTERRUPT:{ |
| throw abort; |
| } |
| case LSParserFilter.FILTER_REJECT:{ |
| // REVISIT: the constant FILTER_REJECT should be changed when new |
| // DOM LS specs gets published |
| |
| // fall through to SKIP since comment has no children. |
| } |
| case LSParserFilter.FILTER_SKIP: { |
| // REVISIT: the constant FILTER_SKIP should be changed when new |
| // DOM LS specs gets published |
| fCurrentNode.removeChild (comment); |
| // make sure we don't loose chars if next event is characters() |
| fFirstChunk = true; |
| return; |
| } |
| |
| default: { |
| // accept node |
| } |
| } |
| } |
| |
| } |
| else { |
| int comment = |
| fDeferredDocumentImpl.createDeferredComment (text.toString ()); |
| fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, comment); |
| } |
| |
| } // comment(XMLString) |
| |
| /** |
| * A processing instruction. Processing instructions consist of a |
| * target name and, optionally, text data. The data is only meaningful |
| * to the application. |
| * <p> |
| * Typically, a processing instruction's data will contain a series |
| * of pseudo-attributes. These pseudo-attributes follow the form of |
| * element attributes but are <strong>not</strong> parsed or presented |
| * to the application as anything other than text. The application is |
| * responsible for parsing the data. |
| * |
| * @param target The target. |
| * @param data The data or null if none specified. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void processingInstruction (String target, XMLString data, Augmentations augs) |
| throws XNIException { |
| |
| if (fInDTD) { |
| if (fInternalSubset != null && !fInDTDExternalSubset) { |
| fInternalSubset.append ("<?"); |
| fInternalSubset.append (target); |
| if (data.length > 0) { |
| fInternalSubset.append (' ').append (data.ch, data.offset, data.length); |
| } |
| fInternalSubset.append ("?>"); |
| } |
| return; |
| } |
| |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>processingInstruction ("+target+")"); |
| } |
| if (!fDeferNodeExpansion) { |
| if (fFilterReject) { |
| return; |
| } |
| ProcessingInstruction pi = |
| fDocument.createProcessingInstruction (target, data.toString ()); |
| |
| |
| setCharacterData (false); |
| fCurrentNode.appendChild (pi); |
| if (fDOMFilter !=null && !fInEntityRef && |
| (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_PROCESSING_INSTRUCTION)!= 0) { |
| short code = fDOMFilter.acceptNode (pi); |
| switch (code) { |
| case LSParserFilter.FILTER_INTERRUPT:{ |
| throw abort; |
| } |
| case LSParserFilter.FILTER_REJECT:{ |
| // fall through to SKIP since PI has no children. |
| } |
| case LSParserFilter.FILTER_SKIP: { |
| fCurrentNode.removeChild (pi); |
| // fFirstChunk must be set to true so that data |
| // won't be lost in the case where the child before PI is |
| // a text node and the next event is characters. |
| fFirstChunk = true; |
| return; |
| } |
| default: { |
| } |
| } |
| } |
| } |
| else { |
| int pi = fDeferredDocumentImpl. |
| createDeferredProcessingInstruction (target, data.toString ()); |
| fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, pi); |
| } |
| |
| } // processingInstruction(String,XMLString) |
| |
| /** |
| * The start of the document. |
| * |
| * @param locator The system identifier of the entity if the entity |
| * is external, null otherwise. |
| * @param encoding The auto-detected IANA encoding name of the entity |
| * stream. This value will be null in those situations |
| * where the entity encoding is not auto-detected (e.g. |
| * internal entities or a document entity that is |
| * parsed from a java.io.Reader). |
| * @param namespaceContext |
| * The namespace context in effect at the |
| * start of this document. |
| * This object represents the current context. |
| * Implementors of this class are responsible |
| * for copying the namespace bindings from the |
| * the current context (and its parent contexts) |
| * if that information is important. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void startDocument (XMLLocator locator, String encoding, |
| NamespaceContext namespaceContext, Augmentations augs) |
| throws XNIException { |
| |
| fLocator = locator; |
| if (!fDeferNodeExpansion) { |
| if (fDocumentClassName.equals (DEFAULT_DOCUMENT_CLASS_NAME)) { |
| fDocument = new DocumentImpl (); |
| fDocumentImpl = (CoreDocumentImpl)fDocument; |
| // REVISIT: when DOM Level 3 is REC rely on Document.support |
| // instead of specific class |
| // set DOM error checking off |
| fDocumentImpl.setStrictErrorChecking (false); |
| // set actual encoding |
| fDocumentImpl.setInputEncoding (encoding); |
| // set documentURI |
| fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); |
| } |
| else if (fDocumentClassName.equals (PSVI_DOCUMENT_CLASS_NAME)) { |
| fDocument = new PSVIDocumentImpl(); |
| fDocumentImpl = (CoreDocumentImpl)fDocument; |
| fStorePSVI = true; |
| // REVISIT: when DOM Level 3 is REC rely on Document.support |
| // instead of specific class |
| // set DOM error checking off |
| fDocumentImpl.setStrictErrorChecking (false); |
| // set actual encoding |
| fDocumentImpl.setInputEncoding (encoding); |
| // set documentURI |
| fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); |
| } |
| else { |
| // use specified document class |
| try { |
| ClassLoader cl = ObjectFactory.findClassLoader(); |
| Class documentClass = ObjectFactory.findProviderClass (fDocumentClassName, |
| cl, true); |
| fDocument = (Document)documentClass.newInstance (); |
| |
| // if subclass of our own class that's cool too |
| Class defaultDocClass = |
| ObjectFactory.findProviderClass (CORE_DOCUMENT_CLASS_NAME, |
| cl, true); |
| if (defaultDocClass.isAssignableFrom (documentClass)) { |
| fDocumentImpl = (CoreDocumentImpl)fDocument; |
| |
| Class psviDocClass = ObjectFactory.findProviderClass (PSVI_DOCUMENT_CLASS_NAME, |
| cl, true); |
| if (psviDocClass.isAssignableFrom (documentClass)) { |
| fStorePSVI = true; |
| } |
| |
| // REVISIT: when DOM Level 3 is REC rely on |
| // Document.support instead of specific class |
| // set DOM error checking off |
| fDocumentImpl.setStrictErrorChecking (false); |
| // set actual encoding |
| fDocumentImpl.setInputEncoding (encoding); |
| // set documentURI |
| if (locator != null) { |
| fDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); |
| } |
| } |
| } |
| catch (ClassNotFoundException e) { |
| // won't happen we already checked that earlier |
| } |
| catch (Exception e) { |
| throw new RuntimeException ( |
| DOMMessageFormatter.formatMessage( |
| DOMMessageFormatter.DOM_DOMAIN, |
| "CannotCreateDocumentClass", |
| new Object [] {fDocumentClassName})); |
| } |
| } |
| fCurrentNode = fDocument; |
| } |
| else { |
| fDeferredDocumentImpl = new DeferredDocumentImpl (fNamespaceAware); |
| fDocument = fDeferredDocumentImpl; |
| fDocumentIndex = fDeferredDocumentImpl.createDeferredDocument (); |
| // REVISIT: strict error checking is not implemented in deferred dom. |
| // Document.support instead of specific class |
| |
| // set actual encoding |
| fDeferredDocumentImpl.setInputEncoding (encoding); |
| // set documentURI |
| fDeferredDocumentImpl.setDocumentURI (locator.getExpandedSystemId ()); |
| fCurrentNodeIndex = fDocumentIndex; |
| |
| } |
| |
| } // startDocument(String,String) |
| |
| /** |
| * Notifies of the presence of an XMLDecl line in the document. If |
| * present, this method will be called immediately following the |
| * startDocument call. |
| * |
| * @param version The XML version. |
| * @param encoding The IANA encoding name of the document, or null if |
| * not specified. |
| * @param standalone The standalone value, or null if not specified. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void xmlDecl (String version, String encoding, String standalone, |
| Augmentations augs) |
| throws XNIException { |
| if (!fDeferNodeExpansion) { |
| // REVISIT: when DOM Level 3 is REC rely on Document.support |
| // instead of specific class |
| if (fDocumentImpl != null) { |
| if (version != null) |
| fDocumentImpl.setXmlVersion (version); |
| fDocumentImpl.setXmlEncoding (encoding); |
| fDocumentImpl.setXmlStandalone ("yes".equals (standalone)); |
| } |
| } |
| else { |
| if (version != null) |
| fDeferredDocumentImpl.setXmlVersion (version); |
| fDeferredDocumentImpl.setXmlEncoding (encoding); |
| fDeferredDocumentImpl.setXmlStandalone ("yes".equals (standalone)); |
| } |
| } // xmlDecl(String,String,String) |
| |
| /** |
| * Notifies of the presence of the DOCTYPE line in the document. |
| * |
| * @param rootElement The name of the root element. |
| * @param publicId The public identifier if an external DTD or null |
| * if the external DTD is specified using SYSTEM. |
| * @param systemId The system identifier if an external DTD, null |
| * otherwise. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void doctypeDecl (String rootElement, |
| String publicId, String systemId, Augmentations augs) |
| throws XNIException { |
| |
| if (!fDeferNodeExpansion) { |
| if (fDocumentImpl != null) { |
| fDocumentType = fDocumentImpl.createDocumentType ( |
| rootElement, publicId, systemId); |
| fCurrentNode.appendChild (fDocumentType); |
| } |
| } |
| else { |
| fDocumentTypeIndex = fDeferredDocumentImpl. |
| createDeferredDocumentType (rootElement, publicId, systemId); |
| fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, fDocumentTypeIndex); |
| } |
| |
| } // doctypeDecl(String,String,String) |
| |
| /** |
| * 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. |
| */ |
| public void startElement (QName element, XMLAttributes attributes, Augmentations augs) |
| throws XNIException { |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>startElement ("+element.rawname+")"); |
| } |
| if (!fDeferNodeExpansion) { |
| if (fFilterReject) { |
| return; |
| } |
| Element el = createElementNode (element); |
| int attrCount = attributes.getLength (); |
| for (int i = 0; i < attrCount; i++) { |
| attributes.getName (i, fAttrQName); |
| Attr attr = createAttrNode (fAttrQName); |
| |
| String attrValue = attributes.getValue (i); |
| |
| AttributePSVI attrPSVI =(AttributePSVI) attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_PSVI); |
| if (fStorePSVI && attrPSVI != null){ |
| ((PSVIAttrNSImpl) attr).setPSVI (attrPSVI); |
| } |
| |
| |
| attr.setValue (attrValue); |
| el.setAttributeNode (attr); |
| // NOTE: The specified value MUST be set after you set |
| // the node value because that turns the "specified" |
| // flag to "true" which may overwrite a "false" |
| // value from the attribute list. -Ac |
| if (fDocumentImpl != null) { |
| AttrImpl attrImpl = (AttrImpl) attr; |
| Object type = null; |
| boolean id = false; |
| |
| // REVISIT: currently it is possible that someone turns off |
| // namespaces and turns on xml schema validation |
| // To avoid classcast exception in AttrImpl check for namespaces |
| // however the correct solution should probably disallow setting |
| // namespaces to false when schema processing is turned on. |
| if (attrPSVI != null && fNamespaceAware) { |
| // XML Schema |
| type = attrPSVI.getMemberTypeDefinition (); |
| if (type == null) { |
| type = attrPSVI.getTypeDefinition (); |
| if (type != null) { |
| id = ((XSSimpleType) type).isIDType (); |
| attrImpl.setType (type); |
| } |
| } |
| else { |
| id = ((XSSimpleType) type).isIDType (); |
| attrImpl.setType (type); |
| } |
| } |
| else { |
| // DTD |
| boolean isDeclared = Boolean.TRUE.equals (attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_DECLARED)); |
| // For DOM Level 3 TypeInfo, the type name must |
| // be null if this attribute has not been declared |
| // in the DTD. |
| if (isDeclared) { |
| type = attributes.getType (i); |
| id = "ID".equals (type); |
| } |
| attrImpl.setType (type); |
| } |
| |
| if (id) { |
| ((ElementImpl) el).setIdAttributeNode (attr, true); |
| } |
| |
| attrImpl.setSpecified (attributes.isSpecified (i)); |
| // REVISIT: Handle entities in attribute value. |
| } |
| } |
| setCharacterData (false); |
| |
| if (augs != null) { |
| ElementPSVI elementPSVI = (ElementPSVI)augs.getItem (Constants.ELEMENT_PSVI); |
| if (elementPSVI != null && fNamespaceAware) { |
| XSTypeDefinition type = elementPSVI.getMemberTypeDefinition (); |
| if (type == null) { |
| type = elementPSVI.getTypeDefinition (); |
| } |
| ((ElementNSImpl)el).setType (type); |
| } |
| } |
| |
| |
| // filter nodes |
| if (fDOMFilter != null && !fInEntityRef) { |
| if (fRoot.rawname == null) { |
| // fill value of the root element |
| fRoot.setValues(element); |
| } else { |
| short code = fDOMFilter.startElement(el); |
| switch (code) { |
| case LSParserFilter.FILTER_INTERRUPT : |
| { |
| throw abort; |
| } |
| case LSParserFilter.FILTER_REJECT : |
| { |
| fFilterReject = true; |
| fRejectedElement.setValues(element); |
| return; |
| } |
| case LSParserFilter.FILTER_SKIP : |
| { |
| fSkippedElemStack.push(element.clone()); |
| return; |
| } |
| default : {} |
| } |
| } |
| } |
| fCurrentNode.appendChild (el); |
| fCurrentNode = el; |
| } |
| else { |
| Object type = null; |
| if (augs != null) { |
| ElementPSVI elementPSVI = (ElementPSVI)augs.getItem (Constants.ELEMENT_PSVI); |
| if (elementPSVI != null) { |
| type = elementPSVI.getMemberTypeDefinition (); |
| if (type == null) { |
| type = elementPSVI.getTypeDefinition (); |
| } |
| } |
| } |
| |
| int el = |
| fDeferredDocumentImpl.createDeferredElement (fNamespaceAware ? |
| element.uri : null, |
| element.rawname, |
| type); |
| int attrCount = attributes.getLength (); |
| for (int i = 0; i < attrCount; i++) { |
| // set type information |
| AttributePSVI attrPSVI = (AttributePSVI)attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_PSVI); |
| boolean id = false; |
| |
| // REVISIT: currently it is possible that someone turns off |
| // namespaces and turns on xml schema validation |
| // To avoid classcast exception in AttrImpl check for namespaces |
| // however the correct solution should probably disallow setting |
| // namespaces to false when schema processing is turned on. |
| if (attrPSVI != null && fNamespaceAware) { |
| // XML Schema |
| type = attrPSVI.getMemberTypeDefinition (); |
| if (type == null) { |
| type = attrPSVI.getTypeDefinition (); |
| if (type != null){ |
| id = ((XSSimpleType) type).isIDType (); |
| } |
| } |
| else { |
| id = ((XSSimpleType) type).isIDType (); |
| } |
| } |
| else { |
| // DTD |
| boolean isDeclared = Boolean.TRUE.equals (attributes.getAugmentations (i).getItem (Constants.ATTRIBUTE_DECLARED)); |
| // For DOM Level 3 TypeInfo, the type name must |
| // be null if this attribute has not been declared |
| // in the DTD. |
| if (isDeclared) { |
| type = attributes.getType (i); |
| id = "ID".equals (type); |
| } |
| } |
| |
| // create attribute |
| fDeferredDocumentImpl.setDeferredAttribute ( |
| el, |
| attributes.getQName (i), |
| attributes.getURI (i), |
| attributes.getValue (i), |
| attributes.isSpecified (i), |
| id, |
| type); |
| } |
| |
| fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, el); |
| fCurrentNodeIndex = el; |
| } |
| } // startElement(QName,XMLAttributes) |
| |
| |
| /** |
| * An empty element. |
| * |
| * @param element The name of the element. |
| * @param attributes The element attributes. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void emptyElement (QName element, XMLAttributes attributes, Augmentations augs) |
| throws XNIException { |
| |
| startElement (element, attributes, augs); |
| endElement (element, augs); |
| |
| } // emptyElement(QName,XMLAttributes) |
| |
| /** |
| * Character content. |
| * |
| * @param text The content. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void characters (XMLString text, Augmentations augs) throws XNIException { |
| |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>characters(): "+text.toString ()); |
| } |
| |
| if (!fDeferNodeExpansion) { |
| |
| if (fFilterReject) { |
| return; |
| } |
| if (fInCDATASection && fCreateCDATANodes) { |
| if (fCurrentCDATASection == null) { |
| fCurrentCDATASection = |
| fDocument.createCDATASection (text.toString ()); |
| fCurrentNode.appendChild (fCurrentCDATASection); |
| fCurrentNode = fCurrentCDATASection; |
| } |
| else { |
| fCurrentCDATASection.appendData (text.toString ()); |
| } |
| } |
| else if (!fInDTD) { |
| // if type is union (XML Schema) it is possible that we receive |
| // character call with empty data |
| if (text.length == 0) { |
| return; |
| } |
| |
| Node child = fCurrentNode.getLastChild (); |
| if (child != null && child.getNodeType () == Node.TEXT_NODE) { |
| // collect all the data into the string buffer. |
| if (fFirstChunk) { |
| if (fDocumentImpl != null) { |
| fStringBuffer.append (((TextImpl)child).removeData ()); |
| } else { |
| fStringBuffer.append (((Text)child).getData ()); |
| ((Text)child).setNodeValue (null); |
| } |
| fFirstChunk = false; |
| } |
| if (text.length > 0) { |
| fStringBuffer.append (text.ch, text.offset, text.length); |
| } |
| } |
| else { |
| fFirstChunk = true; |
| Text textNode = fDocument.createTextNode (text.toString()); |
| fCurrentNode.appendChild (textNode); |
| } |
| |
| } |
| } |
| else { |
| // The Text and CDATASection normalization is taken care of within |
| // the DOM in the deferred case. |
| if (fInCDATASection && fCreateCDATANodes) { |
| if (fCurrentCDATASectionIndex == -1) { |
| int cs = fDeferredDocumentImpl. |
| createDeferredCDATASection (text.toString ()); |
| |
| fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, cs); |
| fCurrentCDATASectionIndex = cs; |
| fCurrentNodeIndex = cs; |
| } |
| else { |
| int txt = fDeferredDocumentImpl. |
| createDeferredTextNode (text.toString (), false); |
| fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, txt); |
| } |
| } else if (!fInDTD) { |
| // if type is union (XML Schema) it is possible that we receive |
| // character call with empty data |
| if (text.length == 0) { |
| return; |
| } |
| |
| String value = text.toString (); |
| int txt = fDeferredDocumentImpl. |
| createDeferredTextNode (value, false); |
| fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, txt); |
| |
| } |
| } |
| } // characters(XMLString) |
| |
| /** |
| * Ignorable whitespace. For this method to be called, the document |
| * source must have some way of determining that the text containing |
| * only whitespace characters should be considered ignorable. For |
| * example, the validator can determine if a length of whitespace |
| * characters in the document are ignorable based on the element |
| * content model. |
| * |
| * @param text The ignorable whitespace. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void ignorableWhitespace (XMLString text, Augmentations augs) throws XNIException { |
| |
| if (!fIncludeIgnorableWhitespace || fFilterReject) { |
| return; |
| } |
| if (!fDeferNodeExpansion) { |
| Node child = fCurrentNode.getLastChild (); |
| if (child != null && child.getNodeType () == Node.TEXT_NODE) { |
| Text textNode = (Text)child; |
| textNode.appendData (text.toString ()); |
| } |
| else { |
| Text textNode = fDocument.createTextNode (text.toString ()); |
| if (fDocumentImpl != null) { |
| TextImpl textNodeImpl = (TextImpl)textNode; |
| textNodeImpl.setIgnorableWhitespace (true); |
| } |
| fCurrentNode.appendChild (textNode); |
| } |
| } |
| else { |
| // The Text normalization is taken care of within the DOM in the |
| // deferred case. |
| int txt = fDeferredDocumentImpl. |
| createDeferredTextNode (text.toString (), true); |
| fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, txt); |
| } |
| |
| } // ignorableWhitespace(XMLString) |
| |
| /** |
| * The end of an element. |
| * |
| * @param element The name of the element. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void endElement (QName element, Augmentations augs) throws XNIException { |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>endElement ("+element.rawname+")"); |
| } |
| if (!fDeferNodeExpansion) { |
| |
| // REVISIT: Should this happen after we call the filter? |
| if (augs != null && fDocumentImpl != null && (fNamespaceAware || fStorePSVI)) { |
| ElementPSVI elementPSVI = (ElementPSVI) augs.getItem(Constants.ELEMENT_PSVI); |
| if (elementPSVI != null) { |
| // Updating TypeInfo. If the declared type is a union the |
| // [member type definition] will only be available at the |
| // end of an element. |
| if (fNamespaceAware) { |
| XSTypeDefinition type = elementPSVI.getMemberTypeDefinition(); |
| if (type == null) { |
| type = elementPSVI.getTypeDefinition(); |
| } |
| ((ElementNSImpl)fCurrentNode).setType(type); |
| } |
| if (fStorePSVI) { |
| ((PSVIElementNSImpl)fCurrentNode).setPSVI (elementPSVI); |
| } |
| } |
| } |
| |
| if (fDOMFilter != null) { |
| if (fFilterReject) { |
| if (element.equals (fRejectedElement)) { |
| fFilterReject = false; |
| } |
| return; |
| } |
| if (!fSkippedElemStack.isEmpty ()) { |
| if (fSkippedElemStack.peek ().equals (element)) { |
| fSkippedElemStack.pop (); |
| return; |
| } |
| } |
| setCharacterData (false); |
| if (!fRoot.equals(element) && !fInEntityRef && (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_ELEMENT)!=0) { |
| short code = fDOMFilter.acceptNode (fCurrentNode); |
| switch (code) { |
| case LSParserFilter.FILTER_INTERRUPT:{ |
| throw abort; |
| } |
| case LSParserFilter.FILTER_REJECT:{ |
| Node parent = fCurrentNode.getParentNode (); |
| parent.removeChild (fCurrentNode); |
| fCurrentNode = parent; |
| return; |
| } |
| case LSParserFilter.FILTER_SKIP: { |
| // make sure that if any char data is available |
| // the fFirstChunk is true, so that if the next event |
| // is characters(), and the last node is text, we will copy |
| // the value already in the text node to fStringBuffer |
| // (not to loose it). |
| fFirstChunk = true; |
| |
| // replace children |
| Node parent = fCurrentNode.getParentNode (); |
| NodeList ls = fCurrentNode.getChildNodes (); |
| int length = ls.getLength (); |
| |
| for (int i=0;i<length;i++) { |
| parent.appendChild (ls.item (0)); |
| } |
| parent.removeChild (fCurrentNode); |
| fCurrentNode = parent; |
| |
| return; |
| } |
| |
| default: { } |
| } |
| } |
| fCurrentNode = fCurrentNode.getParentNode (); |
| |
| } // end-if DOMFilter |
| else { |
| setCharacterData (false); |
| fCurrentNode = fCurrentNode.getParentNode (); |
| } |
| |
| } |
| else { |
| fCurrentNodeIndex = |
| fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex, false); |
| } |
| |
| |
| } // endElement(QName) |
| |
| |
| /** |
| * The start of a CDATA section. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void startCDATA (Augmentations augs) throws XNIException { |
| |
| fInCDATASection = true; |
| if (!fDeferNodeExpansion) { |
| if (fFilterReject) { |
| return; |
| } |
| if (fCreateCDATANodes) { |
| setCharacterData (false); |
| } |
| } |
| } // startCDATA() |
| |
| /** |
| * The end of a CDATA section. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void endCDATA (Augmentations augs) throws XNIException { |
| |
| fInCDATASection = false; |
| if (!fDeferNodeExpansion) { |
| |
| if (fFilterReject) { |
| return; |
| } |
| |
| if (fCurrentCDATASection !=null) { |
| |
| if (fDOMFilter !=null && !fInEntityRef && |
| (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_CDATA_SECTION)!= 0) { |
| short code = fDOMFilter.acceptNode (fCurrentCDATASection); |
| switch (code) { |
| case LSParserFilter.FILTER_INTERRUPT:{ |
| throw abort; |
| } |
| case LSParserFilter.FILTER_REJECT:{ |
| // fall through to SKIP since CDATA section has no children. |
| } |
| case LSParserFilter.FILTER_SKIP: { |
| Node parent = fCurrentNode.getParentNode (); |
| parent.removeChild (fCurrentCDATASection); |
| fCurrentNode = parent; |
| return; |
| } |
| |
| default: { |
| // accept node |
| } |
| } |
| } |
| |
| fCurrentNode = fCurrentNode.getParentNode (); |
| fCurrentCDATASection = null; |
| } |
| } |
| else { |
| if (fCurrentCDATASectionIndex !=-1) { |
| fCurrentNodeIndex = |
| fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex, false); |
| fCurrentCDATASectionIndex = -1; |
| } |
| } |
| |
| } // endCDATA() |
| |
| /** |
| * The end of the document. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void endDocument (Augmentations augs) throws XNIException { |
| |
| if (!fDeferNodeExpansion) { |
| // REVISIT: when DOM Level 3 is REC rely on Document.support |
| // instead of specific class |
| // set the actual encoding and set DOM error checking back on |
| if (fDocumentImpl != null) { |
| if (fLocator != null) { |
| fDocumentImpl.setInputEncoding (fLocator.getEncoding()); |
| } |
| fDocumentImpl.setStrictErrorChecking (true); |
| } |
| fCurrentNode = null; |
| } |
| else { |
| // set the actual encoding |
| if (fLocator != null) { |
| fDeferredDocumentImpl.setInputEncoding (fLocator.getEncoding()); |
| } |
| fCurrentNodeIndex = -1; |
| } |
| |
| } // endDocument() |
| |
| /** |
| * This method notifies the end of a general entity. |
| * <p> |
| * <strong>Note:</strong> This method is not called for entity references |
| * appearing as part of attribute values. |
| * |
| * @param name The name of the entity. |
| * @param augs Additional information that may include infoset augmentations |
| * |
| * @exception XNIException |
| * Thrown by handler to signal an error. |
| */ |
| public void endGeneralEntity (String name, Augmentations augs) throws XNIException { |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>endGeneralEntity: ("+name+")"); |
| } |
| if (!fDeferNodeExpansion) { |
| |
| if (fFilterReject) { |
| return; |
| } |
| setCharacterData (true); |
| |
| if (fDocumentType != null) { |
| // get current entity declaration |
| NamedNodeMap entities = fDocumentType.getEntities (); |
| fCurrentEntityDecl = (EntityImpl) entities.getNamedItem (name); |
| if (fCurrentEntityDecl != null) { |
| if (fCurrentEntityDecl != null && fCurrentEntityDecl.getFirstChild () == null) { |
| fCurrentEntityDecl.setReadOnly (false, true); |
| Node child = fCurrentNode.getFirstChild (); |
| while (child != null) { |
| Node copy = child.cloneNode (true); |
| fCurrentEntityDecl.appendChild (copy); |
| child = child.getNextSibling (); |
| } |
| fCurrentEntityDecl.setReadOnly (true, true); |
| |
| //entities.setNamedItem(fCurrentEntityDecl); |
| } |
| fCurrentEntityDecl = null; |
| } |
| |
| } |
| fInEntityRef = false; |
| boolean removeEntityRef = false; |
| if (fCreateEntityRefNodes) { |
| if (fDocumentImpl != null) { |
| // Make entity ref node read only |
| ((NodeImpl)fCurrentNode).setReadOnly (true, true); |
| } |
| |
| if (fDOMFilter !=null && |
| (fDOMFilter.getWhatToShow () & NodeFilter.SHOW_ENTITY_REFERENCE)!= 0) { |
| short code = fDOMFilter.acceptNode (fCurrentNode); |
| switch (code) { |
| case LSParserFilter.FILTER_INTERRUPT:{ |
| throw abort; |
| } |
| case LSParserFilter.FILTER_REJECT:{ |
| Node parent = fCurrentNode.getParentNode (); |
| parent.removeChild (fCurrentNode); |
| fCurrentNode = parent; |
| return; |
| |
| } |
| case LSParserFilter.FILTER_SKIP: { |
| // make sure we don't loose chars if next event is characters() |
| fFirstChunk = true; |
| removeEntityRef = true; |
| break; |
| } |
| |
| default: { |
| fCurrentNode = fCurrentNode.getParentNode (); |
| } |
| } |
| } else { |
| fCurrentNode = fCurrentNode.getParentNode (); |
| } |
| } |
| |
| if (!fCreateEntityRefNodes || removeEntityRef) { |
| // move entity reference children to the list of |
| // siblings of its parent and remove entity reference |
| NodeList children = fCurrentNode.getChildNodes (); |
| Node parent = fCurrentNode.getParentNode (); |
| int length = children.getLength (); |
| if (length > 0) { |
| |
| // get previous sibling of the entity reference |
| Node node = fCurrentNode.getPreviousSibling (); |
| // normalize text nodes |
| Node child = children.item (0); |
| if (node != null && node.getNodeType () == Node.TEXT_NODE && |
| child.getNodeType () == Node.TEXT_NODE) { |
| ((Text)node).appendData (child.getNodeValue ()); |
| fCurrentNode.removeChild (child); |
| |
| } else { |
| node = parent.insertBefore (child, fCurrentNode); |
| handleBaseURI (node); |
| } |
| |
| for (int i=1;i <length;i++) { |
| node = parent.insertBefore (children.item (0), fCurrentNode); |
| handleBaseURI (node); |
| } |
| } // length > 0 |
| parent.removeChild (fCurrentNode); |
| fCurrentNode = parent; |
| } |
| } |
| else { |
| |
| if (fDocumentTypeIndex != -1) { |
| // find corresponding Entity decl |
| int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); |
| while (node != -1) { |
| short nodeType = fDeferredDocumentImpl.getNodeType (node, false); |
| if (nodeType == Node.ENTITY_NODE) { |
| String nodeName = |
| fDeferredDocumentImpl.getNodeName (node, false); |
| if (nodeName.equals (name)) { |
| fDeferredEntityDecl = node; |
| break; |
| } |
| } |
| node = fDeferredDocumentImpl.getRealPrevSibling (node, false); |
| } |
| } |
| |
| if (fDeferredEntityDecl != -1 && |
| fDeferredDocumentImpl.getLastChild (fDeferredEntityDecl, false) == -1) { |
| // entity definition exists and it does not have any children |
| int prevIndex = -1; |
| int childIndex = fDeferredDocumentImpl.getLastChild (fCurrentNodeIndex, false); |
| while (childIndex != -1) { |
| int cloneIndex = fDeferredDocumentImpl.cloneNode (childIndex, true); |
| fDeferredDocumentImpl.insertBefore (fDeferredEntityDecl, cloneIndex, prevIndex); |
| prevIndex = cloneIndex; |
| childIndex = fDeferredDocumentImpl.getRealPrevSibling (childIndex, false); |
| } |
| } |
| if (fCreateEntityRefNodes) { |
| fCurrentNodeIndex = |
| fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex, |
| false); |
| } else { //!fCreateEntityRefNodes |
| // move children of entity ref before the entity ref. |
| // remove entity ref. |
| |
| // holds a child of entity ref |
| int childIndex = fDeferredDocumentImpl.getLastChild (fCurrentNodeIndex, false); |
| int parentIndex = |
| fDeferredDocumentImpl.getParentNode (fCurrentNodeIndex, |
| false); |
| |
| int prevIndex = fCurrentNodeIndex; |
| int lastChild = childIndex; |
| int sibling = -1; |
| while (childIndex != -1) { |
| handleBaseURI (childIndex); |
| sibling = fDeferredDocumentImpl.getRealPrevSibling (childIndex, false); |
| fDeferredDocumentImpl.insertBefore (parentIndex, childIndex, prevIndex); |
| prevIndex = childIndex; |
| childIndex = sibling; |
| } |
| if(lastChild != -1) |
| fDeferredDocumentImpl.setAsLastChild (parentIndex, lastChild); |
| else{ |
| sibling = fDeferredDocumentImpl.getRealPrevSibling (prevIndex, false); |
| fDeferredDocumentImpl.setAsLastChild (parentIndex, sibling); |
| } |
| fCurrentNodeIndex = parentIndex; |
| } |
| fDeferredEntityDecl = -1; |
| } |
| |
| |
| } // endGeneralEntity(String, Augmentations) |
| |
| |
| /** |
| * Record baseURI information for the Element (by adding xml:base attribute) |
| * or for the ProcessingInstruction (by setting a baseURI field) |
| * Non deferred DOM. |
| * |
| * @param node |
| */ |
| protected final void handleBaseURI (Node node){ |
| if (fDocumentImpl != null) { |
| // REVISIT: remove dependency on our implementation when |
| // DOM L3 becomes REC |
| |
| String baseURI = null; |
| short nodeType = node.getNodeType (); |
| |
| if (nodeType == Node.ELEMENT_NODE) { |
| // if an element already has xml:base attribute |
| // do nothing |
| if (fNamespaceAware) { |
| if (((Element)node).getAttributeNodeNS ("http://www.w3.org/XML/1998/namespace","base")!=null) { |
| return; |
| } |
| } else if (((Element)node).getAttributeNode ("xml:base") != null) { |
| return; |
| } |
| // retrive the baseURI from the entity reference |
| baseURI = ((EntityReferenceImpl)fCurrentNode).getBaseURI (); |
| if (baseURI !=null && !baseURI.equals (fDocumentImpl.getDocumentURI ())) { |
| if (fNamespaceAware) { |
| ((Element)node).setAttributeNS ("http://www.w3.org/XML/1998/namespace","base", baseURI); |
| } else { |
| ((Element)node).setAttribute ("xml:base", baseURI); |
| } |
| } |
| } |
| else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) { |
| |
| baseURI = ((EntityReferenceImpl)fCurrentNode).getBaseURI (); |
| if (baseURI !=null && fErrorHandler != null) { |
| DOMErrorImpl error = new DOMErrorImpl (); |
| error.fType = "pi-base-uri-not-preserved"; |
| error.fRelatedData = baseURI; |
| error.fSeverity = DOMError.SEVERITY_WARNING; |
| fErrorHandler.getErrorHandler ().handleError (error); |
| } |
| } |
| } |
| } |
| |
| /** |
| * |
| * Record baseURI information for the Element (by adding xml:base attribute) |
| * or for the ProcessingInstruction (by setting a baseURI field) |
| * Deferred DOM. |
| * |
| * @param node |
| */ |
| protected final void handleBaseURI (int node){ |
| short nodeType = fDeferredDocumentImpl.getNodeType (node, false); |
| |
| if (nodeType == Node.ELEMENT_NODE) { |
| String baseURI = fDeferredDocumentImpl.getNodeValueString (fCurrentNodeIndex, false); |
| if (baseURI == null) { |
| baseURI = fDeferredDocumentImpl.getDeferredEntityBaseURI (fDeferredEntityDecl); |
| } |
| if (baseURI !=null && !baseURI.equals (fDeferredDocumentImpl.getDocumentURI ())) { |
| fDeferredDocumentImpl.setDeferredAttribute (node, |
| "xml:base", |
| "http://www.w3.org/XML/1998/namespace", |
| baseURI, |
| true); |
| } |
| } |
| else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) { |
| |
| |
| // retrieve baseURI from the entity reference |
| String baseURI = fDeferredDocumentImpl.getNodeValueString (fCurrentNodeIndex, false); |
| |
| if (baseURI == null) { |
| // try baseURI of the entity declaration |
| baseURI = fDeferredDocumentImpl.getDeferredEntityBaseURI (fDeferredEntityDecl); |
| } |
| |
| if (baseURI != null && fErrorHandler != null) { |
| DOMErrorImpl error = new DOMErrorImpl (); |
| error.fType = "pi-base-uri-not-preserved"; |
| error.fRelatedData = baseURI; |
| error.fSeverity = DOMError.SEVERITY_WARNING; |
| fErrorHandler.getErrorHandler ().handleError (error); |
| } |
| } |
| } |
| |
| |
| // |
| // XMLDTDHandler methods |
| // |
| |
| /** |
| * The start of the DTD. |
| * |
| * @param locator The document locator, or null if the document |
| * location cannot be reported during the parsing of |
| * the document DTD. However, it is <em>strongly</em> |
| * recommended that a locator be supplied that can |
| * at least report the base system identifier of the |
| * DTD. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void startDTD (XMLLocator locator, Augmentations augs) throws XNIException { |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>startDTD"); |
| if (DEBUG_BASEURI) { |
| System.out.println (" expandedSystemId: "+locator.getExpandedSystemId ()); |
| System.out.println (" baseURI:"+ locator.getBaseSystemId ()); |
| } |
| } |
| |
| fInDTD = true; |
| if (locator != null) { |
| fBaseURIStack.push (locator.getBaseSystemId ()); |
| } |
| if (fDeferNodeExpansion || fDocumentImpl != null) { |
| fInternalSubset = new StringBuffer (1024); |
| } |
| } // startDTD(XMLLocator) |
| |
| |
| /** |
| * The end of the DTD. |
| * |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void endDTD (Augmentations augs) throws XNIException { |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>endDTD()"); |
| } |
| fInDTD = false; |
| if (!fBaseURIStack.isEmpty ()) { |
| fBaseURIStack.pop (); |
| } |
| String internalSubset = fInternalSubset != null && fInternalSubset.length () > 0 |
| ? fInternalSubset.toString () : null; |
| if (fDeferNodeExpansion) { |
| if (internalSubset != null) { |
| fDeferredDocumentImpl.setInternalSubset (fDocumentTypeIndex, internalSubset); |
| } |
| } |
| else if (fDocumentImpl != null) { |
| if (internalSubset != null) { |
| ((DocumentTypeImpl)fDocumentType).setInternalSubset (internalSubset); |
| } |
| } |
| } // endDTD() |
| |
| /** |
| * The start of a conditional section. |
| * |
| * @param type The type of the conditional section. This value will |
| * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| * |
| * @see #CONDITIONAL_INCLUDE |
| * @see #CONDITIONAL_IGNORE |
| */ |
| public void startConditional (short type, Augmentations augs) throws XNIException { |
| } // startConditional(short) |
| |
| /** |
| * The end of a conditional section. |
| * |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void endConditional (Augmentations augs) throws XNIException { |
| } // endConditional() |
| |
| |
| /** |
| * The start of the DTD external subset. |
| * |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void startExternalSubset (XMLResourceIdentifier identifier, |
| Augmentations augs) throws XNIException { |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>startExternalSubset"); |
| if (DEBUG_BASEURI) { |
| System.out.println (" expandedSystemId: "+identifier.getExpandedSystemId ()); |
| System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); |
| } |
| } |
| fBaseURIStack.push (identifier.getBaseSystemId ()); |
| fInDTDExternalSubset = true; |
| } // startExternalSubset(Augmentations) |
| |
| /** |
| * The end of the DTD external subset. |
| * |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void endExternalSubset (Augmentations augs) throws XNIException { |
| fInDTDExternalSubset = false; |
| fBaseURIStack.pop (); |
| } // endExternalSubset(Augmentations) |
| |
| /** |
| * An internal entity declaration. |
| * |
| * @param name The name of the entity. Parameter entity names start with |
| * '%', whereas the name of a general entity is just the |
| * entity name. |
| * @param text The value of the entity. |
| * @param nonNormalizedText The non-normalized value of the entity. This |
| * value contains the same sequence of characters that was in |
| * the internal entity declaration, without any entity |
| * references expanded. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void internalEntityDecl (String name, XMLString text, |
| XMLString nonNormalizedText, |
| Augmentations augs) throws XNIException { |
| |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>internalEntityDecl: "+name); |
| if (DEBUG_BASEURI) { |
| System.out.println (" baseURI:"+ (String)fBaseURIStack.peek ()); |
| } |
| } |
| // internal subset string |
| if (fInternalSubset != null && !fInDTDExternalSubset) { |
| fInternalSubset.append ("<!ENTITY "); |
| if (name.startsWith ("%")) { |
| fInternalSubset.append ("% "); |
| fInternalSubset.append (name.substring (1)); |
| } |
| else { |
| fInternalSubset.append (name); |
| } |
| fInternalSubset.append (' '); |
| String value = nonNormalizedText.toString (); |
| boolean singleQuote = value.indexOf ('\'') == -1; |
| fInternalSubset.append (singleQuote ? '\'' : '"'); |
| fInternalSubset.append (value); |
| fInternalSubset.append (singleQuote ? '\'' : '"'); |
| fInternalSubset.append (">\n"); |
| } |
| |
| // NOTE: We only know how to create these nodes for the Xerces |
| // DOM implementation because DOM Level 2 does not specify |
| // that functionality. -Ac |
| |
| // create full node |
| // don't add parameter entities! |
| if(name.startsWith ("%")) |
| return; |
| if (fDocumentType != null) { |
| NamedNodeMap entities = fDocumentType.getEntities (); |
| EntityImpl entity = (EntityImpl)entities.getNamedItem (name); |
| if (entity == null) { |
| entity = (EntityImpl)fDocumentImpl.createEntity (name); |
| entity.setBaseURI ((String)fBaseURIStack.peek ()); |
| entities.setNamedItem (entity); |
| } |
| } |
| |
| // create deferred node |
| if (fDocumentTypeIndex != -1) { |
| boolean found = false; |
| int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); |
| while (node != -1) { |
| short nodeType = fDeferredDocumentImpl.getNodeType (node, false); |
| if (nodeType == Node.ENTITY_NODE) { |
| String nodeName = fDeferredDocumentImpl.getNodeName (node, false); |
| if (nodeName.equals (name)) { |
| found = true; |
| break; |
| } |
| } |
| node = fDeferredDocumentImpl.getRealPrevSibling (node, false); |
| } |
| if (!found) { |
| int entityIndex = |
| fDeferredDocumentImpl.createDeferredEntity (name, null, null, null, (String)fBaseURIStack.peek ()); |
| fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, entityIndex); |
| } |
| } |
| |
| } // internalEntityDecl(String,XMLString,XMLString) |
| |
| /** |
| * An external entity declaration. |
| * |
| * @param name The name of the entity. Parameter entity names start |
| * with '%', whereas the name of a general entity is just |
| * the entity name. |
| * @param identifier An object containing all location information |
| * pertinent to this notation. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void externalEntityDecl (String name, XMLResourceIdentifier identifier, |
| Augmentations augs) throws XNIException { |
| |
| |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>externalEntityDecl: "+name); |
| if (DEBUG_BASEURI) { |
| System.out.println (" expandedSystemId:"+ identifier.getExpandedSystemId ()); |
| System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); |
| } |
| } |
| // internal subset string |
| String publicId = identifier.getPublicId (); |
| String literalSystemId = identifier.getLiteralSystemId (); |
| if (fInternalSubset != null && !fInDTDExternalSubset) { |
| fInternalSubset.append ("<!ENTITY "); |
| if (name.startsWith ("%")) { |
| fInternalSubset.append ("% "); |
| fInternalSubset.append (name.substring (1)); |
| } |
| else { |
| fInternalSubset.append (name); |
| } |
| fInternalSubset.append (' '); |
| if (publicId != null) { |
| fInternalSubset.append ("PUBLIC '"); |
| fInternalSubset.append (publicId); |
| fInternalSubset.append ("' '"); |
| } |
| else { |
| fInternalSubset.append ("SYSTEM '"); |
| } |
| fInternalSubset.append (literalSystemId); |
| fInternalSubset.append ("'>\n"); |
| } |
| |
| // NOTE: We only know how to create these nodes for the Xerces |
| // DOM implementation because DOM Level 2 does not specify |
| // that functionality. -Ac |
| |
| // create full node |
| // don't add parameter entities! |
| if(name.startsWith ("%")) |
| return; |
| if (fDocumentType != null) { |
| NamedNodeMap entities = fDocumentType.getEntities (); |
| EntityImpl entity = (EntityImpl)entities.getNamedItem (name); |
| if (entity == null) { |
| entity = (EntityImpl)fDocumentImpl.createEntity (name); |
| entity.setPublicId (publicId); |
| entity.setSystemId (literalSystemId); |
| entity.setBaseURI (identifier.getBaseSystemId ()); |
| entities.setNamedItem (entity); |
| } |
| } |
| |
| // create deferred node |
| if (fDocumentTypeIndex != -1) { |
| boolean found = false; |
| int nodeIndex = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); |
| while (nodeIndex != -1) { |
| short nodeType = fDeferredDocumentImpl.getNodeType (nodeIndex, false); |
| if (nodeType == Node.ENTITY_NODE) { |
| String nodeName = fDeferredDocumentImpl.getNodeName (nodeIndex, false); |
| if (nodeName.equals (name)) { |
| found = true; |
| break; |
| } |
| } |
| nodeIndex = fDeferredDocumentImpl.getRealPrevSibling (nodeIndex, false); |
| } |
| if (!found) { |
| int entityIndex = fDeferredDocumentImpl.createDeferredEntity ( |
| name, publicId, literalSystemId, null, identifier.getBaseSystemId ()); |
| fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, entityIndex); |
| } |
| } |
| |
| } // externalEntityDecl(String,XMLResourceIdentifier, Augmentations) |
| |
| |
| /** |
| * This method notifies of the start of a parameter entity. The parameter |
| * entity name start with a '%' character. |
| * |
| * @param name The name of the parameter 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 parameter entities). |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void startParameterEntity (String name, |
| XMLResourceIdentifier identifier, |
| String encoding, |
| Augmentations augs) throws XNIException { |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>startParameterEntity: "+name); |
| if (DEBUG_BASEURI) { |
| System.out.println (" expandedSystemId: "+identifier.getExpandedSystemId ()); |
| System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); |
| } |
| } |
| fBaseURIStack.push (identifier.getExpandedSystemId ()); |
| } |
| |
| |
| /** |
| * This method notifies the end of a parameter entity. Parameter entity |
| * names begin with a '%' character. |
| * |
| * @param name The name of the parameter entity. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void endParameterEntity (String name, Augmentations augs) throws XNIException { |
| |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>endParameterEntity: "+name); |
| } |
| fBaseURIStack.pop (); |
| } |
| |
| /** |
| * An unparsed entity declaration. |
| * |
| * @param name The name of the entity. |
| * @param identifier An object containing all location information |
| * pertinent to this entity. |
| * @param notation The name of the notation. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void unparsedEntityDecl (String name, XMLResourceIdentifier identifier, |
| String notation, Augmentations augs) |
| throws XNIException { |
| |
| if (DEBUG_EVENTS) { |
| System.out.println ("==>unparsedEntityDecl: "+name); |
| if (DEBUG_BASEURI) { |
| System.out.println (" expandedSystemId:"+ identifier.getExpandedSystemId ()); |
| System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); |
| } |
| } |
| // internal subset string |
| String publicId = identifier.getPublicId (); |
| String literalSystemId = identifier.getLiteralSystemId (); |
| if (fInternalSubset != null && !fInDTDExternalSubset) { |
| fInternalSubset.append ("<!ENTITY "); |
| fInternalSubset.append (name); |
| fInternalSubset.append (' '); |
| if (publicId != null) { |
| fInternalSubset.append ("PUBLIC '"); |
| fInternalSubset.append (publicId); |
| if (literalSystemId != null) { |
| fInternalSubset.append ("' '"); |
| fInternalSubset.append (literalSystemId); |
| } |
| } |
| else { |
| fInternalSubset.append ("SYSTEM '"); |
| fInternalSubset.append (literalSystemId); |
| } |
| fInternalSubset.append ("' NDATA "); |
| fInternalSubset.append (notation); |
| fInternalSubset.append (">\n"); |
| } |
| |
| // NOTE: We only know how to create these nodes for the Xerces |
| // DOM implementation because DOM Level 2 does not specify |
| // that functionality. -Ac |
| |
| // create full node |
| if (fDocumentType != null) { |
| NamedNodeMap entities = fDocumentType.getEntities (); |
| EntityImpl entity = (EntityImpl)entities.getNamedItem (name); |
| if (entity == null) { |
| entity = (EntityImpl)fDocumentImpl.createEntity (name); |
| entity.setPublicId (publicId); |
| entity.setSystemId (literalSystemId); |
| entity.setNotationName (notation); |
| entity.setBaseURI (identifier.getBaseSystemId ()); |
| entities.setNamedItem (entity); |
| } |
| } |
| |
| // create deferred node |
| if (fDocumentTypeIndex != -1) { |
| boolean found = false; |
| int nodeIndex = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); |
| while (nodeIndex != -1) { |
| short nodeType = fDeferredDocumentImpl.getNodeType (nodeIndex, false); |
| if (nodeType == Node.ENTITY_NODE) { |
| String nodeName = fDeferredDocumentImpl.getNodeName (nodeIndex, false); |
| if (nodeName.equals (name)) { |
| found = true; |
| break; |
| } |
| } |
| nodeIndex = fDeferredDocumentImpl.getRealPrevSibling (nodeIndex, false); |
| } |
| if (!found) { |
| int entityIndex = fDeferredDocumentImpl.createDeferredEntity ( |
| name, publicId, literalSystemId, notation, identifier.getBaseSystemId ()); |
| fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, entityIndex); |
| } |
| } |
| |
| } // unparsedEntityDecl(String,XMLResourceIdentifier, String, Augmentations) |
| |
| /** |
| * A notation declaration |
| * |
| * @param name The name of the notation. |
| * @param identifier An object containing all location information |
| * pertinent to this notation. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void notationDecl (String name, XMLResourceIdentifier identifier, |
| Augmentations augs) throws XNIException { |
| |
| // internal subset string |
| String publicId = identifier.getPublicId (); |
| String literalSystemId = identifier.getLiteralSystemId (); |
| if (fInternalSubset != null && !fInDTDExternalSubset) { |
| fInternalSubset.append ("<!NOTATION "); |
| fInternalSubset.append (name); |
| if (publicId != null) { |
| fInternalSubset.append (" PUBLIC '"); |
| fInternalSubset.append (publicId); |
| if (literalSystemId != null) { |
| fInternalSubset.append ("' '"); |
| fInternalSubset.append (literalSystemId); |
| } |
| } |
| else { |
| fInternalSubset.append (" SYSTEM '"); |
| fInternalSubset.append (literalSystemId); |
| } |
| fInternalSubset.append ("'>\n"); |
| } |
| |
| // NOTE: We only know how to create these nodes for the Xerces |
| // DOM implementation because DOM Level 2 does not specify |
| // that functionality. -Ac |
| |
| // create full node |
| if (fDocumentImpl !=null && fDocumentType != null) { |
| NamedNodeMap notations = fDocumentType.getNotations (); |
| if (notations.getNamedItem (name) == null) { |
| NotationImpl notation = (NotationImpl)fDocumentImpl.createNotation (name); |
| notation.setPublicId (publicId); |
| notation.setSystemId (literalSystemId); |
| notation.setBaseURI (identifier.getBaseSystemId ()); |
| notations.setNamedItem (notation); |
| } |
| } |
| |
| // create deferred node |
| if (fDocumentTypeIndex != -1) { |
| boolean found = false; |
| int nodeIndex = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); |
| while (nodeIndex != -1) { |
| short nodeType = fDeferredDocumentImpl.getNodeType (nodeIndex, false); |
| if (nodeType == Node.NOTATION_NODE) { |
| String nodeName = fDeferredDocumentImpl.getNodeName (nodeIndex, false); |
| if (nodeName.equals (name)) { |
| found = true; |
| break; |
| } |
| } |
| nodeIndex = fDeferredDocumentImpl.getPrevSibling (nodeIndex, false); |
| } |
| if (!found) { |
| int notationIndex = fDeferredDocumentImpl.createDeferredNotation ( |
| name, publicId, literalSystemId, identifier.getBaseSystemId ()); |
| fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, notationIndex); |
| } |
| } |
| |
| } // notationDecl(String,XMLResourceIdentifier, Augmentations) |
| |
| /** |
| * Characters within an IGNORE conditional section. |
| * |
| * @param text The ignored text. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void ignoredCharacters (XMLString text, Augmentations augs) throws XNIException { |
| } // ignoredCharacters(XMLString, Augmentations) |
| |
| |
| /** |
| * An element declaration. |
| * |
| * @param name The name of the element. |
| * @param contentModel The element content model. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void elementDecl (String name, String contentModel, Augmentations augs) |
| throws XNIException { |
| |
| // internal subset string |
| if (fInternalSubset != null && !fInDTDExternalSubset) { |
| fInternalSubset.append ("<!ELEMENT "); |
| fInternalSubset.append (name); |
| fInternalSubset.append (' '); |
| fInternalSubset.append (contentModel); |
| fInternalSubset.append (">\n"); |
| } |
| |
| } // elementDecl(String,String) |
| |
| /** |
| * An attribute declaration. |
| * |
| * @param elementName The name of the element that this attribute |
| * is associated with. |
| * @param attributeName The name of the attribute. |
| * @param type The attribute type. This value will be one of |
| * the following: "CDATA", "ENTITY", "ENTITIES", |
| * "ENUMERATION", "ID", "IDREF", "IDREFS", |
| * "NMTOKEN", "NMTOKENS", or "NOTATION". |
| * @param enumeration If the type has the value "ENUMERATION" or |
| * "NOTATION", this array holds the allowed attribute |
| * values; otherwise, this array is null. |
| * @param defaultType The attribute default type. This value will be |
| * one of the following: "#FIXED", "#IMPLIED", |
| * "#REQUIRED", or null. |
| * @param defaultValue The attribute default value, or null if no |
| * default value is specified. |
| * @param nonNormalizedDefaultValue The attribute default value with no normalization |
| * performed, or null if no default value is specified. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void attributeDecl (String elementName, String attributeName, |
| String type, String[] enumeration, |
| String defaultType, XMLString defaultValue, |
| XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException { |
| |
| // internal subset string |
| if (fInternalSubset != null && !fInDTDExternalSubset) { |
| fInternalSubset.append ("<!ATTLIST "); |
| fInternalSubset.append (elementName); |
| fInternalSubset.append (' '); |
| fInternalSubset.append (attributeName); |
| fInternalSubset.append (' '); |
| if (type.equals ("ENUMERATION")) { |
| fInternalSubset.append ('('); |
| for (int i = 0; i < enumeration.length; i++) { |
| if (i > 0) { |
| fInternalSubset.append ('|'); |
| } |
| fInternalSubset.append (enumeration[i]); |
| } |
| fInternalSubset.append (')'); |
| } |
| else { |
| fInternalSubset.append (type); |
| } |
| if (defaultType != null) { |
| fInternalSubset.append (' '); |
| fInternalSubset.append (defaultType); |
| } |
| if (defaultValue != null) { |
| fInternalSubset.append (" '"); |
| for (int i = 0; i < defaultValue.length; i++) { |
| char c = defaultValue.ch[defaultValue.offset + i]; |
| if (c == '\'') { |
| fInternalSubset.append ("'"); |
| } |
| else { |
| fInternalSubset.append (c); |
| } |
| } |
| fInternalSubset.append ('\''); |
| } |
| fInternalSubset.append (">\n"); |
| } |
| // REVISIT: This code applies to the support of domx/grammar-access |
| // feature in Xerces 1 |
| |
| // deferred expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| // get the default value |
| if (defaultValue != null) { |
| |
| // get element definition |
| int elementDefIndex = fDeferredDocumentImpl.lookupElementDefinition (elementName); |
| |
| // create element definition if not already there |
| if (elementDefIndex == -1) { |
| elementDefIndex = fDeferredDocumentImpl.createDeferredElementDefinition (elementName); |
| fDeferredDocumentImpl.appendChild (fDocumentTypeIndex, elementDefIndex); |
| } |
| // add default attribute |
| int attrIndex = fDeferredDocumentImpl.createDeferredAttribute ( |
| attributeName, defaultValue.toString (), false); |
| if ("ID".equals (type)) { |
| fDeferredDocumentImpl.setIdAttribute (attrIndex); |
| } |
| // REVISIT: set ID type correctly |
| fDeferredDocumentImpl.appendChild (elementDefIndex, attrIndex); |
| } |
| |
| } // if deferred |
| |
| // full expansion |
| else if (fDocumentImpl != null) { |
| |
| // get the default value |
| if (defaultValue != null) { |
| |
| // get element definition node |
| NamedNodeMap elements = ((DocumentTypeImpl)fDocumentType).getElements (); |
| ElementDefinitionImpl elementDef = (ElementDefinitionImpl)elements.getNamedItem (elementName); |
| if (elementDef == null) { |
| elementDef = fDocumentImpl.createElementDefinition (elementName); |
| ((DocumentTypeImpl)fDocumentType).getElements ().setNamedItem (elementDef); |
| } |
| |
| // REVISIT: Check for uniqueness of element name? -Ac |
| |
| // create attribute and set properties |
| boolean nsEnabled = fNamespaceAware; |
| AttrImpl attr; |
| if (nsEnabled) { |
| String namespaceURI = null; |
| // DOM Level 2 wants all namespace declaration attributes |
| // to be bound to "http://www.w3.org/2000/xmlns/" |
| // So as long as the XML parser doesn't do it, it needs to |
| // done here. |
| if (attributeName.startsWith ("xmlns:") || |
| attributeName.equals ("xmlns")) { |
| namespaceURI = NamespaceContext.XMLNS_URI; |
| } |
| attr = (AttrImpl)fDocumentImpl.createAttributeNS (namespaceURI, |
| attributeName); |
| } |
| else { |
| attr = (AttrImpl)fDocumentImpl.createAttribute (attributeName); |
| } |
| attr.setValue (defaultValue.toString ()); |
| attr.setSpecified (false); |
| attr.setIdAttribute ("ID".equals (type)); |
| |
| // add default attribute to element definition |
| if (nsEnabled){ |
| elementDef.getAttributes ().setNamedItemNS (attr); |
| } |
| else { |
| elementDef.getAttributes ().setNamedItem (attr); |
| } |
| } |
| |
| } // if NOT defer-node-expansion |
| |
| } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations) |
| |
| |
| /** |
| * The start of an attribute list. |
| * |
| * @param elementName The name of the element that this attribute |
| * list is associated with. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void startAttlist (String elementName, Augmentations augs) throws XNIException { |
| } // startAttlist(String) |
| |
| |
| /** |
| * The end of an attribute list. |
| * |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void endAttlist (Augmentations augs) throws XNIException { |
| } // endAttlist() |
| |
| |
| // method to create an element node. |
| // subclasses can override this method to create element nodes in other ways. |
| protected Element createElementNode (QName element) { |
| Element el = null; |
| |
| if (fNamespaceAware) { |
| // if we are using xerces DOM implementation, call our |
| // own constructor to reuse the strings we have here. |
| if (fDocumentImpl != null) { |
| el = fDocumentImpl.createElementNS (element.uri, element.rawname, |
| element.localpart); |
| } |
| else { |
| el = fDocument.createElementNS (element.uri, element.rawname); |
| } |
| } |
| else { |
| el = fDocument.createElement (element.rawname); |
| } |
| |
| return el; |
| } |
| |
| // method to create an attribute node. |
| // subclasses can override this method to create attribute nodes in other ways. |
| protected Attr createAttrNode (QName attrQName) { |
| Attr attr = null; |
| |
| if (fNamespaceAware) { |
| if (fDocumentImpl != null) { |
| // if we are using xerces DOM implementation, call our |
| // own constructor to reuse the strings we have here. |
| attr = fDocumentImpl.createAttributeNS (attrQName.uri, |
| attrQName.rawname, |
| attrQName.localpart); |
| } |
| else { |
| attr = fDocument.createAttributeNS (attrQName.uri, |
| attrQName.rawname); |
| } |
| } |
| else { |
| attr = fDocument.createAttribute (attrQName.rawname); |
| } |
| |
| return attr; |
| } |
| |
| /* |
| * When the first characters() call is received, the data is stored in |
| * a new Text node. If right after the first characters() we receive another chunk of data, |
| * the data from the Text node, following the new characters are appended |
| * to the fStringBuffer and the text node data is set to empty. |
| * |
| * This function is called when the state is changed and the |
| * data must be appended to the current node. |
| * |
| * Note: if DOMFilter is set, you must make sure that if Node is skipped, |
| * or removed fFistChunk must be set to true, otherwise some data can be lost. |
| * |
| */ |
| protected void setCharacterData (boolean sawChars){ |
| |
| // handle character data |
| fFirstChunk = sawChars; |
| |
| |
| // if we have data in the buffer we must have created |
| // a text node already. |
| |
| Node child = fCurrentNode.getLastChild (); |
| if (child != null) { |
| if (fStringBuffer.length () > 0) { |
| // REVISIT: should this check be performed? |
| if (child.getNodeType () == Node.TEXT_NODE) { |
| if (fDocumentImpl != null) { |
| ((TextImpl)child).replaceData (fStringBuffer.toString ()); |
| } |
| else { |
| ((Text)child).setData (fStringBuffer.toString ()); |
| } |
| } |
| // reset string buffer |
| fStringBuffer.setLength (0); |
| } |
| |
| if (fDOMFilter !=null && !fInEntityRef) { |
| if ( (child.getNodeType () == Node.TEXT_NODE ) && |
| ((fDOMFilter.getWhatToShow () & NodeFilter.SHOW_TEXT)!= 0) ) { |
| short code = fDOMFilter.acceptNode (child); |
| switch (code) { |
| case LSParserFilter.FILTER_INTERRUPT:{ |
| throw abort; |
| } |
| case LSParserFilter.FILTER_REJECT:{ |
| // fall through to SKIP since Comment has no children. |
| } |
| case LSParserFilter.FILTER_SKIP: { |
| fCurrentNode.removeChild (child); |
| return; |
| } |
| default: { |
| // accept node -- do nothing |
| } |
| } |
| } |
| } // end-if fDOMFilter !=null |
| |
| } // end-if child !=null |
| } |
| |
| |
| /** |
| * @see org.w3c.dom.ls.LSParser#abort() |
| */ |
| public void abort () { |
| throw abort; |
| } |
| |
| |
| } // class AbstractDOMParser |