| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999,2000 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xerces" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, International |
| * Business Machines, Inc., http://www.apache.org. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| package org.apache.xerces.parsers; |
| |
| import java.io.IOException; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| import java.util.StringTokenizer; |
| |
| import org.apache.xerces.dom.TextImpl; |
| import org.apache.xerces.framework.XMLAttrList; |
| import org.apache.xerces.framework.XMLContentSpec; |
| import org.apache.xerces.framework.XMLDocumentHandler; |
| import org.apache.xerces.framework.XMLParser; |
| import org.apache.xerces.readers.XMLEntityHandler; |
| import org.apache.xerces.utils.QName; |
| import org.apache.xerces.utils.StringPool; |
| import org.apache.xerces.validators.common.XMLAttributeDecl; |
| import org.apache.xerces.validators.common.XMLElementDecl; |
| import org.apache.xerces.validators.schema.XUtil; |
| |
| import org.apache.xerces.dom.DeferredDocumentImpl; |
| import org.apache.xerces.dom.DocumentImpl; |
| import org.apache.xerces.dom.DocumentTypeImpl; |
| import org.apache.xerces.dom.NodeImpl; |
| import org.apache.xerces.dom.EntityImpl; |
| import org.apache.xerces.dom.NotationImpl; |
| import org.apache.xerces.dom.ElementDefinitionImpl; |
| import org.apache.xerces.dom.AttrImpl; |
| import org.apache.xerces.dom.TextImpl; |
| import org.apache.xerces.dom.ElementImpl; |
| import org.apache.xerces.dom.EntityImpl; |
| import org.apache.xerces.dom.EntityReferenceImpl; |
| |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Comment; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.DocumentType; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Entity; |
| import org.w3c.dom.EntityReference; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.ProcessingInstruction; |
| import org.w3c.dom.Text; |
| |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXNotRecognizedException; |
| import org.xml.sax.SAXNotSupportedException; |
| |
| /** |
| * DOMParser provides a parser which produces a W3C DOM tree as its output |
| * |
| * |
| * @version $Id$ |
| */ |
| public class DOMParser |
| extends XMLParser |
| implements XMLDocumentHandler |
| { |
| |
| // |
| // Constants |
| // |
| |
| // public |
| |
| /** Default programmatic document class name (org.apache.xerces.dom.DocumentImpl). */ |
| public static final String DEFAULT_DOCUMENT_CLASS_NAME = "org.apache.xerces.dom.DocumentImpl"; |
| |
| /** Default deferred document class name (org.apache.xerces.dom.DeferredDocumentImpl). */ |
| public static final String DEFAULT_DEFERRED_DOCUMENT_CLASS_NAME = "org.apache.xerces.dom.DeferredDocumentImpl"; |
| |
| // debugging |
| |
| /** Set to true to debug attribute list declaration calls. */ |
| private static final boolean DEBUG_ATTLIST_DECL = false; |
| |
| // features and properties |
| |
| /** Features recognized by this parser. */ |
| private static final String RECOGNIZED_FEATURES[] = { |
| // SAX2 core features |
| // Xerces features |
| "http://apache.org/xml/features/dom/defer-node-expansion", |
| "http://apache.org/xml/features/dom/create-entity-ref-nodes", |
| "http://apache.org/xml/features/dom/include-ignorable-whitespace", |
| // Experimental features |
| "http://apache.org/xml/features/domx/grammar-access", |
| }; |
| |
| /** Properties recognized by this parser. */ |
| private static final String RECOGNIZED_PROPERTIES[] = { |
| // SAX2 core properties |
| // Xerces properties |
| "http://apache.org/xml/properties/dom/document-class-name", |
| "http://apache.org/xml/properties/dom/current-element-node", |
| }; |
| |
| // |
| // Data |
| // |
| |
| // common data |
| |
| protected Document fDocument; |
| |
| // deferred expansion data |
| |
| protected DeferredDocumentImpl fDeferredDocumentImpl; |
| protected int fDocumentIndex; |
| protected int fDocumentTypeIndex; |
| protected int fCurrentNodeIndex; |
| |
| // full expansion data |
| |
| protected DocumentImpl fDocumentImpl; |
| protected DocumentType fDocumentType; |
| protected Node fCurrentElementNode; |
| |
| // state |
| |
| protected boolean fInDTD; |
| protected boolean fWithinElement; |
| protected boolean fInCDATA; |
| |
| // features |
| private boolean fGrammarAccess; |
| |
| // properties |
| |
| // REVISIT: Even though these have setters and getters, should they |
| // be protected visibility? -Ac |
| private String fDocumentClassName; |
| private boolean fDeferNodeExpansion; |
| private boolean fCreateEntityReferenceNodes; |
| private boolean fIncludeIgnorableWhitespace; |
| |
| // built-in entities |
| |
| protected int fAmpIndex; |
| protected int fLtIndex; |
| protected int fGtIndex; |
| protected int fAposIndex; |
| protected int fQuotIndex; |
| |
| private boolean fSeenRootElement; |
| |
| private boolean fStringPoolInUse; |
| |
| private XMLAttrList fAttrList; |
| |
| // |
| // Constructors |
| // |
| |
| /** Default constructor. */ |
| public DOMParser() { |
| |
| initHandlers(false, this, this); |
| |
| // setup parser state |
| init(); |
| |
| // set default values |
| try { |
| setDocumentClassName(DEFAULT_DOCUMENT_CLASS_NAME); |
| setCreateEntityReferenceNodes(true); |
| setDeferNodeExpansion(true); |
| setIncludeIgnorableWhitespace(true); |
| } catch (SAXException e) { |
| throw new RuntimeException("PAR001 Fatal error constructing DOMParser."); |
| } |
| |
| } // <init>() |
| |
| // |
| // Public methods |
| // |
| |
| // document |
| |
| /** Returns the document. */ |
| public Document getDocument() { |
| if (fDocumentImpl != null) { |
| fDocumentImpl.setErrorChecking(true); |
| } |
| return fDocument; |
| } |
| |
| // features and properties |
| |
| /** |
| * Returns a list of features that this parser recognizes. |
| * This method will never return null; if no features are |
| * recognized, this method will return a zero length array. |
| * |
| * @see #isFeatureRecognized |
| * @see #setFeature |
| * @see #getFeature |
| */ |
| public String[] getFeaturesRecognized() { |
| |
| // get features that super/this recognizes |
| String superRecognized[] = super.getFeaturesRecognized(); |
| String thisRecognized[] = RECOGNIZED_FEATURES; |
| |
| // is one or the other the empty set? |
| int thisLength = thisRecognized.length; |
| if (thisLength == 0) { |
| return superRecognized; |
| } |
| int superLength = superRecognized.length; |
| if (superLength == 0) { |
| return thisRecognized; |
| } |
| |
| // combine the two lists and return |
| String recognized[] = new String[superLength + thisLength]; |
| System.arraycopy(superRecognized, 0, recognized, 0, superLength); |
| System.arraycopy(thisRecognized, 0, recognized, superLength, thisLength); |
| return recognized; |
| |
| } // getFeaturesRecognized():String[] |
| |
| /** |
| * Returns a list of properties that this parser recognizes. |
| * This method will never return null; if no properties are |
| * recognized, this method will return a zero length array. |
| * |
| * @see #isPropertyRecognized |
| * @see #setProperty |
| * @see #getProperty |
| */ |
| public String[] getPropertiesRecognized() { |
| |
| // get properties that super/this recognizes |
| String superRecognized[] = super.getPropertiesRecognized(); |
| String thisRecognized[] = RECOGNIZED_PROPERTIES; |
| |
| // is one or the other the empty set? |
| int thisLength = thisRecognized.length; |
| if (thisLength == 0) { |
| return superRecognized; |
| } |
| int superLength = superRecognized.length; |
| if (superLength == 0) { |
| return thisRecognized; |
| } |
| |
| // combine the two lists and return |
| String recognized[] = new String[superLength + thisLength]; |
| System.arraycopy(superRecognized, 0, recognized, 0, superLength); |
| System.arraycopy(thisRecognized, 0, recognized, superLength, thisLength); |
| return recognized; |
| |
| } |
| |
| // resetting |
| |
| /** Resets the parser. */ |
| public void reset() throws Exception { |
| if (fStringPoolInUse) { |
| // we can't reuse the string pool, let's create another one |
| fStringPool = new StringPool(); |
| fStringPoolInUse = false; |
| } |
| super.reset(); |
| init(); |
| } |
| |
| /** Resets or copies the parser. */ |
| public void resetOrCopy() throws Exception { |
| super.resetOrCopy(); |
| init(); |
| } |
| |
| // |
| // Protected methods |
| // |
| |
| // initialization |
| |
| /** |
| * Initializes the parser to a pre-parse state. This method is |
| * called between calls to <code>parse()</code>. |
| */ |
| protected void init() { |
| |
| // init common |
| fDocument = null; |
| |
| // init deferred expansion |
| fDeferredDocumentImpl = null; |
| fDocumentIndex = -1; |
| fDocumentTypeIndex = -1; |
| fCurrentNodeIndex = -1; |
| |
| // init full expansion |
| fDocumentImpl = null; |
| fDocumentType = null; |
| fCurrentElementNode = null; |
| |
| // state |
| fInDTD = false; |
| fWithinElement = false; |
| fInCDATA = false; |
| |
| // built-in entities |
| fAmpIndex = fStringPool.addSymbol("amp"); |
| fLtIndex = fStringPool.addSymbol("lt"); |
| fGtIndex = fStringPool.addSymbol("gt"); |
| fAposIndex = fStringPool.addSymbol("apos"); |
| fQuotIndex = fStringPool.addSymbol("quot"); |
| |
| fSeenRootElement = false; |
| fStringPoolInUse = false; |
| |
| fAttrList = new XMLAttrList(fStringPool); |
| |
| } // init() |
| |
| // features |
| |
| /** |
| * This method sets whether the expansion of the nodes in the default |
| * DOM implementation are deferred. |
| * |
| * @see #getDeferNodeExpansion |
| * @see #setDocumentClassName |
| */ |
| protected void setDeferNodeExpansion(boolean deferNodeExpansion) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| fDeferNodeExpansion = deferNodeExpansion; |
| } |
| |
| /** |
| * Returns true if the expansion of the nodes in the default DOM |
| * implementation are deferred. |
| * |
| * @see #setDeferNodeExpansion |
| */ |
| protected boolean getDeferNodeExpansion() |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| return fDeferNodeExpansion; |
| } |
| |
| /** |
| * This feature determines whether entity references within |
| * the document are included in the document tree as |
| * EntityReference nodes. |
| * <p> |
| * Note: The children of the entity reference are always |
| * added to the document. This feature only affects |
| * whether an EntityReference node is also included |
| * as the parent of the entity reference children. |
| * |
| * @param create True to create entity reference nodes; false |
| * to only insert the entity reference children. |
| * |
| * @see #getCreateEntityReferenceNodes |
| */ |
| protected void setCreateEntityReferenceNodes(boolean create) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| fCreateEntityReferenceNodes = create; |
| } |
| |
| /** |
| * Returns true if entity references within the document are |
| * included in the document tree as EntityReference nodes. |
| * |
| * @see #setCreateEntityReferenceNodes |
| */ |
| public boolean getCreateEntityReferenceNodes() |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| return fCreateEntityReferenceNodes; |
| } |
| |
| /** |
| * This feature determines whether text nodes that can be |
| * considered "ignorable whitespace" are included in the DOM |
| * tree. |
| * <p> |
| * Note: The only way that the parser can determine if text |
| * is ignorable is by reading the associated grammar |
| * and having a content model for the document. When |
| * ignorable whitespace text nodes *are* included in |
| * the DOM tree, they will be flagged as ignorable. |
| * The ignorable flag can be queried by calling the |
| * TextImpl#isIgnorableWhitespace():boolean method. |
| * |
| * @param include True to include ignorable whitespace text nodes; |
| * false to not include ignorable whitespace text |
| * nodes. |
| * |
| * @see #getIncludeIgnorableWhitespace |
| */ |
| public void setIncludeIgnorableWhitespace(boolean include) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| fIncludeIgnorableWhitespace = include; |
| } |
| |
| /** |
| * Returns true if ignorable whitespace text nodes are included |
| * in the DOM tree. |
| * |
| * @see #setIncludeIgnorableWhitespace |
| */ |
| public boolean getIncludeIgnorableWhitespace() |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| return fIncludeIgnorableWhitespace; |
| } |
| |
| // properties |
| |
| /** |
| * 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 #setDeferNodeExpansion |
| * @see #DEFAULT_DOCUMENT_CLASS_NAME |
| */ |
| protected void setDocumentClassName(String documentClassName) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| |
| // normalize class name |
| if (documentClassName == null) { |
| documentClassName = DEFAULT_DOCUMENT_CLASS_NAME; |
| } |
| |
| // verify that this class exists and is of the right type |
| try { |
| Class _class = Class.forName(documentClassName); |
| //if (!_class.isAssignableFrom(Document.class)) { |
| if (!Document.class.isAssignableFrom(_class)) { |
| throw new IllegalArgumentException("PAR002 Class, \""+documentClassName+"\", is not of type org.w3c.dom.Document."+"\n"+documentClassName); |
| } |
| } |
| catch (ClassNotFoundException e) { |
| throw new IllegalArgumentException("PAR003 Class, \""+documentClassName+"\", not found."+"\n"+documentClassName); |
| } |
| |
| // set document class name |
| fDocumentClassName = documentClassName; |
| if (!documentClassName.equals(DEFAULT_DOCUMENT_CLASS_NAME)) { |
| setDeferNodeExpansion(false); |
| } |
| |
| } // setDocumentClassName(String) |
| |
| /** |
| * Returns the fully qualified class name of the document factory |
| * used when constructing the DOM tree. |
| * |
| * @see #setDocumentClassName |
| */ |
| protected String getDocumentClassName() |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| return fDocumentClassName; |
| } |
| |
| /** |
| * Returns the current element node. |
| * <p> |
| * Note: This method is not supported when the "deferNodeExpansion" |
| * property is set to true and the document factory is set to |
| * the default factory. |
| */ |
| protected Element getCurrentElementNode() |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| |
| if (fCurrentElementNode != null && |
| fCurrentElementNode.getNodeType() == Node.ELEMENT_NODE) { |
| return (Element)fCurrentElementNode; |
| } |
| return null; |
| |
| } // getCurrentElementNode():Element |
| |
| // |
| // Configurable methods |
| // |
| |
| /** |
| * 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. |
| */ |
| public void setFeature(String featureId, boolean state) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| |
| // |
| // SAX2 core features |
| // |
| |
| if (featureId.startsWith(SAX2_FEATURES_PREFIX)) { |
| // |
| // No additional SAX properties defined for DOMParser. |
| // Pass request off to XMLParser for the common cases. |
| // |
| } |
| |
| // |
| // Xerces features |
| // |
| |
| else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) { |
| String feature = featureId.substring(XERCES_FEATURES_PREFIX.length()); |
| // |
| // http://apache.org/xml/features/dom/defer-node-expansion |
| // Allows the document tree returned by getDocument() |
| // to be constructed lazily. In other words, the DOM |
| // nodes are constructed as the tree is traversed. |
| // This allows the document to be returned sooner with |
| // the expense of holding all of the blocks of character |
| // data held in memory. Then again, lots of DOM nodes |
| // use a lot of memory as well. |
| // |
| if (feature.equals("dom/defer-node-expansion")) { |
| if (fParseInProgress) { |
| throw new SAXNotSupportedException("PAR004 Cannot setFeature("+featureId + "): parse is in progress."+"\n"+featureId); |
| } |
| setDeferNodeExpansion(state); |
| return; |
| } |
| // |
| // http://apache.org/xml/features/dom/create-entity-ref-nodes |
| // This feature determines whether entity references within |
| // the document are included in the document tree as |
| // EntityReference nodes. |
| // Note: The children of the entity reference are always |
| // added to the document. This feature only affects |
| // whether an EntityReference node is also included |
| // as the parent of the entity reference children. |
| // |
| if (feature.equals("dom/create-entity-ref-nodes")) { |
| setCreateEntityReferenceNodes(state); |
| return; |
| } |
| |
| // |
| // http://apache.org/xml/features/dom/include-ignorable-whitespace |
| // This feature determines whether text nodes that can be |
| // considered "ignorable whitespace" are included in the DOM |
| // tree. |
| // Note: The only way that the parser can determine if text |
| // is ignorable is by reading the associated grammar |
| // and having a content model for the document. When |
| // ignorable whitespace text nodes *are* included in |
| // the DOM tree, they will be flagged as ignorable. |
| // The ignorable flag can be queried by calling the |
| // TextImpl#isIgnorableWhitespace():boolean method. |
| // |
| if (feature.equals("dom/include-ignorable-whitespace")) { |
| setIncludeIgnorableWhitespace(state); |
| return; |
| } |
| |
| // |
| // Experimental features |
| // |
| |
| // |
| // http://apache.org/xml/features/domx/grammar-access |
| // Allows grammar access in the DOM tree. Currently, this |
| // means that there is an XML Schema document tree as a |
| // child of the Doctype node. |
| // |
| if (feature.equals("domx/grammar-access")) { |
| fGrammarAccess = state; |
| return; |
| } |
| |
| // |
| // Pass request off to XMLParser for the common cases. |
| // |
| } |
| |
| // |
| // Pass request off to XMLParser for the common cases. |
| // |
| super.setFeature(featureId, state); |
| |
| } // setFeature(String,boolean) |
| |
| /** |
| * 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 SAXNotRecognizedException If the requested feature is |
| * not known. |
| */ |
| public boolean getFeature(String featureId) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| |
| // |
| // SAX2 core features |
| // |
| |
| if (featureId.startsWith(SAX2_FEATURES_PREFIX)) { |
| // |
| // No additional SAX properties defined for DOMParser. |
| // Pass request off to XMLParser for the common cases. |
| // |
| } |
| |
| // |
| // Xerces features |
| // |
| |
| else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) { |
| String feature = featureId.substring(XERCES_FEATURES_PREFIX.length()); |
| // |
| // http://apache.org/xml/features/dom/defer-node-expansion |
| // Allows the document tree returned by getDocument() |
| // to be constructed lazily. In other words, the DOM |
| // nodes are constructed as the tree is traversed. |
| // This allows the document to be returned sooner with |
| // the expense of holding all of the blocks of character |
| // data held in memory. Then again, lots of DOM nodes |
| // use a lot of memory as well. |
| // |
| if (feature.equals("dom/defer-node-expansion")) { |
| return getDeferNodeExpansion(); |
| } |
| // |
| // http://apache.org/xml/features/dom/create-entity-ref-nodes |
| // This feature determines whether entity references within |
| // the document are included in the document tree as |
| // EntityReference nodes. |
| // Note: The children of the entity reference are always |
| // added to the document. This feature only affects |
| // whether an EntityReference node is also included |
| // as the parent of the entity reference children. |
| // |
| else if (feature.equals("dom/create-entity-ref-nodes")) { |
| return getCreateEntityReferenceNodes(); |
| } |
| |
| // |
| // http://apache.org/xml/features/dom/include-ignorable-whitespace |
| // This feature determines whether text nodes that can be |
| // considered "ignorable whitespace" are included in the DOM |
| // tree. |
| // Note: The only way that the parser can determine if text |
| // is ignorable is by reading the associated grammar |
| // and having a content model for the document. When |
| // ignorable whitespace text nodes *are* included in |
| // the DOM tree, they will be flagged as ignorable. |
| // The ignorable flag can be queried by calling the |
| // TextImpl#isIgnorableWhitespace():boolean method. |
| // |
| if (feature.equals("dom/include-ignorable-whitespace")) { |
| return getIncludeIgnorableWhitespace(); |
| } |
| |
| // |
| // Experimental features |
| // |
| |
| // |
| // http://apache.org/xml/features/domx/grammar-access |
| // Allows grammar access in the DOM tree. Currently, this |
| // means that there is an XML Schema document tree as a |
| // child of the Doctype node. |
| // |
| if (feature.equals("domx/grammar-access")) { |
| return fGrammarAccess; |
| } |
| |
| // |
| // Pass request off to XMLParser for the common cases. |
| // |
| } |
| |
| // |
| // Pass request off to XMLParser for the common cases. |
| // |
| return super.getFeature(featureId); |
| |
| } // getFeature(String):boolean |
| |
| /** |
| * 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 Object 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. |
| */ |
| public void setProperty(String propertyId, Object value) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| |
| // |
| // Xerces properties |
| // |
| |
| if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) { |
| String property = propertyId.substring(XERCES_PROPERTIES_PREFIX.length()); |
| // |
| // http://apache.org/xml/properties/dom/current-element-node |
| // Returns the current element node as the DOM Parser is |
| // parsing. This property is useful for determining the |
| // relative location of the document when an error is |
| // encountered. Note that this feature does *not* work |
| // when the http://apache.org/xml/features/dom/defer-node-expansion |
| // is set to true. |
| // |
| if (property.equals("dom/current-element-node")) { |
| throw new SAXNotSupportedException("PAR005 Property, \""+propertyId+"\" is read-only.\n"+propertyId); |
| } |
| // |
| // http://apache.org/xml/properties/dom/document-class-name |
| // This property can be used to set/query the name of the |
| // document factory. |
| // |
| else if (property.equals("dom/document-class-name")) { |
| if (value != null && !(value instanceof String)) { |
| throw new SAXNotSupportedException("PAR006 Property value must be of type java.lang.String."); |
| } |
| setDocumentClassName((String)value); |
| return; |
| } |
| } |
| |
| // |
| // Pass request off to XMLParser for the common cases. |
| // |
| super.setProperty(propertyId, value); |
| |
| } // setProperty(String,Object) |
| |
| /** |
| * 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 SAXNotRecognizedException If the requested property is |
| * not known. |
| * |
| * @see Configurable#getProperty |
| */ |
| public Object getProperty(String propertyId) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| |
| // |
| // Xerces properties |
| // |
| |
| if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) { |
| String property = propertyId.substring(XERCES_PROPERTIES_PREFIX.length()); |
| // |
| // http://apache.org/xml/properties/dom/current-element-node |
| // Returns the current element node as the DOM Parser is |
| // parsing. This property is useful for determining the |
| // relative location of the document when an error is |
| // encountered. Note that this feature does *not* work |
| // when the http://apache.org/xml/features/dom/defer-node-expansion |
| // is set to true. |
| // |
| if (property.equals("dom/current-element-node")) { |
| boolean throwException = false; |
| try { |
| throwException = getFeature(XERCES_FEATURES_PREFIX+"dom/defer-node-expansion"); |
| } |
| catch (SAXNotSupportedException e) { |
| // ignore |
| } |
| catch (SAXNotRecognizedException e) { |
| // ignore |
| } |
| if (throwException) { |
| throw new SAXNotSupportedException("PAR007 Current element node cannot be queried when node expansion is deferred."); |
| } |
| return getCurrentElementNode(); |
| } |
| // |
| // http://apache.org/xml/properties/dom/document-class-name |
| // This property can be used to set/query the name of the |
| // document factory. |
| // |
| else if (property.equals("dom/document-class-name")) { |
| return getDocumentClassName(); |
| } |
| } |
| |
| // |
| // Pass request off to XMLParser for the common cases. |
| // |
| return super.getProperty(propertyId); |
| |
| } // getProperty(String):Object |
| |
| // |
| // XMLParser methods |
| // |
| |
| /** Start document. */ |
| public void startDocument() { |
| |
| // deferred expansion |
| String documentClassName = null; |
| try { |
| documentClassName = getDocumentClassName(); |
| } catch (SAXException e) { |
| throw new RuntimeException("PAR008 Fatal error getting document factory."); |
| } |
| boolean deferNodeExpansion = true; |
| try { |
| deferNodeExpansion = getDeferNodeExpansion(); |
| } catch (SAXException e) { |
| throw new RuntimeException("PAR009 Fatal error reading expansion mode."); |
| } |
| try { |
| boolean isDocumentImpl = fDocumentClassName.equals(DEFAULT_DOCUMENT_CLASS_NAME); |
| boolean isDeferredImpl = fDocumentClassName.equals(DEFAULT_DEFERRED_DOCUMENT_CLASS_NAME); |
| if (deferNodeExpansion && (isDocumentImpl || isDeferredImpl)) { |
| boolean nsEnabled = false; |
| try { nsEnabled = getNamespaces(); } |
| catch (SAXException s) {} |
| fDeferredDocumentImpl = new DeferredDocumentImpl(fStringPool, nsEnabled, fGrammarAccess); |
| fStringPoolInUse = true; |
| fDocument = fDeferredDocumentImpl; |
| fDocumentIndex = fDeferredDocumentImpl.createDocument(); |
| fCurrentNodeIndex = fDocumentIndex; |
| } |
| |
| // full expansion |
| else { |
| Class docClass = Class.forName(documentClassName); |
| Class defaultDocClass = Class.forName(DEFAULT_DOCUMENT_CLASS_NAME); |
| if (isDocumentImpl) { |
| fDocument = new DocumentImpl(fGrammarAccess); |
| } |
| else { |
| try { |
| Class documentClass = Class.forName(documentClassName); |
| fDocument = (Document)documentClass.newInstance(); |
| } |
| catch (Exception e) { |
| // REVISIT: We've already checked the type of the factory |
| // in the setDocumentClassName() method. The only |
| // exception that can occur here is if the class |
| // doesn't have a zero-arg constructor. -Ac |
| } |
| } |
| if (docClass.isAssignableFrom(defaultDocClass)) { |
| fDocumentImpl = (DocumentImpl)fDocument; |
| fDocumentImpl.setErrorChecking(false); |
| } |
| |
| fCurrentElementNode = fDocument; |
| } |
| } |
| catch (ClassNotFoundException e) { |
| // REVISIT: Localize this message. |
| throw new RuntimeException(documentClassName); |
| } |
| |
| } // startDocument() |
| |
| /** End document. */ |
| public void endDocument() throws Exception {} |
| |
| /** XML declaration. */ |
| public void xmlDecl(int versionIndex, int encodingIndex, int standaloneIndex) throws Exception { |
| |
| // release strings |
| fStringPool.releaseString(versionIndex); |
| fStringPool.releaseString(encodingIndex); |
| fStringPool.releaseString(standaloneIndex); |
| } |
| |
| /** Text declaration. */ |
| public void textDecl(int versionIndex, int encodingIndex) throws Exception { |
| |
| // release strings |
| fStringPool.releaseString(versionIndex); |
| fStringPool.releaseString(encodingIndex); |
| } |
| |
| /** Report the start of the scope of a namespace declaration. */ |
| public void startNamespaceDeclScope(int prefix, int uri) throws Exception {} |
| |
| /** Report the end of the scope of a namespace declaration. */ |
| public void endNamespaceDeclScope(int prefix) throws Exception {} |
| |
| |
| |
| /** Start element. */ |
| public void startElement(QName elementQName, |
| XMLAttrList xmlAttrList, int attrListIndex) |
| throws Exception { |
| |
| // deferred expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| int element = |
| fDeferredDocumentImpl.createElement(elementQName.rawname, |
| elementQName.uri, |
| xmlAttrList, |
| attrListIndex); |
| fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, element); |
| fCurrentNodeIndex = element; |
| fWithinElement = true; |
| |
| // identifier registration |
| int index = xmlAttrList.getFirstAttr(attrListIndex); |
| while (index != -1) { |
| if (xmlAttrList.getAttType(index) == fStringPool.addSymbol("ID")) { |
| int nameIndex = xmlAttrList.getAttValue(index); |
| fDeferredDocumentImpl.putIdentifier(nameIndex, element); |
| } |
| index = xmlAttrList.getNextAttr(index); |
| } |
| |
| // copy schema grammar, if needed |
| if (!fSeenRootElement) { |
| fSeenRootElement = true; |
| if (fDocumentTypeIndex == -1) { |
| fDocumentTypeIndex = fDeferredDocumentImpl.createDocumentType(elementQName.rawname, -1, -1); |
| fDeferredDocumentImpl.appendChild(0, fDocumentTypeIndex); |
| } |
| if (fGrammarAccess) { |
| // REVISIT: How do we know which grammar is in use? |
| //Document schemaDocument = fValidator.getSchemaDocument(); |
| int size = fGrammarResolver.size(); |
| if (size > 0) { |
| Enumeration schemas = fGrammarResolver.nameSpaceKeys(); |
| Document schemaDocument = fGrammarResolver.getGrammar((String)schemas.nextElement()).getGrammarDocument(); |
| if (schemaDocument != null) { |
| Element schema = schemaDocument.getDocumentElement(); |
| copyInto(schema, fDocumentTypeIndex); |
| } |
| } |
| } |
| } |
| } |
| |
| // full expansion |
| else { |
| |
| boolean nsEnabled = false; |
| try { nsEnabled = getNamespaces(); } |
| catch (SAXException s) {} |
| |
| String elementName = fStringPool.toString(elementQName.rawname); |
| Element e; |
| if (nsEnabled) { |
| e = fDocument.createElementNS( |
| // REVISIT: Make sure uri is filled in by caller. |
| fStringPool.toString(elementQName.uri), |
| fStringPool.toString(elementQName.localpart) |
| ); |
| } else { |
| e = fDocument.createElement(elementName); |
| } |
| int attrHandle = xmlAttrList.getFirstAttr(attrListIndex); |
| while (attrHandle != -1) { |
| int attName = xmlAttrList.getAttrName(attrHandle); |
| String attrName = fStringPool.toString(attName); |
| String attrValue = |
| fStringPool.toString(xmlAttrList.getAttValue(attrHandle)); |
| if (nsEnabled) { |
| int nsURIIndex = xmlAttrList.getAttrURI(attrHandle); |
| String namespaceURI = fStringPool.toString(nsURIIndex); |
| // 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. |
| int prefixIndex = xmlAttrList.getAttrPrefix(attrHandle); |
| String prefix = fStringPool.toString(prefixIndex); |
| if (namespaceURI == null) { |
| if (prefix != null) { |
| if (prefix.equals("xmlns")) { |
| namespaceURI = "http://www.w3.org/2000/xmlns/"; |
| } |
| } else if (attrName.equals("xmlns")) { |
| namespaceURI = "http://www.w3.org/2000/xmlns/"; |
| } |
| } |
| e.setAttributeNS(namespaceURI, attrName, attrValue); |
| } else { |
| e.setAttribute(attrName, attrValue); |
| } |
| if (!xmlAttrList.isSpecified(attrHandle)) { |
| ((AttrImpl)e.getAttributeNode(attrName)) |
| .setSpecified(false); |
| } |
| attrHandle = xmlAttrList.getNextAttr(attrHandle); |
| } |
| fCurrentElementNode.appendChild(e); |
| fCurrentElementNode = e; |
| fWithinElement = true; |
| |
| // identifier registration |
| if (fDocumentImpl != null) { |
| int index = xmlAttrList.getFirstAttr(attrListIndex); |
| while (index != -1) { |
| if (xmlAttrList.getAttType(index) == fStringPool.addSymbol("ID")) { |
| String name = fStringPool.toString(xmlAttrList.getAttValue(index)); |
| fDocumentImpl.putIdentifier(name, e); |
| } |
| index = xmlAttrList.getNextAttr(index); |
| } |
| } |
| |
| xmlAttrList.releaseAttrList(attrListIndex); |
| |
| // copy schema grammar, if needed |
| if (!fSeenRootElement) { |
| fSeenRootElement = true; |
| if (fDocumentImpl != null |
| && fGrammarAccess && fGrammarResolver.size() > 0) { |
| if (fDocumentType == null) { |
| String rootName = elementName; |
| String systemId = ""; // REVISIT: How do we get this value? -Ac |
| String publicId = ""; // REVISIT: How do we get this value? -Ac |
| fDocumentType = fDocumentImpl.createDocumentType(rootName, publicId, systemId); |
| fDocument.appendChild(fDocumentType); |
| // REVISIT: We could use introspection to get the |
| // DOMImplementation#createDocumentType method |
| // for DOM Level 2 implementations. The only |
| // problem is that the owner document for the |
| // node created is null. How does it get set |
| // for document when appended? A cursory look |
| // at the DOM Level 2 CR didn't yield any |
| // information. -Ac |
| } |
| Enumeration schemas = fGrammarResolver.nameSpaceKeys(); |
| Document schemaDocument = fGrammarResolver.getGrammar((String)schemas.nextElement()).getGrammarDocument(); |
| if (schemaDocument != null) { |
| Element schema = schemaDocument.getDocumentElement(); |
| XUtil.copyInto(schema, fDocumentType); |
| } |
| } |
| } |
| } |
| |
| } // startElement(QName,XMLAttrList,int) |
| |
| /** End element. */ |
| public void endElement(QName elementQName) |
| throws Exception { |
| |
| // deferred node expansion |
| if (fDeferredDocumentImpl != null) { |
| fCurrentNodeIndex = fDeferredDocumentImpl.getParentNode(fCurrentNodeIndex, false); |
| fWithinElement = false; |
| } |
| |
| // full node expansion |
| else { |
| fCurrentElementNode = fCurrentElementNode.getParentNode(); |
| fWithinElement = false; |
| if (fDocumentImpl != null) { |
| ((NodeImpl)fCurrentElementNode).reduceWaste(); |
| } |
| } |
| |
| } // endElement(QName) |
| |
| /** Characters. */ |
| public void characters(int dataIndex) |
| throws Exception { |
| |
| // deferred node expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| int text; |
| |
| if (fInCDATA) { |
| text = fDeferredDocumentImpl.createCDATASection(dataIndex, false); |
| } else { |
| // The Text normalization is taken care of within the Text Node |
| // in the DEFERRED case. |
| text = fDeferredDocumentImpl.createTextNode(dataIndex, false); |
| } |
| fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, text); |
| } |
| |
| // full node expansion |
| else { |
| |
| Text text; |
| |
| if (fInCDATA) { |
| text = fDocument.createCDATASection(fStringPool.orphanString(dataIndex)); |
| } |
| else { |
| |
| if (fWithinElement && fCurrentElementNode.getNodeType() == Node.ELEMENT_NODE) { |
| Node lastChild = fCurrentElementNode.getLastChild(); |
| if (lastChild != null |
| && lastChild.getNodeType() == Node.TEXT_NODE) { |
| // Normalization of Text Nodes - append rather than create. |
| ((Text)lastChild).appendData(fStringPool.orphanString(dataIndex)); |
| return; |
| } |
| } |
| text = fDocument.createTextNode(fStringPool.orphanString(dataIndex)); |
| } |
| |
| fCurrentElementNode.appendChild(text); |
| |
| } |
| |
| } // characters(int) |
| |
| /** Ignorable whitespace. */ |
| public void ignorableWhitespace(int dataIndex) throws Exception { |
| |
| // ignore the whitespace |
| if (!fIncludeIgnorableWhitespace) { |
| fStringPool.orphanString(dataIndex); |
| return; |
| } |
| |
| // deferred node expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| int text; |
| |
| if (fInCDATA) { |
| text = fDeferredDocumentImpl.createCDATASection(dataIndex, true); |
| } else { |
| // The Text normalization is taken care of within the Text Node |
| // in the DEFERRED case. |
| text = fDeferredDocumentImpl.createTextNode(dataIndex, true); |
| } |
| fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, text); |
| } |
| |
| // full node expansion |
| else { |
| |
| Text text; |
| |
| if (fInCDATA) { |
| text = fDocument.createCDATASection(fStringPool.orphanString(dataIndex)); |
| } |
| else { |
| |
| if (fWithinElement && fCurrentElementNode.getNodeType() == Node.ELEMENT_NODE) { |
| Node lastChild = fCurrentElementNode.getLastChild(); |
| if (lastChild != null |
| && lastChild.getNodeType() == Node.TEXT_NODE) { |
| // Normalization of Text Nodes - append rather than create. |
| ((Text)lastChild).appendData(fStringPool.orphanString(dataIndex)); |
| return; |
| } |
| } |
| text = fDocument.createTextNode(fStringPool.orphanString(dataIndex)); |
| } |
| |
| if (fDocumentImpl != null) { |
| ((TextImpl)text).setIgnorableWhitespace(true); |
| } |
| |
| fCurrentElementNode.appendChild(text); |
| |
| } |
| |
| } // ignorableWhitespace(int) |
| |
| /** Processing instruction. */ |
| public void processingInstruction(int targetIndex, int dataIndex) |
| throws Exception { |
| |
| // deferred node expansion |
| if (fDeferredDocumentImpl != null) { |
| int pi = fDeferredDocumentImpl.createProcessingInstruction(targetIndex, dataIndex); |
| fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, pi); |
| } |
| |
| // full node expansion |
| else { |
| String target = fStringPool.orphanString(targetIndex); |
| String data = fStringPool.orphanString(dataIndex); |
| ProcessingInstruction pi = fDocument.createProcessingInstruction(target, data); |
| fCurrentElementNode.appendChild(pi); |
| } |
| |
| } // processingInstruction(int,int) |
| |
| /** Comment. */ |
| public void comment(int dataIndex) throws Exception { |
| |
| if (fInDTD && !fGrammarAccess) { |
| fStringPool.orphanString(dataIndex); |
| } |
| else { |
| // deferred node expansion |
| if (fDeferredDocumentImpl != null) { |
| int comment = fDeferredDocumentImpl.createComment(dataIndex); |
| fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, comment); |
| } |
| |
| // full node expansion |
| else { |
| Comment comment = fDocument.createComment(fStringPool.orphanString(dataIndex)); |
| fCurrentElementNode.appendChild(comment); |
| } |
| } |
| |
| } // comment(int) |
| |
| /** Not called. */ |
| public void characters(char ch[], int start, int length) throws Exception {} |
| |
| /** Not called. */ |
| public void ignorableWhitespace(char ch[], int start, int length) throws Exception {} |
| |
| // |
| // XMLDocumentScanner methods |
| // |
| |
| /** Start CDATA section. */ |
| public void startCDATA() throws Exception { |
| fInCDATA = true; |
| } |
| |
| /** End CDATA section. */ |
| public void endCDATA() throws Exception { |
| fInCDATA = false; |
| } |
| |
| // |
| // XMLEntityHandler methods |
| // |
| |
| /** Start entity reference. */ |
| public void startEntityReference(int entityName, int entityType, |
| int entityContext) throws Exception { |
| |
| // are we ignoring entity reference nodes? |
| if (!fCreateEntityReferenceNodes) { |
| return; |
| } |
| |
| // ignore built-in entities |
| if (entityName == fAmpIndex || |
| entityName == fGtIndex || |
| entityName == fLtIndex || |
| entityName == fAposIndex || |
| entityName == fQuotIndex) { |
| return; |
| } |
| |
| // we only support one context for entity references right now... |
| if (entityContext != XMLEntityHandler.ENTITYREF_IN_CONTENT) { |
| return; |
| } |
| |
| // deferred node expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| int entityRefIndex = fDeferredDocumentImpl.createEntityReference(entityName); |
| fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, entityRefIndex); |
| |
| fCurrentNodeIndex = entityRefIndex; |
| } |
| |
| // full node expansion |
| else { |
| |
| EntityReference er = |
| fDocument.createEntityReference(fStringPool.toString(entityName)); |
| |
| fCurrentElementNode.appendChild(er); |
| fCurrentElementNode = er; |
| try { |
| EntityReferenceImpl xer = (EntityReferenceImpl) er; |
| xer.setReadOnly(false, false); |
| } catch (Exception e) { |
| // we aren't building against Xerces - do nothing |
| } |
| } |
| |
| } // startEntityReference(int,int,int) |
| |
| /** End entity reference. */ |
| public void endEntityReference(int entityName, int entityType, |
| int entityContext) throws Exception { |
| |
| // are we ignoring entity reference nodes? |
| if (!fCreateEntityReferenceNodes) { |
| return; |
| } |
| |
| // ignore built-in entities |
| if (entityName == fAmpIndex || |
| entityName == fGtIndex || |
| entityName == fLtIndex || |
| entityName == fAposIndex || |
| entityName == fQuotIndex) { |
| return; |
| } |
| |
| // we only support one context for entity references right now... |
| if (entityContext != XMLEntityHandler.ENTITYREF_IN_CONTENT) { |
| return; |
| } |
| |
| // deferred node expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| String name = fStringPool.toString(entityName); |
| |
| int erChild = fCurrentNodeIndex; |
| fCurrentNodeIndex = fDeferredDocumentImpl.getParentNode(erChild, false); |
| |
| // should never be true - we should not return here. |
| if (fDeferredDocumentImpl.getNodeType(erChild, false) != Node.ENTITY_REFERENCE_NODE) return; |
| |
| erChild = fDeferredDocumentImpl.getLastChild(erChild, false); // first Child of EntityReference |
| |
| if (fDocumentTypeIndex != -1) { |
| // find Entity decl for this EntityReference. |
| int entityDecl = fDeferredDocumentImpl.getLastChild(fDocumentTypeIndex, false); |
| while (entityDecl != -1) { |
| if (fDeferredDocumentImpl.getNodeType(entityDecl, false) == Node.ENTITY_NODE |
| && fDeferredDocumentImpl.getNodeNameString(entityDecl, false).equals(name)) // string compare... |
| { |
| break; |
| } |
| entityDecl = fDeferredDocumentImpl.getPrevSibling(entityDecl, false); |
| } |
| |
| if (entityDecl != -1 |
| && fDeferredDocumentImpl.getLastChild(entityDecl, false) == -1) { |
| // found entityDecl with same name as this reference |
| // AND it doesn't have any children. |
| |
| // we don't need to iterate, because the whole structure |
| // should already be connected to the 1st child. |
| fDeferredDocumentImpl.setAsLastChild(entityDecl, erChild); |
| } |
| } |
| |
| } |
| |
| // full node expansion |
| else { |
| |
| Node erNode = fCurrentElementNode;//fCurrentElementNode.getParentNode(); |
| fCurrentElementNode = erNode.getParentNode(); |
| |
| try { |
| EntityReferenceImpl xer = (EntityReferenceImpl) erNode; |
| xer.setReadOnly(false, false); |
| |
| // if necessary populate the related entity now |
| if (fDocumentImpl != null) { |
| |
| NamedNodeMap entities = fDocumentType.getEntities(); |
| String name = fStringPool.toString(entityName); |
| Node entityNode = entities.getNamedItem(name); |
| |
| // We could simply return here if there is no entity for |
| // the reference or if the entity is already populated. |
| if (entityNode == null || entityNode.hasChildNodes()) { |
| return; |
| } |
| |
| EntityImpl entity = (EntityImpl) entityNode; |
| entity.setReadOnly(false, false); |
| for (Node child = erNode.getFirstChild(); |
| child != null; |
| child = child.getNextSibling()) { |
| Node childClone = child.cloneNode(true); |
| entity.appendChild(childClone); |
| } |
| entity.setReadOnly(true, true); |
| } |
| } catch (Exception e) { |
| // we aren't building against Xerces - do nothing |
| } |
| } |
| |
| } // endEntityReference(int,int,int) |
| |
| // |
| // DTDValidator.EventHandler methods |
| // |
| |
| /** |
| * This function will be called when a <!DOCTYPE...> declaration is |
| * encountered. |
| */ |
| public void startDTD(QName rootElement, int publicId, int systemId) |
| throws Exception { |
| |
| fInDTD = true; |
| |
| // full expansion |
| if (fDocumentImpl != null) { |
| String rootElementName = fStringPool.toString(rootElement.rawname); |
| String publicString = fStringPool.toString(publicId); |
| String systemString = fStringPool.toString(systemId); |
| fDocumentType = fDocumentImpl. |
| createDocumentType(rootElementName, publicString, systemString); |
| fDocumentImpl.appendChild(fDocumentType); |
| |
| if (fGrammarAccess) { |
| Element schema = fDocument.createElement("schema"); |
| // REVISIT: What should the namespace be? -Ac |
| schema.setAttribute("xmlns", "http://www.w3.org/1999/XMLSchema"); |
| ((AttrImpl)schema.getAttributeNode("xmlns")).setSpecified(false); |
| schema.setAttribute("finalDefault", ""); |
| ((AttrImpl)schema.getAttributeNode("finalDefault")).setSpecified(false); |
| schema.setAttribute("exactDefault", ""); |
| ((AttrImpl)schema.getAttributeNode("exactDefault")).setSpecified(false); |
| fDocumentType.appendChild(schema); |
| fCurrentElementNode = schema; |
| } |
| } |
| |
| // deferred expansion |
| else if (fDeferredDocumentImpl != null) { |
| fDocumentTypeIndex = |
| fDeferredDocumentImpl. |
| createDocumentType(rootElement.rawname, publicId, systemId); |
| fDeferredDocumentImpl.appendChild(fDocumentIndex, fDocumentTypeIndex); |
| |
| if (fGrammarAccess) { |
| int handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("xmlns"), |
| fStringPool.addString("http://www.w3.org/1999/XMLSchema"), |
| fStringPool.addSymbol("CDATA"), |
| false, |
| false); // search |
| fAttrList.addAttr( |
| fStringPool.addSymbol("finalDefault"), |
| fStringPool.addString(""), |
| fStringPool.addSymbol("CDATA"), |
| false, |
| false); // search |
| fAttrList.addAttr( |
| fStringPool.addSymbol("exactDefault"), |
| fStringPool.addString(""), |
| fStringPool.addSymbol("CDATA"), |
| false, |
| false); // search |
| fAttrList.endAttrList(); |
| int schemaIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("schema"), fAttrList, handle); |
| // REVISIT: What should the namespace be? -Ac |
| fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, schemaIndex); |
| fCurrentNodeIndex = schemaIndex; |
| } |
| } |
| |
| } // startDTD(int,int,int) |
| |
| /** |
| * Supports DOM Level 2 internalSubset additions. |
| * Called when the internal subset is completely scanned. |
| */ |
| public void internalSubset(int internalSubset) { |
| |
| //System.out.println("internalSubset callback:"+fStringPool.toString(internalSubset)); |
| |
| // full expansion |
| if (fDocumentImpl != null && fDocumentType != null) { |
| ((DocumentTypeImpl)fDocumentType).setInternalSubset(fStringPool.toString(internalSubset)); |
| } |
| |
| // deferred expansion |
| else if (fDeferredDocumentImpl != null) { |
| fDeferredDocumentImpl.setInternalSubset(fDocumentTypeIndex, internalSubset); |
| } |
| |
| } |
| |
| |
| /** |
| * This function will be called at the end of the DTD. |
| */ |
| public void endDTD() throws Exception { |
| |
| fInDTD = false; |
| |
| if (fGrammarAccess) { |
| if (fDocumentImpl != null) { |
| fCurrentElementNode = fDocumentImpl; |
| } |
| else if (fDeferredDocumentImpl != null) { |
| fCurrentNodeIndex = 0; |
| } |
| } |
| |
| } // endDTD() |
| |
| /** |
| * <!ELEMENT Name contentspec> |
| */ |
| public void elementDecl(QName elementDecl, |
| int contentSpecType, |
| int contentSpecIndex, |
| XMLContentSpec.Provider contentSpecProvider) throws Exception { |
| |
| if (DEBUG_ATTLIST_DECL) { |
| String contentModel = XMLContentSpec.toString(contentSpecProvider, fStringPool, contentSpecIndex); |
| System.out.println("elementDecl(" + fStringPool.toString(elementDecl.rawname) + ", " + |
| contentModel + ")"); |
| } |
| |
| // |
| // Create element declaration |
| // |
| if (fGrammarAccess) { |
| |
| if (fDeferredDocumentImpl != null) { |
| |
| // |
| // Build element |
| // |
| |
| // get element declaration; create if necessary |
| int schemaIndex = getLastChildElement(fDocumentTypeIndex, "schema"); |
| String elementName = fStringPool.toString(elementDecl.rawname); |
| int elementIndex = getLastChildElement(schemaIndex, "element", "name", elementName); |
| if (elementIndex == -1) { |
| int handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("name"), |
| fStringPool.addString(elementName), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); // search |
| fAttrList.addAttr( |
| fStringPool.addSymbol("minOccurs"), // name |
| fStringPool.addString("1"), // value |
| fStringPool.addSymbol("NMTOKEN"), // type |
| false, // specified |
| false); // search |
| fAttrList.addAttr( |
| fStringPool.addSymbol("nullable"), // name |
| fStringPool.addString("false"), // value |
| fStringPool.addSymbol("ENUMERATION"), // type |
| false, // specified |
| false); // search |
| fAttrList.addAttr( |
| fStringPool.addSymbol("abstract"), // name |
| fStringPool.addString("false"), // value |
| fStringPool.addSymbol("ENUMERATION"), // type |
| false, // specified |
| false); // search |
| fAttrList.addAttr( |
| fStringPool.addSymbol("final"), // name |
| fStringPool.addString("false"), // value |
| fStringPool.addSymbol("ENUMERATION"), // type |
| false, // specified |
| false); // search |
| fAttrList.endAttrList(); |
| elementIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("element"), fAttrList, handle); |
| fDeferredDocumentImpl.appendChild(schemaIndex, elementIndex); |
| } |
| |
| // |
| // Build content model |
| // |
| |
| // get type element; create if necessary |
| int typeIndex = getLastChildElement(elementIndex, "complexType"); |
| if (typeIndex == -1 && contentSpecType != XMLElementDecl.TYPE_MIXED) { |
| typeIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("complexType"), null, -1); |
| // REVISIT: Check for type redeclaration? -Ac |
| fDeferredDocumentImpl.insertBefore(elementIndex, typeIndex, getFirstChildElement(elementIndex)); |
| } |
| |
| // create models |
| switch (contentSpecType) { |
| case XMLElementDecl.TYPE_EMPTY: { |
| int attributeIndex = fDeferredDocumentImpl.createAttribute(fStringPool.addSymbol("content"), fStringPool.addString("empty"), true); |
| fDeferredDocumentImpl.setAttributeNode(typeIndex, attributeIndex); |
| break; |
| } |
| case XMLElementDecl.TYPE_ANY: { |
| int anyIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("any"), null, -1); |
| fDeferredDocumentImpl.insertBefore(typeIndex, anyIndex, getFirstChildElement(typeIndex)); |
| break; |
| } |
| case XMLElementDecl.TYPE_MIXED: { |
| XMLContentSpec contentSpec = new XMLContentSpec(); |
| contentSpecProvider.getContentSpec(contentSpecIndex, contentSpec); |
| contentSpecIndex = contentSpec.value; |
| if (contentSpecIndex == -1) { |
| int attributeIndex = fDeferredDocumentImpl.createAttribute(fStringPool.addSymbol("type"), fStringPool.addString("string"), true); |
| fDeferredDocumentImpl.setAttributeNode(elementIndex, attributeIndex); |
| } |
| else { |
| if (typeIndex == -1) { |
| typeIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("complexType"), null, -1); |
| // REVISIT: Check for type redeclaration? -Ac |
| fDeferredDocumentImpl.insertBefore(elementIndex, typeIndex, getFirstChildElement(elementIndex)); |
| } |
| int attributeIndex = fDeferredDocumentImpl.createAttribute(fStringPool.addSymbol("content"), fStringPool.addString("mixed"), true); |
| fDeferredDocumentImpl.setAttributeNode(typeIndex, attributeIndex); |
| int handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("minOccurs"), |
| fStringPool.addString("0"), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); // search |
| fAttrList.addAttr( |
| fStringPool.addSymbol("maxOccurs"), |
| fStringPool.addString("unbounded"), |
| fStringPool.addSymbol("CDATA"), |
| true, |
| false); // search |
| fAttrList.endAttrList(); |
| int choiceIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("choice"), fAttrList, handle); |
| fDeferredDocumentImpl.appendChild(typeIndex, choiceIndex); |
| while (contentSpecIndex != -1) { |
| |
| // get node |
| contentSpecProvider.getContentSpec(contentSpecIndex, contentSpec); |
| int type = contentSpec.type; |
| int left = contentSpec.value; |
| int right = contentSpec.otherValue; |
| |
| // if leaf, skip "#PCDATA" and stop |
| if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) { |
| break; |
| } |
| |
| // add right hand leaf |
| contentSpecProvider.getContentSpec(right, contentSpec); |
| handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("ref"), |
| fStringPool.addString(fStringPool.toString(contentSpec.value)), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); //search |
| fAttrList.endAttrList(); |
| int rightIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("element"), fAttrList, handle); |
| int refIndex = getFirstChildElement(choiceIndex); |
| fDeferredDocumentImpl.insertBefore(choiceIndex, rightIndex, refIndex); |
| |
| // go to next node |
| contentSpecIndex = left; |
| } |
| } |
| break; |
| } |
| case XMLElementDecl.TYPE_CHILDREN: { |
| int attributeIndex = fDeferredDocumentImpl.createAttribute(fStringPool.addSymbol("content"), fStringPool.addString("elementOnly"), true); |
| fDeferredDocumentImpl.setAttributeNode(typeIndex, attributeIndex); |
| int children = createChildren(contentSpecProvider, |
| contentSpecIndex, |
| new XMLContentSpec(), |
| fDeferredDocumentImpl, |
| -1); |
| fDeferredDocumentImpl.insertBefore(typeIndex, children, getFirstChildElement(typeIndex)); |
| break; |
| } |
| } |
| |
| } // if defer-node-expansion |
| |
| else if (fDocumentImpl != null) { |
| |
| // |
| // Build element |
| // |
| |
| // get element declaration; create if necessary |
| Element schema = XUtil.getLastChildElement(fDocumentType, "schema"); |
| String elementName = fStringPool.toString(elementDecl.rawname); |
| Element element = XUtil.getLastChildElement(schema, "element", "name", elementName); |
| if (element == null) { |
| element = fDocumentImpl.createElement("element"); |
| element.setAttribute("name", elementName); |
| element.setAttribute("minOccurs", "1"); |
| ((AttrImpl)element.getAttributeNode("minOccurs")).setSpecified(false); |
| element.setAttribute("nullable", "false"); |
| ((AttrImpl)element.getAttributeNode("nullable")).setSpecified(false); |
| element.setAttribute("abstract", "false"); |
| ((AttrImpl)element.getAttributeNode("abstract")).setSpecified(false); |
| element.setAttribute("final", "false"); |
| ((AttrImpl)element.getAttributeNode("final")).setSpecified(false); |
| schema.appendChild(element); |
| } |
| |
| // |
| // Build content model |
| // |
| |
| // get type element; create if necessary |
| Element type = XUtil.getLastChildElement(element, "complexType"); |
| if (type == null && contentSpecType != XMLElementDecl.TYPE_MIXED) { |
| type = fDocumentImpl.createElement("complexType"); |
| // REVISIT: Check for type redeclaration? -Ac |
| element.insertBefore(type, XUtil.getFirstChildElement(element)); |
| } |
| |
| // create models |
| switch (contentSpecType) { |
| case XMLElementDecl.TYPE_EMPTY: { |
| type.setAttribute("content", "empty"); |
| break; |
| } |
| case XMLElementDecl.TYPE_ANY: { |
| Element any = fDocumentImpl.createElement("any"); |
| type.insertBefore(any, XUtil.getFirstChildElement(type)); |
| break; |
| } |
| case XMLElementDecl.TYPE_MIXED: { |
| XMLContentSpec contentSpec = new XMLContentSpec(); |
| contentSpecProvider.getContentSpec(contentSpecIndex, contentSpec); |
| contentSpecIndex = contentSpec.value; |
| if (contentSpecIndex == -1) { |
| element.setAttribute("type", "string"); |
| } |
| else { |
| if (type == null) { |
| type = fDocumentImpl.createElement("complexType"); |
| // REVISIT: Check for type redeclaration? -Ac |
| element.insertBefore(type, XUtil.getFirstChildElement(element)); |
| } |
| type.setAttribute("content", "mixed"); |
| Element choice = fDocumentImpl.createElement("choice"); |
| choice.setAttribute("minOccurs", "0"); |
| choice.setAttribute("maxOccurs", "unbounded"); |
| type.appendChild(choice); |
| while (contentSpecIndex != -1) { |
| |
| // get node |
| contentSpecProvider.getContentSpec(contentSpecIndex, contentSpec); |
| int cstype = contentSpec.type; |
| int csleft = contentSpec.value; |
| int csright = contentSpec.otherValue; |
| |
| // if leaf, skip "#PCDATA" and stop |
| if (cstype == XMLContentSpec.CONTENTSPECNODE_LEAF) { |
| break; |
| } |
| |
| // add right hand leaf |
| contentSpecProvider.getContentSpec(csright, contentSpec); |
| Element right = fDocumentImpl.createElement("element"); |
| right.setAttribute("ref", fStringPool.toString(contentSpec.value)); |
| Element ref = XUtil.getFirstChildElement(choice); |
| choice.insertBefore(right, ref); |
| |
| // go to next node |
| contentSpecIndex = csleft; |
| } |
| } |
| break; |
| } |
| case XMLElementDecl.TYPE_CHILDREN: { |
| type.setAttribute("content", "elementOnly"); |
| Element children = createChildren(contentSpecProvider, |
| contentSpecIndex, |
| new XMLContentSpec(), |
| fDocumentImpl, |
| null); |
| type.insertBefore(children, XUtil.getFirstChildElement(type)); |
| break; |
| } |
| } |
| |
| } // if NOT defer-node-expansion |
| |
| } // if grammar-access |
| |
| } // elementDecl(int,String) |
| |
| /** |
| * <!ATTLIST Name AttDef> |
| */ |
| public void attlistDecl(QName elementDecl, QName attributeDecl, |
| int attType, boolean attList, String enumString, |
| int attDefaultType, int attDefaultValue) |
| throws Exception { |
| |
| if (DEBUG_ATTLIST_DECL) { |
| System.out.println("attlistDecl(" + fStringPool.toString(elementDecl.rawname) + ", " + |
| fStringPool.toString(attributeDecl.rawname) + ", " + |
| fStringPool.toString(attType) + ", " + |
| enumString + ", " + |
| fStringPool.toString(attDefaultType) + ", " + |
| fStringPool.toString(attDefaultValue) + ")"); |
| } |
| |
| // deferred expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| // get the default value |
| if (attDefaultValue != -1) { |
| if (DEBUG_ATTLIST_DECL) { |
| System.out.println(" adding default attribute value: "+ |
| fStringPool.toString(attDefaultValue)); |
| } |
| |
| // get element definition |
| int elementDefIndex = fDeferredDocumentImpl.lookupElementDefinition(elementDecl.rawname); |
| |
| // create element definition if not already there |
| if (elementDefIndex == -1) { |
| elementDefIndex = fDeferredDocumentImpl.createElementDefinition(elementDecl.rawname); |
| fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, elementDefIndex); |
| } |
| |
| // add default attribute |
| int attrIndex = |
| fDeferredDocumentImpl.createAttribute(attributeDecl.rawname, |
| attributeDecl.uri, |
| attDefaultValue, |
| false); |
| fDeferredDocumentImpl.appendChild(elementDefIndex, attrIndex); |
| |
| } |
| |
| // |
| // Create attribute declaration |
| // |
| if (fGrammarAccess) { |
| |
| // get element declaration; create it if necessary |
| int schemaIndex = getLastChildElement(fDocumentTypeIndex, "schema"); |
| String elementName = fStringPool.toString(elementDecl.rawname); |
| int elementIndex = getLastChildElement(schemaIndex, "element", "name", elementName); |
| if (elementIndex == -1) { |
| int handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("name"), |
| fStringPool.addString(elementName), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); //search |
| fAttrList.endAttrList(); |
| elementIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("element"), fAttrList, handle); |
| fDeferredDocumentImpl.appendChild(schemaIndex, elementIndex); |
| } |
| |
| // get type element; create it if necessary |
| int typeIndex = getLastChildElement(elementIndex, "complexType"); |
| if (typeIndex == -1) { |
| typeIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("complexType"), null, -1); |
| fDeferredDocumentImpl.insertBefore(elementIndex, typeIndex, getLastChildElement(elementIndex)); |
| } |
| |
| // create attribute and set its attributes |
| String attributeName = fStringPool.toString(attributeDecl.rawname); |
| int attributeIndex = getLastChildElement(elementIndex, "attribute", "name", attributeName); |
| if (attributeIndex == -1) { |
| int handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("name"), |
| fStringPool.addString(attributeName), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); // search |
| fAttrList.addAttr( |
| fStringPool.addSymbol("maxOccurs"), |
| fStringPool.addString("1"), |
| fStringPool.addSymbol("CDATA"), |
| false, |
| false); // search |
| fAttrList.endAttrList(); |
| attributeIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("attribute"), fAttrList, handle); |
| fDeferredDocumentImpl.appendChild(typeIndex, attributeIndex); |
| |
| // attribute type: CDATA, ENTITY, ... , NMTOKENS; ENUMERATION |
| if (attType == XMLAttributeDecl.TYPE_ENUMERATION) { |
| handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("base"), |
| fStringPool.addString("NMTOKEN"), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); // search |
| fAttrList.endAttrList(); |
| int simpleTypeIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("simpleType"), fAttrList, handle); |
| fDeferredDocumentImpl.appendChild(attributeIndex, simpleTypeIndex); |
| String tokenizerString = enumString.substring(1, enumString.length() - 1); |
| StringTokenizer tokenizer = new StringTokenizer(tokenizerString, "|"); |
| while (tokenizer.hasMoreTokens()) { |
| handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("value"), |
| fStringPool.addString(tokenizer.nextToken()), |
| fStringPool.addSymbol("CDATA"), |
| true, |
| false); // search |
| fAttrList.endAttrList(); |
| int enumerationIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("enumeration"), fAttrList, handle); |
| fDeferredDocumentImpl.appendChild(simpleTypeIndex, enumerationIndex); |
| } |
| } |
| else { |
| int typeNameIndex = -1; |
| switch (attType) { |
| case XMLAttributeDecl.TYPE_ENTITY: { |
| typeNameIndex = fStringPool.addString(attList?"ENTITIES":"ENTITY"); |
| break; |
| } |
| case XMLAttributeDecl.TYPE_ID: { |
| typeNameIndex = fStringPool.addString("ID"); |
| break; |
| } |
| case XMLAttributeDecl.TYPE_IDREF: { |
| typeNameIndex = fStringPool.addString(attList?"IDREFS":"IDREF"); |
| break; |
| } |
| case XMLAttributeDecl.TYPE_NMTOKEN: { |
| typeNameIndex = fStringPool.addString(attList?"NMTOKENS":"NMTOKEN"); |
| break; |
| } |
| case XMLAttributeDecl.TYPE_NOTATION: { |
| typeNameIndex = fStringPool.addString("NOTATION"); |
| break; |
| } |
| case XMLAttributeDecl.TYPE_CDATA: |
| default: { |
| typeNameIndex = fStringPool.addString("string"); |
| break; |
| } |
| } |
| int attrIndex = fDeferredDocumentImpl.createAttribute(fStringPool.addSymbol("type"), typeNameIndex, true); |
| fDeferredDocumentImpl.setAttributeNode(attributeIndex, attrIndex); |
| } |
| |
| // attribute default type: #IMPLIED, #REQUIRED, #FIXED |
| boolean fixed = false; |
| switch (attDefaultType) { |
| case XMLAttributeDecl.DEFAULT_TYPE_REQUIRED: { |
| int useAttrIndex = fDeferredDocumentImpl.createAttribute(fStringPool.addSymbol("use"), fStringPool.addString("required"), true); |
| fDeferredDocumentImpl.setAttributeNode(attributeIndex, useAttrIndex); |
| break; |
| } |
| case XMLAttributeDecl.DEFAULT_TYPE_FIXED: { |
| fixed = true; |
| int useAttrIndex = fDeferredDocumentImpl.createAttribute(fStringPool.addSymbol("use"), fStringPool.addString("fixed"), true); |
| fDeferredDocumentImpl.setAttributeNode(attributeIndex, useAttrIndex); |
| break; |
| } |
| } |
| |
| // attribute default value |
| if (attDefaultValue != -1) { |
| if (!fixed) { |
| int useAttrIndex = fDeferredDocumentImpl.createAttribute(fStringPool.addSymbol("use"), fStringPool.addString("default"), true); |
| fDeferredDocumentImpl.setAttributeNode(attributeIndex, useAttrIndex); |
| } |
| int valueAttrIndex = fDeferredDocumentImpl.createAttribute(fStringPool.addSymbol("value"), attDefaultValue, true); |
| fDeferredDocumentImpl.setAttributeNode(attributeIndex, valueAttrIndex); |
| } |
| } |
| } |
| } |
| |
| // full expansion |
| else if (fDocumentImpl != null) { |
| |
| // get the default value |
| if (attDefaultValue != -1) { |
| if (DEBUG_ATTLIST_DECL) { |
| System.out.println(" adding default attribute value: "+ |
| fStringPool.toString(attDefaultValue)); |
| } |
| |
| // get element name |
| String elementName = fStringPool.toString(elementDecl.rawname); |
| |
| // 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 |
| // REVISIT: what about default attributes with URI? -ALH |
| |
| // get attribute name and value index |
| String attrName = fStringPool.toString(attributeDecl.rawname); |
| String attrValue = fStringPool.toString(attDefaultValue); |
| |
| // create attribute and set properties |
| AttrImpl attr = (AttrImpl)fDocumentImpl.createAttribute(attrName); |
| attr.setValue(attrValue); |
| attr.setSpecified(false); |
| |
| // add default attribute to element definition |
| elementDef.getAttributes().setNamedItem(attr); |
| } |
| |
| // |
| // Create attribute declaration |
| // |
| try { |
| if (fGrammarAccess) { |
| |
| // get element declaration; create it if necessary |
| Element schema = XUtil.getLastChildElement(fDocumentType, "schema"); |
| String elementName = fStringPool.toString(elementDecl.rawname); |
| Element element = XUtil.getLastChildElement(schema, "element", "name", elementName); |
| if (element == null) { |
| element = fDocumentImpl.createElement("element"); |
| element.setAttribute("name", elementName); |
| schema.appendChild(element); |
| } |
| |
| // get type element; create it if necessary |
| Element type = XUtil.getLastChildElement(element, "complexType"); |
| if (type == null) { |
| type = fDocumentImpl.createElement("complexType"); |
| element.insertBefore(type, XUtil.getLastChildElement(element)); |
| } |
| |
| // create attribute and set its attributes |
| String attributeName = fStringPool.toString(attributeDecl.rawname); |
| Element attribute = XUtil.getLastChildElement(element, "attribute", "name", attributeName); |
| if (attribute == null) { |
| attribute = fDocumentImpl.createElement("attribute"); |
| attribute.setAttribute("name", attributeName); |
| attribute.setAttribute("maxOccurs", "1"); |
| ((AttrImpl)attribute.getAttributeNode("maxOccurs")).setSpecified(false); |
| type.appendChild(attribute); |
| |
| // attribute type: CDATA, ENTITY, ... , NMTOKENS; ENUMERATION |
| if (attType == XMLAttributeDecl.TYPE_ENUMERATION) { |
| Element simpleType = fDocumentImpl.createElement("simpleType"); |
| simpleType.setAttribute("base", "NMTOKEN"); |
| attribute.appendChild(simpleType); |
| String tokenizerString = enumString.substring(1, enumString.length() - 1); |
| StringTokenizer tokenizer = new StringTokenizer(tokenizerString, "|"); |
| while (tokenizer.hasMoreTokens()) { |
| Element enumeration = fDocumentImpl.createElement("enumeration"); |
| enumeration.setAttribute("value", tokenizer.nextToken()); |
| simpleType.appendChild(enumeration); |
| } |
| } |
| else { |
| String typeName = null; |
| switch (attType) { |
| case XMLAttributeDecl.TYPE_ENTITY: { |
| typeName = attList ? "ENTITIES" : "ENTITY"; |
| break; |
| } |
| case XMLAttributeDecl.TYPE_ID: { |
| typeName = "ID"; |
| break; |
| } |
| case XMLAttributeDecl.TYPE_IDREF: { |
| typeName = attList ? "IDREFS" : "IDREF"; |
| break; |
| } |
| case XMLAttributeDecl.TYPE_NMTOKEN: { |
| typeName = attList ? "NMTOKENS" : "NMTOKEN"; |
| break; |
| } |
| case XMLAttributeDecl.TYPE_NOTATION: { |
| typeName = "NOTATION"; |
| break; |
| } |
| case XMLAttributeDecl.TYPE_CDATA: |
| default: { |
| typeName = "string"; |
| break; |
| } |
| } |
| attribute.setAttribute("type", typeName); |
| } |
| |
| // attribute default type: #IMPLIED, #REQUIRED, #FIXED |
| boolean fixed = false; |
| switch (attDefaultType) { |
| case XMLAttributeDecl.DEFAULT_TYPE_REQUIRED: { |
| attribute.setAttribute("use", "required"); |
| break; |
| } |
| case XMLAttributeDecl.DEFAULT_TYPE_FIXED: { |
| attribute.setAttribute("use", "fixed"); |
| fixed = true; |
| break; |
| } |
| } |
| |
| // attribute default value |
| if (attDefaultValue != -1) { |
| if (!fixed) { |
| attribute.setAttribute("use", "default"); |
| } |
| attribute.setAttribute("value", fStringPool.toString(attDefaultValue)); |
| } |
| } |
| } |
| } |
| catch (Exception e) { |
| e.printStackTrace(System.err); |
| } |
| |
| } // if NOT defer-node-expansion |
| |
| } // attlistDecl(int,int,int,String,int,int) |
| |
| /** |
| * <!ENTITY % Name EntityValue> (internal) |
| */ |
| public void internalPEDecl(int entityNameIndex, int entityValueIndex) throws Exception { |
| if (fDeferredDocumentImpl != null) { |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY % "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(" \""); |
| str.append(fStringPool.toString(entityValueIndex)); |
| str.append("\">"); |
| int commentIndex = fStringPool.addString(str.toString()); |
| int internalPEEntityIndex = fDeferredDocumentImpl.createComment(commentIndex); |
| int schemaIndex = getFirstChildElement(fDocumentTypeIndex, "schema"); |
| fDeferredDocumentImpl.appendChild(schemaIndex, internalPEEntityIndex); |
| } |
| } |
| else if (fDocumentImpl != null) { |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY % "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(" \""); |
| str.append(fStringPool.orphanString(entityValueIndex)); |
| str.append("\">"); |
| Node internalPEEntity = fDocumentImpl.createComment(str.toString()); |
| Node schema = XUtil.getFirstChildElement(fDocumentType, "schema"); |
| schema.appendChild(internalPEEntity); |
| } |
| } |
| else { |
| fStringPool.orphanString(entityValueIndex); |
| } |
| } |
| |
| /** |
| * <!ENTITY % Name ExternalID> (external) |
| */ |
| public void externalPEDecl(int entityNameIndex, int publicIdIndex, int systemIdIndex) throws Exception { |
| if (fDeferredDocumentImpl != null) { |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(' '); |
| if (publicIdIndex != -1) { |
| str.append("PUBLIC \""); |
| str.append(fStringPool.toString(publicIdIndex)); |
| str.append('"'); |
| if (systemIdIndex != -1) { |
| str.append(" \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| } |
| else if (systemIdIndex != -1) { |
| str.append("SYSTEM \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| str.append('>'); |
| int commentIndex = fStringPool.addString(str.toString()); |
| int externalPEEntityIndex = fDeferredDocumentImpl.createComment(commentIndex); |
| int schemaIndex = getFirstChildElement(fDocumentTypeIndex, "schema"); |
| fDeferredDocumentImpl.appendChild(schemaIndex, externalPEEntityIndex); |
| } |
| } |
| else if (fDocumentImpl != null) { |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(' '); |
| if (publicIdIndex != -1) { |
| str.append("PUBLIC \""); |
| str.append(fStringPool.toString(publicIdIndex)); |
| str.append('"'); |
| if (systemIdIndex != -1) { |
| str.append(" \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| } |
| else if (systemIdIndex != -1) { |
| str.append("SYSTEM \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| str.append('>'); |
| Node externalPEEntity = fDocumentImpl.createComment(str.toString()); |
| Node schema = XUtil.getFirstChildElement(fDocumentType, "schema"); |
| schema.appendChild(externalPEEntity); |
| } |
| } |
| } |
| |
| /** |
| * <!ENTITY Name EntityValue> (internal) |
| */ |
| public void internalEntityDecl(int entityNameIndex, int entityValueIndex) |
| throws Exception { |
| |
| // deferred expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| if (fDocumentTypeIndex == -1) return; //revisit: should never happen. Exception? |
| |
| //revisit: how to check if entity was already declared. |
| // XML spec says that 1st Entity decl is binding. |
| |
| int newEntityIndex = fDeferredDocumentImpl.createEntity(entityNameIndex, -1, -1, -1); |
| fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, newEntityIndex); |
| |
| // REVISIT: Entities were removed from latest working draft. -Ac |
| // create internal entity declaration |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(" \""); |
| str.append(fStringPool.toString(entityValueIndex)); |
| str.append("\">"); |
| int commentIndex = fStringPool.addString(str.toString()); |
| int textEntityIndex = fDeferredDocumentImpl.createComment(commentIndex); |
| int schemaIndex = getFirstChildElement(fDocumentTypeIndex, "schema"); |
| fDeferredDocumentImpl.appendChild(schemaIndex, textEntityIndex); |
| } |
| } |
| |
| // full expansion |
| else if (fDocumentImpl != null) { |
| if (fDocumentType == null) return; //revisit: should never happen. Exception? |
| |
| //revisit: how to check if entity was already declared. |
| // XML spec says that 1st Entity decl is binding. |
| |
| String entityName = fStringPool.toString(entityNameIndex); |
| |
| Entity entity = fDocumentImpl.createEntity(entityName); |
| fDocumentType.getEntities().setNamedItem(entity); |
| |
| // REVISIT: Entities were removed from latest working draft. -Ac |
| // create internal entity declaration |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(" \""); |
| str.append(fStringPool.toString(entityValueIndex)); |
| str.append("\">"); |
| Node textEntity = fDocumentImpl.createComment(str.toString()); |
| Node schema = XUtil.getFirstChildElement(fDocumentType, "schema"); |
| schema.appendChild(textEntity); |
| } |
| } |
| |
| } // internalEntityDecl(int,int) |
| |
| /** |
| * <!ENTITY Name ExternalID> (external) |
| */ |
| public void externalEntityDecl(int entityNameIndex, int publicIdIndex, int systemIdIndex) |
| throws Exception { |
| |
| // deferred expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| //revisit: how to check if entity was already declared. |
| // XML spec says that 1st Entity decl is binding. |
| |
| int newEntityIndex = fDeferredDocumentImpl.createEntity(entityNameIndex, publicIdIndex, systemIdIndex, -1); |
| |
| fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, newEntityIndex); |
| |
| // REVISIT: Entities were removed from latest working draft. -Ac |
| // create external entity declaration |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(' '); |
| if (publicIdIndex != -1) { |
| str.append("PUBLIC \""); |
| str.append(fStringPool.toString(publicIdIndex)); |
| str.append('"'); |
| if (systemIdIndex != -1) { |
| str.append(" \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| } |
| else if (systemIdIndex != -1) { |
| str.append("SYSTEM \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| str.append('>'); |
| int commentIndex = fStringPool.addString(str.toString()); |
| int externalEntityIndex = fDeferredDocumentImpl.createComment(commentIndex); |
| int schemaIndex = getFirstChildElement(fDocumentTypeIndex, "schema"); |
| fDeferredDocumentImpl.appendChild(schemaIndex, externalEntityIndex); |
| } |
| } |
| |
| // full expansion |
| else if (fDocumentImpl != null) { |
| |
| //revisit: how to check if entity was already declared. |
| // XML spec says that 1st Entity decl is binding. |
| |
| String entityName = fStringPool.toString(entityNameIndex); |
| String publicId = fStringPool.toString(publicIdIndex); |
| String systemId = fStringPool.toString(systemIdIndex); |
| |
| EntityImpl entity = (EntityImpl)fDocumentImpl.createEntity(entityName); |
| if (publicIdIndex != -1) { |
| entity.setPublicId(publicId); |
| } |
| entity.setSystemId(systemId); |
| fDocumentType.getEntities().setNamedItem(entity); |
| |
| // REVISIT: Entities were removed from latest working draft. -Ac |
| // create external entity declaration |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(' '); |
| if (publicIdIndex != -1) { |
| str.append("PUBLIC \""); |
| str.append(fStringPool.toString(publicIdIndex)); |
| str.append('"'); |
| if (systemIdIndex != -1) { |
| str.append(" \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| } |
| else if (systemIdIndex != -1) { |
| str.append("SYSTEM \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| str.append('>'); |
| Node externalEntity = fDocumentImpl.createComment(str.toString()); |
| Node schema = XUtil.getFirstChildElement(fDocumentType, "schema"); |
| schema.appendChild(externalEntity); |
| } |
| } |
| |
| } // externalEntityDecl(int,int,int) |
| |
| /** |
| * <!ENTITY Name ExternalID NDataDecl> (unparsed) |
| */ |
| public void unparsedEntityDecl(int entityNameIndex, |
| int publicIdIndex, int systemIdIndex, |
| int notationNameIndex) throws Exception { |
| |
| // deferred expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| //revisit: how to check if entity was already declared. |
| // XML spec says that 1st Entity decl is binding. |
| |
| int newEntityIndex = fDeferredDocumentImpl.createEntity(entityNameIndex, publicIdIndex, systemIdIndex, notationNameIndex); |
| |
| fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, newEntityIndex); |
| |
| // REVISIT: Entities were removed from latest working draft. -Ac |
| // add unparsed entity declaration |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(' '); |
| if (publicIdIndex != -1) { |
| str.append("PUBLIC \""); |
| str.append(fStringPool.toString(publicIdIndex)); |
| str.append('"'); |
| if (systemIdIndex != -1) { |
| str.append(" \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| } |
| else if (systemIdIndex != -1) { |
| str.append("SYSTEM \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| str.append(" NDATA "); |
| str.append(fStringPool.toString(notationNameIndex)); |
| str.append('>'); |
| int commentIndex = fStringPool.addString(str.toString()); |
| int unparsedEntityIndex = fDeferredDocumentImpl.createComment(commentIndex); |
| int schemaIndex = getFirstChildElement(fDocumentTypeIndex, "schema"); |
| fDeferredDocumentImpl.appendChild(schemaIndex, unparsedEntityIndex); |
| } |
| } |
| |
| // full expansion |
| else if (fDocumentImpl != null) { |
| |
| //revisit: how to check if entity was already declared. |
| // XML spec says that 1st Entity decl is binding. |
| |
| String entityName = fStringPool.toString(entityNameIndex); |
| String publicId = fStringPool.toString(publicIdIndex); |
| String systemId = fStringPool.toString(systemIdIndex); |
| String notationName = fStringPool.toString(notationNameIndex); |
| |
| EntityImpl entity = (EntityImpl)fDocumentImpl.createEntity(entityName); |
| if (publicIdIndex != -1) { |
| entity.setPublicId(publicId); |
| } |
| entity.setSystemId(systemId); |
| entity.setNotationName(notationName); |
| fDocumentType.getEntities().setNamedItem(entity); |
| |
| // REVISIT: Entities were removed from latest working draft. -Ac |
| // add unparsed entity declaration |
| if (fGrammarAccess) { |
| StringBuffer str = new StringBuffer(); |
| str.append("<!ENTITY "); |
| str.append(fStringPool.toString(entityNameIndex)); |
| str.append(' '); |
| if (publicIdIndex != -1) { |
| str.append("PUBLIC \""); |
| str.append(fStringPool.toString(publicIdIndex)); |
| str.append('"'); |
| if (systemIdIndex != -1) { |
| str.append(" \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| } |
| else if (systemIdIndex != -1) { |
| str.append("SYSTEM \""); |
| str.append(fStringPool.toString(systemIdIndex)); |
| str.append('"'); |
| } |
| str.append(" NDATA "); |
| str.append(fStringPool.toString(notationNameIndex)); |
| str.append('>'); |
| Node unparsedEntity = fDocumentImpl.createComment(str.toString()); |
| Node schema = XUtil.getFirstChildElement(fDocumentType, "schema"); |
| schema.appendChild(unparsedEntity); |
| } |
| } |
| |
| } // unparsedEntityDecl(int,int,int,int) |
| |
| /** |
| * <!NOTATION Name ExternalId> |
| */ |
| public void notationDecl(int notationNameIndex, int publicIdIndex, int systemIdIndex) |
| throws Exception { |
| |
| // deferred expansion |
| if (fDeferredDocumentImpl != null) { |
| |
| //revisit: how to check if entity was already declared. |
| // XML spec says that 1st Entity decl is binding. |
| |
| int newNotationIndex = fDeferredDocumentImpl.createNotation(notationNameIndex, publicIdIndex, systemIdIndex); |
| |
| fDeferredDocumentImpl.appendChild(fDocumentTypeIndex, newNotationIndex); |
| |
| // create notation declaration |
| if (fGrammarAccess) { |
| int schemaIndex = getLastChildElement(fDocumentTypeIndex, "schema"); |
| String notationName = fStringPool.toString(notationNameIndex); |
| int notationIndex = getLastChildElement(schemaIndex, "notation", "name", notationName); |
| if (notationIndex == -1) { |
| int handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("name"), |
| fStringPool.addString(notationName), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); // search |
| if (publicIdIndex != -1) { |
| fAttrList.addAttr( |
| fStringPool.addSymbol("public"), |
| publicIdIndex, |
| fStringPool.addSymbol("CDATA"), |
| true, |
| false); // search |
| } |
| if (systemIdIndex != -1) { |
| fAttrList.addAttr( |
| fStringPool.addSymbol("system"), |
| systemIdIndex, |
| fStringPool.addSymbol("CDATA"), |
| true, |
| false); // search |
| } |
| fAttrList.endAttrList(); |
| notationIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol("notation"), fAttrList, handle); |
| fDeferredDocumentImpl.appendChild(schemaIndex, notationIndex); |
| } |
| } |
| } |
| |
| // full expansion |
| else if (fDocumentImpl != null) { |
| |
| // REVISIT: how to check if entity was already declared. |
| // XML spec says that 1st Entity decl is binding. |
| |
| String notationName = fStringPool.toString(notationNameIndex); |
| String publicId = fStringPool.toString(publicIdIndex); |
| String systemId = fStringPool.toString(systemIdIndex); |
| |
| NotationImpl notationImpl = (NotationImpl)fDocumentImpl.createNotation(notationName); |
| notationImpl.setPublicId(publicId); |
| if (systemIdIndex != -1) { |
| notationImpl.setSystemId(systemId); |
| } |
| |
| fDocumentType.getNotations().setNamedItem(notationImpl); |
| |
| // create notation declaration |
| if (fGrammarAccess) { |
| Element schema = XUtil.getFirstChildElement(fDocumentType, "schema"); |
| Element notation = XUtil.getFirstChildElement(schema, "notation", "name", notationName); |
| if (notation == null) { |
| notation = fDocument.createElement("notation"); |
| notation.setAttribute("name", notationName); |
| //notation.setAttribute("export", "true"); |
| //((AttrImpl)notation.getAttributeNode("export")).setSpecified(false); |
| if (publicId != null) { |
| notation.setAttribute("public", publicId); |
| } |
| if (systemIdIndex != -1) { |
| notation.setAttribute("system", systemId); |
| } |
| schema.appendChild(notation); |
| } |
| } |
| } |
| |
| } // notationDecl(int,int,int) |
| |
| // |
| // Private methods |
| // |
| |
| /** Returns the first child element of the specified node. */ |
| private int getFirstChildElement(int nodeIndex) { |
| int childIndex = getLastChildElement(nodeIndex); |
| while (childIndex != -1) { |
| int prevIndex = getPrevSiblingElement(childIndex); |
| if (prevIndex == -1) { |
| break; |
| } |
| childIndex = prevIndex; |
| } |
| return childIndex; |
| } |
| |
| /** Returns the first child element of the specified node. */ |
| private int getFirstChildElement(int nodeIndex, String name) { |
| int childIndex = getLastChildElement(nodeIndex); |
| if (childIndex != -1) { |
| int nameIndex = fStringPool.addSymbol(name); |
| while (childIndex != -1) { |
| if (fDeferredDocumentImpl.getNodeName(childIndex, false) == nameIndex) { |
| break; |
| } |
| int prevIndex = getPrevSiblingElement(childIndex); |
| childIndex = prevIndex; |
| } |
| } |
| return childIndex; |
| } |
| |
| /** Returns the last child element of the specified node. */ |
| private int getLastChildElement(int nodeIndex) { |
| int childIndex = fDeferredDocumentImpl.getLastChild(nodeIndex, false); |
| while (childIndex != -1) { |
| if (fDeferredDocumentImpl.getNodeType(childIndex, false) == Node.ELEMENT_NODE) { |
| return childIndex; |
| } |
| childIndex = fDeferredDocumentImpl.getPrevSibling(childIndex, false); |
| } |
| return -1; |
| } |
| |
| /** Returns the previous sibling element of the specified node. */ |
| private int getPrevSiblingElement(int nodeIndex) { |
| int siblingIndex = fDeferredDocumentImpl.getPrevSibling(nodeIndex, false); |
| while (siblingIndex != -1) { |
| if (fDeferredDocumentImpl.getNodeType(siblingIndex, false) == Node.ELEMENT_NODE) { |
| return siblingIndex; |
| } |
| siblingIndex = fDeferredDocumentImpl.getPrevSibling(siblingIndex, false); |
| } |
| return -1; |
| } |
| |
| /** Returns the first child element with the given name. */ |
| private int getLastChildElement(int nodeIndex, String elementName) { |
| int childIndex = getLastChildElement(nodeIndex); |
| if (childIndex != -1) { |
| while (childIndex != -1) { |
| String nodeName = fDeferredDocumentImpl.getNodeNameString(childIndex, false); |
| if (nodeName.equals(elementName)) { |
| return childIndex; |
| } |
| childIndex = getPrevSiblingElement(childIndex); |
| } |
| } |
| return -1; |
| } |
| |
| /** Returns the next sibling element with the given name. */ |
| private int getPrevSiblingElement(int nodeIndex, String elementName) { |
| int siblingIndex = getPrevSiblingElement(nodeIndex); |
| if (siblingIndex != -1) { |
| while (siblingIndex != -1) { |
| String nodeName = fDeferredDocumentImpl.getNodeNameString(siblingIndex, false); |
| if (nodeName.equals(elementName)) { |
| return siblingIndex; |
| } |
| siblingIndex = getPrevSiblingElement(siblingIndex); |
| } |
| } |
| return -1; |
| } |
| |
| /** Returns the first child element with the given name. */ |
| private int getLastChildElement(int nodeIndex, String elemName, String attrName, String attrValue) { |
| int childIndex = getLastChildElement(nodeIndex, elemName); |
| if (childIndex != -1) { |
| while (childIndex != -1) { |
| int attrIndex = fDeferredDocumentImpl.getNodeValue(childIndex, false); |
| while (attrIndex != -1) { |
| String nodeName = fDeferredDocumentImpl.getNodeNameString(attrIndex, false); |
| if (nodeName.equals(attrName)) { |
| // REVISIT: Do we need to normalize the text? -Ac |
| int textIndex = fDeferredDocumentImpl.getLastChild(attrIndex, false); |
| String nodeValue = fDeferredDocumentImpl.getNodeValueString(textIndex, false); |
| if (nodeValue.equals(attrValue)) { |
| return childIndex; |
| } |
| } |
| attrIndex = fDeferredDocumentImpl.getPrevSibling(attrIndex, false); |
| } |
| childIndex = getPrevSiblingElement(childIndex, elemName); |
| } |
| } |
| return -1; |
| } |
| |
| /** Returns the next sibling element with the given name and attribute. */ |
| private int getPrevSiblingElement(int nodeIndex, String elemName, String attrName, String attrValue) { |
| int siblingIndex = getPrevSiblingElement(nodeIndex, elemName); |
| if (siblingIndex != -1) { |
| int attributeNameIndex = fStringPool.addSymbol(attrName); |
| while (siblingIndex != -1) { |
| int attrIndex = fDeferredDocumentImpl.getNodeValue(siblingIndex, false); |
| while (attrIndex != -1) { |
| int attrValueIndex = fDeferredDocumentImpl.getNodeValue(attrIndex, false); |
| if (attrValue.equals(fStringPool.toString(attrValueIndex))) { |
| return siblingIndex; |
| } |
| attrIndex = fDeferredDocumentImpl.getPrevSibling(attrIndex, false); |
| } |
| siblingIndex = getPrevSiblingElement(siblingIndex, elemName); |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Copies the source tree into the specified place in a destination |
| * tree. The source node and its children are appended as children |
| * of the destination node. |
| * <p> |
| * <em>Note:</em> This is an iterative implementation. |
| */ |
| private void copyInto(Node src, int destIndex) throws Exception { |
| |
| // for ignorable whitespace features |
| boolean domimpl = src != null && src instanceof DocumentImpl; |
| |
| // placement variables |
| Node start = src; |
| Node parent = src; |
| Node place = src; |
| |
| // traverse source tree |
| while (place != null) { |
| |
| // copy this node |
| int nodeIndex = -1; |
| short type = place.getNodeType(); |
| switch (type) { |
| case Node.CDATA_SECTION_NODE: { |
| boolean ignorable = domimpl && ((TextImpl)place).isIgnorableWhitespace(); |
| nodeIndex = fDeferredDocumentImpl.createCDATASection(fStringPool.addString(place.getNodeValue()), ignorable); |
| break; |
| } |
| case Node.COMMENT_NODE: { |
| nodeIndex = fDeferredDocumentImpl.createComment(fStringPool.addString(place.getNodeValue())); |
| break; |
| } |
| case Node.ELEMENT_NODE: { |
| XMLAttrList attrList = null; |
| int handle = -1; |
| NamedNodeMap attrs = place.getAttributes(); |
| if (attrs != null) { |
| int length = attrs.getLength(); |
| if (length > 0) { |
| handle = fAttrList.startAttrList(); |
| for (int i = 0; i < length; i++) { |
| Attr attr = (Attr)attrs.item(i); |
| String attrName = attr.getNodeName(); |
| String attrValue = attr.getNodeValue(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol(attrName), |
| fStringPool.addString(attrValue), |
| fStringPool.addSymbol("CDATA"), // REVISIT |
| attr.getSpecified(), |
| false); // search |
| } |
| fAttrList.endAttrList(); |
| attrList = fAttrList; |
| } |
| } |
| nodeIndex = fDeferredDocumentImpl.createElement(fStringPool.addSymbol(place.getNodeName()), attrList, handle); |
| break; |
| } |
| case Node.ENTITY_REFERENCE_NODE: { |
| nodeIndex = fDeferredDocumentImpl.createEntityReference(fStringPool.addSymbol(place.getNodeName())); |
| break; |
| } |
| case Node.PROCESSING_INSTRUCTION_NODE: { |
| nodeIndex = fDeferredDocumentImpl.createProcessingInstruction(fStringPool.addSymbol(place.getNodeName()), fStringPool.addString(place.getNodeValue())); |
| break; |
| } |
| case Node.TEXT_NODE: { |
| boolean ignorable = domimpl && ((TextImpl)place).isIgnorableWhitespace(); |
| nodeIndex = fDeferredDocumentImpl.createTextNode(fStringPool.addString(place.getNodeValue()), ignorable); |
| break; |
| } |
| default: { |
| throw new IllegalArgumentException("PAR010 Can't copy node type, "+ |
| type+" ("+ |
| place.getNodeName()+')' |
| +"\n"+type+"\t"+place.getNodeName()); |
| } |
| } |
| fDeferredDocumentImpl.appendChild(destIndex, nodeIndex); |
| |
| // iterate over children |
| if (place.hasChildNodes()) { |
| parent = place; |
| place = place.getFirstChild(); |
| destIndex = nodeIndex; |
| } |
| |
| // advance |
| else { |
| place = place.getNextSibling(); |
| while (place == null && parent != start) { |
| place = parent.getNextSibling(); |
| parent = parent.getParentNode(); |
| destIndex = fDeferredDocumentImpl.getParentNode(destIndex, false); |
| } |
| } |
| |
| } |
| |
| } // copyInto(Node,int) |
| |
| /** |
| * Sets the appropriate occurrence count attributes on the specified |
| * model element. |
| */ |
| private void setOccurrenceCount(Element model, int minOccur, int maxOccur) { |
| |
| // min |
| model.setAttribute("minOccurs", Integer.toString(minOccur)); |
| if (minOccur == 1) { |
| ((AttrImpl)model.getAttributeNode("minOccurs")).setSpecified(false); |
| } |
| |
| // max |
| if (maxOccur == -1) { |
| model.setAttribute("maxOccurs", "*"); |
| } |
| else if (maxOccur != 1) { |
| model.setAttribute("maxOccurs", Integer.toString(maxOccur)); |
| } |
| |
| } // setOccurrenceCount(Element,int,int) |
| |
| /** Creates the children for the element decl. */ |
| private Element createChildren(XMLContentSpec.Provider provider, |
| int index, XMLContentSpec node, |
| DocumentImpl factory, |
| Element parent) throws Exception { |
| |
| // get occurrence count |
| provider.getContentSpec(index, node); |
| int occurs = -1; |
| switch (node.type) { |
| case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: { |
| occurs = '+'; |
| provider.getContentSpec(node.value, node); |
| break; |
| } |
| case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: { |
| occurs = '*'; |
| provider.getContentSpec(node.value, node); |
| break; |
| } |
| case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: { |
| occurs = '?'; |
| provider.getContentSpec(node.value, node); |
| break; |
| } |
| } |
| |
| // flatten model |
| int nodeType = node.type; |
| switch (nodeType) { |
| |
| // CHOICE or SEQUENCE |
| case XMLContentSpec.CONTENTSPECNODE_CHOICE: |
| case XMLContentSpec.CONTENTSPECNODE_SEQ: { |
| |
| // go down left side |
| int leftIndex = node.value; |
| int rightIndex = node.otherValue; |
| Element left = createChildren(provider, leftIndex, node, |
| factory, parent); |
| |
| // go down right side |
| Element right = createChildren(provider, rightIndex, node, |
| factory, null); |
| |
| // append left children |
| boolean choice = nodeType == XMLContentSpec.CONTENTSPECNODE_CHOICE; |
| String type = choice ? "choice" : "sequence"; |
| Element model = left; |
| if (!left.getNodeName().equals(type)) { |
| String minOccurs = left.getAttribute("minOccurs"); |
| String maxOccurs = left.getAttribute("maxOccurs"); |
| boolean min1 = minOccurs.length() == 0 || minOccurs.equals("1"); |
| boolean max1 = maxOccurs.length() == 0 || maxOccurs.equals("1"); |
| if (parent == null || (min1 && max1)) { |
| model = factory.createElement(type); |
| model.appendChild(left); |
| } |
| else { |
| model = parent; |
| } |
| } |
| |
| // set occurrence count |
| switch (occurs) { |
| case '+': { |
| model.setAttribute("maxOccurs", "unbounded"); |
| break; |
| } |
| case '*': { |
| model.setAttribute("minOccurs", "0"); |
| model.setAttribute("maxOccurs", "unbounded"); |
| break; |
| } |
| case '?': { |
| model.setAttribute("minOccurs", "0"); |
| break; |
| } |
| } |
| |
| // append right children |
| model.appendChild(right); |
| |
| // return model |
| return model; |
| } |
| |
| // LEAF |
| case XMLContentSpec.CONTENTSPECNODE_LEAF: { |
| Element leaf = factory.createElement("element"); |
| leaf.setAttribute("ref", fStringPool.toString(node.value)); |
| switch (occurs) { |
| case '+': { |
| leaf.setAttribute("maxOccurs", "unbounded"); |
| break; |
| } |
| case '*': { |
| leaf.setAttribute("minOccurs", "0"); |
| leaf.setAttribute("maxOccurs", "unbounded"); |
| break; |
| } |
| case '?': { |
| leaf.setAttribute("minOccurs", "0"); |
| break; |
| } |
| } |
| return leaf; |
| } |
| |
| } // switch node type |
| |
| // error |
| return null; |
| |
| } // createChildren(XMLContentSpec.Provider,int,XMLContentSpec,DocumentImpl,Element):Element |
| |
| /** Creates the children for the deferred element decl. */ |
| private int createChildren(XMLContentSpec.Provider provider, |
| int index, XMLContentSpec node, |
| DeferredDocumentImpl factory, |
| int parent) throws Exception { |
| |
| // get occurrence count |
| provider.getContentSpec(index, node); |
| int occurs = -1; |
| switch (node.type) { |
| case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: { |
| occurs = '+'; |
| provider.getContentSpec(node.value, node); |
| break; |
| } |
| case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: { |
| occurs = '*'; |
| provider.getContentSpec(node.value, node); |
| break; |
| } |
| case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: { |
| occurs = '?'; |
| provider.getContentSpec(node.value, node); |
| break; |
| } |
| } |
| |
| // flatten model |
| int nodeType = node.type; |
| switch (nodeType) { |
| |
| // CHOICE or SEQUENCE |
| case XMLContentSpec.CONTENTSPECNODE_CHOICE: |
| case XMLContentSpec.CONTENTSPECNODE_SEQ: { |
| |
| // go down left side |
| int leftIndex = node.value; |
| int rightIndex = node.otherValue; |
| int left = createChildren(provider, leftIndex, node, |
| factory, parent); |
| |
| // go down right side |
| int right = createChildren(provider, rightIndex, node, |
| factory, -1); |
| |
| // append left children |
| boolean choice = nodeType == XMLContentSpec.CONTENTSPECNODE_CHOICE; |
| int type = fStringPool.addSymbol(choice ? "choice" : "sequence"); |
| int model = left; |
| if (factory.getNodeName(left, false) != type) { |
| int minOccurs = factory.getAttribute(left, fStringPool.addSymbol("minOccurs")); |
| int maxOccurs = factory.getAttribute(left, fStringPool.addSymbol("maxOccurs")); |
| boolean min1 = minOccurs == -1 || fStringPool.toString(minOccurs).equals("1"); |
| boolean max1 = maxOccurs == -1 || fStringPool.toString(maxOccurs).equals("1"); |
| if (parent == -1 || (min1 && max1)) { |
| model = factory.createElement(type, null, -1); |
| factory.appendChild(model, left); |
| } |
| else { |
| model = parent; |
| } |
| } |
| |
| // set occurrence count |
| switch (occurs) { |
| case '+': { |
| int maxOccurs = factory.createAttribute(fStringPool.addSymbol("maxOccurs"), |
| fStringPool.addString("unbounded"), |
| true); |
| factory.setAttributeNode(model, maxOccurs); |
| break; |
| } |
| case '*': { |
| int minOccurs = factory.createAttribute(fStringPool.addSymbol("minOccurs"), |
| fStringPool.addString("0"), |
| true); |
| factory.setAttributeNode(model, minOccurs); |
| int maxOccurs = factory.createAttribute(fStringPool.addSymbol("maxOccurs"), |
| fStringPool.addString("unbounded"), |
| true); |
| factory.setAttributeNode(model, maxOccurs); |
| break; |
| } |
| case '?': { |
| int minOccurs = factory.createAttribute(fStringPool.addSymbol("minOccurs"), |
| fStringPool.addString("0"), |
| true); |
| factory.setAttributeNode(model, minOccurs); |
| break; |
| } |
| } |
| |
| // append right children |
| factory.appendChild(model, right); |
| |
| // return model |
| return model; |
| } |
| |
| // LEAF |
| case XMLContentSpec.CONTENTSPECNODE_LEAF: { |
| int handle = fAttrList.startAttrList(); |
| fAttrList.addAttr( |
| fStringPool.addSymbol("ref"), |
| fStringPool.addString(fStringPool.toString(node.value)), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); // search |
| switch (occurs) { |
| case '+': { |
| fAttrList.addAttr( |
| fStringPool.addSymbol("maxOccurs"), |
| fStringPool.addString("unbounded"), |
| fStringPool.addSymbol("CDATA"), |
| true, |
| false); // search |
| break; |
| } |
| case '*': { |
| fAttrList.addAttr( |
| fStringPool.addSymbol("minOccurs"), |
| fStringPool.addString("0"), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); // search |
| fAttrList.addAttr( |
| fStringPool.addSymbol("maxOccurs"), |
| fStringPool.addString("unbounded"), |
| fStringPool.addSymbol("CDATA"), |
| true, |
| false); // search |
| break; |
| } |
| case '?': { |
| fAttrList.addAttr( |
| fStringPool.addSymbol("minOccurs"), |
| fStringPool.addString("0"), |
| fStringPool.addSymbol("NMTOKEN"), |
| true, |
| false); // search |
| break; |
| } |
| } |
| fAttrList.endAttrList(); |
| int leaf = factory.createElement(fStringPool.addSymbol("element"), fAttrList, handle); |
| return leaf; |
| } |
| |
| } // switch node type |
| |
| // error |
| return -1; |
| |
| } // createChildren(XMLContentSpec.Provider,int,XMLContentSpec,DeferredDocumentImpl,int):int |
| |
| } // class DOMParser |