0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: *
0005: * Copyright (c) 1999,2000 The Apache Software Foundation. All rights
0006: * reserved.
0007: *
0008: * Redistribution and use in source and binary forms, with or without
0009: * modification, are permitted provided that the following conditions
0010: * are met:
0011: *
0012: * 1. Redistributions of source code must retain the above copyright
0013: * notice, this list of conditions and the following disclaimer.
0014: *
0015: * 2. Redistributions in binary form must reproduce the above copyright
0016: * notice, this list of conditions and the following disclaimer in
0017: * the documentation and/or other materials provided with the
0018: * distribution.
0019: *
0020: * 3. The end-user documentation included with the redistribution,
0021: * if any, must include the following acknowledgment:
0022: * "This product includes software developed by the
0023: * Apache Software Foundation (http://www.apache.org/)."
0024: * Alternately, this acknowledgment may appear in the software itself,
0025: * if and wherever such third-party acknowledgments normally appear.
0026: *
0027: * 4. The names "Xerces" and "Apache Software Foundation" must
0028: * not be used to endorse or promote products derived from this
0029: * software without prior written permission. For written
0030: * permission, please contact apache@apache.org.
0031: *
0032: * 5. Products derived from this software may not be called "Apache",
0033: * nor may "Apache" appear in their name, without prior written
0034: * permission of the Apache Software Foundation.
0035: *
0036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047: * SUCH DAMAGE.
0048: * ====================================================================
0049: *
0050: * This software consists of voluntary contributions made by many
0051: * individuals on behalf of the Apache Software Foundation and was
0052: * originally based on software copyright (c) 1999, International
0053: * Business Machines, Inc., http://www.apache.org. For more
0054: * information on the Apache Software Foundation, please see
0055: * <http://www.apache.org/>.
0056: */
0057:
0058: package org.apache.xerces.parsers;
0059:
0060: import java.io.IOException;
0061: import java.util.Enumeration;
0062: import java.util.Hashtable;
0063: import java.util.StringTokenizer;
0064:
0065: import org.apache.xerces.dom.TextImpl;
0066: import org.apache.xerces.framework.XMLAttrList;
0067: import org.apache.xerces.framework.XMLContentSpec;
0068: import org.apache.xerces.framework.XMLDocumentHandler;
0069: import org.apache.xerces.framework.XMLParser;
0070: import org.apache.xerces.readers.XMLEntityHandler;
0071: import org.apache.xerces.utils.QName;
0072: import org.apache.xerces.utils.StringPool;
0073: import org.apache.xerces.validators.common.XMLAttributeDecl;
0074: import org.apache.xerces.validators.common.XMLElementDecl;
0075: import org.apache.xerces.validators.schema.XUtil;
0076: import org.apache.xerces.validators.schema.SchemaSymbols;
0077:
0078: import org.apache.xerces.dom.DeferredDocumentImpl;
0079: import org.apache.xerces.dom.DocumentImpl;
0080: import org.apache.xerces.dom.DocumentTypeImpl;
0081: import org.apache.xerces.dom.NodeImpl;
0082: import org.apache.xerces.dom.EntityImpl;
0083: import org.apache.xerces.dom.NotationImpl;
0084: import org.apache.xerces.dom.ElementDefinitionImpl;
0085: import org.apache.xerces.dom.AttrImpl;
0086: import org.apache.xerces.dom.TextImpl;
0087: import org.apache.xerces.dom.ElementImpl;
0088: import org.apache.xerces.dom.EntityImpl;
0089:
0090: import org.w3c.dom.Attr;
0091: import org.w3c.dom.Comment;
0092: import org.w3c.dom.Document;
0093: import org.w3c.dom.DocumentType;
0094: import org.w3c.dom.Element;
0095: import org.w3c.dom.Entity;
0096: import org.w3c.dom.EntityReference;
0097: import org.w3c.dom.Node;
0098: import org.w3c.dom.NodeList;
0099: import org.w3c.dom.NamedNodeMap;
0100: import org.w3c.dom.ProcessingInstruction;
0101: import org.w3c.dom.Text;
0102:
0103: import org.xml.sax.SAXException;
0104: import org.xml.sax.SAXNotRecognizedException;
0105: import org.xml.sax.SAXNotSupportedException;
0106:
0107: /**
0108: * DOMParser provides a parser which produces a W3C DOM tree as its output
0109: *
0110: *
0111: * @version $Id: DOMParser.java,v 1.51 2001/07/09 19:29:09 sandygao Exp $
0112: */
0113: public class DOMParser extends XMLParser implements XMLDocumentHandler {
0114:
0115: //
0116: // Constants
0117: //
0118:
0119: // public
0120:
0121: /** Default programmatic document class name (org.apache.xerces.dom.DocumentImpl). */
0122: public static final String DEFAULT_DOCUMENT_CLASS_NAME = "org.apache.xerces.dom.DocumentImpl";
0123:
0124: /** Default deferred document class name (org.apache.xerces.dom.DeferredDocumentImpl). */
0125: public static final String DEFAULT_DEFERRED_DOCUMENT_CLASS_NAME = "org.apache.xerces.dom.DeferredDocumentImpl";
0126:
0127: // debugging
0128:
0129: /** Set to true to debug attribute list declaration calls. */
0130: private static final boolean DEBUG_ATTLIST_DECL = false;
0131:
0132: // features and properties
0133:
0134: /** Features recognized by this parser. */
0135: private static final String RECOGNIZED_FEATURES[] = {
0136: // SAX2 core features
0137: // Xerces features
0138: "http://apache.org/xml/features/dom/defer-node-expansion",
0139: "http://apache.org/xml/features/dom/create-entity-ref-nodes",
0140: "http://apache.org/xml/features/dom/include-ignorable-whitespace",
0141: // Experimental features
0142: "http://apache.org/xml/features/domx/grammar-access", };
0143:
0144: /** Properties recognized by this parser. */
0145: private static final String RECOGNIZED_PROPERTIES[] = {
0146: // SAX2 core properties
0147: // Xerces properties
0148: "http://apache.org/xml/properties/dom/document-class-name",
0149: "http://apache.org/xml/properties/dom/current-element-node", };
0150:
0151: //
0152: // Data
0153: //
0154:
0155: // common data
0156:
0157: protected Document fDocument;
0158:
0159: // deferred expansion data
0160:
0161: protected DeferredDocumentImpl fDeferredDocumentImpl;
0162: protected int fDocumentIndex;
0163: protected int fDocumentTypeIndex;
0164: protected int fCurrentNodeIndex;
0165:
0166: //DOM Level 3 WD - experimental
0167:
0168: protected int fCurrentEntityName; //name of current entity reference
0169: protected int fCurrentEntityNode; //index of entity node corresponding to current entity reference
0170:
0171: // full expansion data
0172:
0173: protected DocumentImpl fDocumentImpl;
0174: protected DocumentType fDocumentType;
0175: protected Node fCurrentElementNode;
0176:
0177: // state
0178:
0179: protected boolean fInDTD;
0180: protected boolean fWithinElement;
0181: protected boolean fInCDATA;
0182:
0183: // features
0184: private boolean fGrammarAccess;
0185:
0186: // properties
0187:
0188: // REVISIT: Even though these have setters and getters, should they
0189: // be protected visibility? -Ac
0190: private String fDocumentClassName;
0191: private boolean fDeferNodeExpansion;
0192: private boolean fCreateEntityReferenceNodes;
0193: private boolean fIncludeIgnorableWhitespace;
0194:
0195: // built-in entities
0196:
0197: protected int fAmpIndex;
0198: protected int fLtIndex;
0199: protected int fGtIndex;
0200: protected int fAposIndex;
0201: protected int fQuotIndex;
0202:
0203: private boolean fSeenRootElement;
0204:
0205: private boolean fStringPoolInUse;
0206:
0207: private XMLAttrList fAttrList;
0208:
0209: //
0210: // Constructors
0211: //
0212:
0213: /** Default constructor. */
0214: public DOMParser() {
0215:
0216: initHandlers(false, this , this );
0217:
0218: // setup parser state
0219: init();
0220:
0221: // set default values
0222: try {
0223: setDocumentClassName(DEFAULT_DOCUMENT_CLASS_NAME);
0224: setCreateEntityReferenceNodes(true);
0225: setDeferNodeExpansion(true);
0226: setIncludeIgnorableWhitespace(true);
0227: } catch (SAXException e) {
0228: throw new RuntimeException(
0229: "PAR001 Fatal error constructing DOMParser.");
0230: }
0231:
0232: } // <init>()
0233:
0234: //
0235: // Public methods
0236: //
0237:
0238: // document
0239:
0240: /** Returns the document. */
0241: public Document getDocument() {
0242: return fDocument;
0243: }
0244:
0245: // features and properties
0246:
0247: /**
0248: * Returns a list of features that this parser recognizes.
0249: * This method will never return null; if no features are
0250: * recognized, this method will return a zero length array.
0251: *
0252: * @see #isFeatureRecognized
0253: * @see #setFeature
0254: * @see #getFeature
0255: */
0256: public String[] getFeaturesRecognized() {
0257:
0258: // get features that super/this recognizes
0259: String super Recognized[] = super .getFeaturesRecognized();
0260: String this Recognized[] = RECOGNIZED_FEATURES;
0261:
0262: // is one or the other the empty set?
0263: int this Length = this Recognized.length;
0264: if (this Length == 0) {
0265: return super Recognized;
0266: }
0267: int super Length = super Recognized.length;
0268: if (super Length == 0) {
0269: return this Recognized;
0270: }
0271:
0272: // combine the two lists and return
0273: String recognized[] = new String[super Length + this Length];
0274: System
0275: .arraycopy(super Recognized, 0, recognized, 0,
0276: super Length);
0277: System.arraycopy(this Recognized, 0, recognized, super Length,
0278: this Length);
0279: return recognized;
0280:
0281: } // getFeaturesRecognized():String[]
0282:
0283: /**
0284: * Returns a list of properties that this parser recognizes.
0285: * This method will never return null; if no properties are
0286: * recognized, this method will return a zero length array.
0287: *
0288: * @see #isPropertyRecognized
0289: * @see #setProperty
0290: * @see #getProperty
0291: */
0292: public String[] getPropertiesRecognized() {
0293:
0294: // get properties that super/this recognizes
0295: String super Recognized[] = super .getPropertiesRecognized();
0296: String this Recognized[] = RECOGNIZED_PROPERTIES;
0297:
0298: // is one or the other the empty set?
0299: int this Length = this Recognized.length;
0300: if (this Length == 0) {
0301: return super Recognized;
0302: }
0303: int super Length = super Recognized.length;
0304: if (super Length == 0) {
0305: return this Recognized;
0306: }
0307:
0308: // combine the two lists and return
0309: String recognized[] = new String[super Length + this Length];
0310: System
0311: .arraycopy(super Recognized, 0, recognized, 0,
0312: super Length);
0313: System.arraycopy(this Recognized, 0, recognized, super Length,
0314: this Length);
0315: return recognized;
0316:
0317: }
0318:
0319: // resetting
0320:
0321: /** Resets the parser. */
0322: public void reset() throws Exception {
0323: if (fStringPoolInUse) {
0324: // we can't reuse the string pool, let's create another one
0325: fStringPool = new StringPool();
0326: fStringPoolInUse = false;
0327: }
0328: super .reset();
0329: init();
0330: }
0331:
0332: /** Resets or copies the parser. */
0333: public void resetOrCopy() throws Exception {
0334: super .resetOrCopy();
0335: init();
0336: }
0337:
0338: //
0339: // Protected methods
0340: //
0341:
0342: // initialization
0343:
0344: /**
0345: * Initializes the parser to a pre-parse state. This method is
0346: * called between calls to <code>parse()</code>.
0347: */
0348: protected void init() {
0349:
0350: // init common
0351: fDocument = null;
0352:
0353: // init deferred expansion
0354: fDeferredDocumentImpl = null;
0355: fDocumentIndex = -1;
0356: fDocumentTypeIndex = -1;
0357: fCurrentNodeIndex = -1;
0358:
0359: //DOM Level 3 WD - experimental
0360: fCurrentEntityNode = -1;
0361: fCurrentEntityName = -1;
0362:
0363: // init full expansion
0364: fDocumentImpl = null;
0365: fDocumentType = null;
0366: fCurrentElementNode = null;
0367:
0368: // state
0369: fInDTD = false;
0370: fWithinElement = false;
0371: fInCDATA = false;
0372:
0373: // built-in entities
0374: fAmpIndex = fStringPool.addSymbol("amp");
0375: fLtIndex = fStringPool.addSymbol("lt");
0376: fGtIndex = fStringPool.addSymbol("gt");
0377: fAposIndex = fStringPool.addSymbol("apos");
0378: fQuotIndex = fStringPool.addSymbol("quot");
0379:
0380: fSeenRootElement = false;
0381: fStringPoolInUse = false;
0382:
0383: fAttrList = new XMLAttrList(fStringPool);
0384:
0385: } // init()
0386:
0387: // features
0388:
0389: /**
0390: * This method sets whether the expansion of the nodes in the default
0391: * DOM implementation are deferred.
0392: *
0393: * @see #getDeferNodeExpansion
0394: * @see #setDocumentClassName
0395: */
0396: protected void setDeferNodeExpansion(boolean deferNodeExpansion)
0397: throws SAXNotRecognizedException, SAXNotSupportedException {
0398: fDeferNodeExpansion = deferNodeExpansion;
0399: }
0400:
0401: /**
0402: * Returns true if the expansion of the nodes in the default DOM
0403: * implementation are deferred.
0404: *
0405: * @see #setDeferNodeExpansion
0406: */
0407: protected boolean getDeferNodeExpansion()
0408: throws SAXNotRecognizedException, SAXNotSupportedException {
0409: return fDeferNodeExpansion;
0410: }
0411:
0412: /**
0413: * This feature determines whether entity references within
0414: * the document are included in the document tree as
0415: * EntityReference nodes.
0416: * <p>
0417: * Note: The children of the entity reference are always
0418: * added to the document. This feature only affects
0419: * whether an EntityReference node is also included
0420: * as the parent of the entity reference children.
0421: *
0422: * @param create True to create entity reference nodes; false
0423: * to only insert the entity reference children.
0424: *
0425: * @see #getCreateEntityReferenceNodes
0426: */
0427: protected void setCreateEntityReferenceNodes(boolean create)
0428: throws SAXNotRecognizedException, SAXNotSupportedException {
0429: fCreateEntityReferenceNodes = create;
0430: }
0431:
0432: /**
0433: * Returns true if entity references within the document are
0434: * included in the document tree as EntityReference nodes.
0435: *
0436: * @see #setCreateEntityReferenceNodes
0437: */
0438: public boolean getCreateEntityReferenceNodes()
0439: throws SAXNotRecognizedException, SAXNotSupportedException {
0440: return fCreateEntityReferenceNodes;
0441: }
0442:
0443: /**
0444: * This feature determines whether text nodes that can be
0445: * considered "ignorable whitespace" are included in the DOM
0446: * tree.
0447: * <p>
0448: * Note: The only way that the parser can determine if text
0449: * is ignorable is by reading the associated grammar
0450: * and having a content model for the document. When
0451: * ignorable whitespace text nodes *are* included in
0452: * the DOM tree, they will be flagged as ignorable.
0453: * The ignorable flag can be queried by calling the
0454: * TextImpl#isIgnorableWhitespace():boolean method.
0455: *
0456: * @param include True to include ignorable whitespace text nodes;
0457: * false to not include ignorable whitespace text
0458: * nodes.
0459: *
0460: * @see #getIncludeIgnorableWhitespace
0461: */
0462: public void setIncludeIgnorableWhitespace(boolean include)
0463: throws SAXNotRecognizedException, SAXNotSupportedException {
0464: fIncludeIgnorableWhitespace = include;
0465: }
0466:
0467: /**
0468: * Returns true if ignorable whitespace text nodes are included
0469: * in the DOM tree.
0470: *
0471: * @see #setIncludeIgnorableWhitespace
0472: */
0473: public boolean getIncludeIgnorableWhitespace()
0474: throws SAXNotRecognizedException, SAXNotSupportedException {
0475: return fIncludeIgnorableWhitespace;
0476: }
0477:
0478: // properties
0479:
0480: /**
0481: * This method allows the programmer to decide which document
0482: * factory to use when constructing the DOM tree. However, doing
0483: * so will lose the functionality of the default factory. Also,
0484: * a document class other than the default will lose the ability
0485: * to defer node expansion on the DOM tree produced.
0486: *
0487: * @param documentClassName The fully qualified class name of the
0488: * document factory to use when constructing
0489: * the DOM tree.
0490: *
0491: * @see #getDocumentClassName
0492: * @see #setDeferNodeExpansion
0493: * @see #DEFAULT_DOCUMENT_CLASS_NAME
0494: */
0495: protected void setDocumentClassName(String documentClassName)
0496: throws SAXNotRecognizedException, SAXNotSupportedException {
0497:
0498: // normalize class name
0499: if (documentClassName == null) {
0500: documentClassName = DEFAULT_DOCUMENT_CLASS_NAME;
0501: }
0502:
0503: // verify that this class exists and is of the right type
0504: try {
0505: Class _class = Class.forName(documentClassName);
0506: //if (!_class.isAssignableFrom(Document.class)) {
0507: if (!Document.class.isAssignableFrom(_class)) {
0508: throw new IllegalArgumentException("PAR002 Class, \""
0509: + documentClassName
0510: + "\", is not of type org.w3c.dom.Document."
0511: + "\n" + documentClassName);
0512: }
0513: } catch (ClassNotFoundException e) {
0514: throw new IllegalArgumentException("PAR003 Class, \""
0515: + documentClassName + "\", not found." + "\n"
0516: + documentClassName);
0517: }
0518:
0519: // set document class name
0520: fDocumentClassName = documentClassName;
0521: if (!documentClassName.equals(DEFAULT_DOCUMENT_CLASS_NAME)) {
0522: setDeferNodeExpansion(false);
0523: }
0524:
0525: } // setDocumentClassName(String)
0526:
0527: /**
0528: * Returns the fully qualified class name of the document factory
0529: * used when constructing the DOM tree.
0530: *
0531: * @see #setDocumentClassName
0532: */
0533: protected String getDocumentClassName()
0534: throws SAXNotRecognizedException, SAXNotSupportedException {
0535: return fDocumentClassName;
0536: }
0537:
0538: /**
0539: * Returns the current element node.
0540: * <p>
0541: * Note: This method is not supported when the "deferNodeExpansion"
0542: * property is set to true and the document factory is set to
0543: * the default factory.
0544: */
0545: protected Element getCurrentElementNode()
0546: throws SAXNotRecognizedException, SAXNotSupportedException {
0547:
0548: if (fCurrentElementNode != null
0549: && fCurrentElementNode.getNodeType() == Node.ELEMENT_NODE) {
0550: return (Element) fCurrentElementNode;
0551: }
0552: return null;
0553:
0554: } // getCurrentElementNode():Element
0555:
0556: //
0557: // Configurable methods
0558: //
0559:
0560: /**
0561: * Set the state of any feature in a SAX2 parser. The parser
0562: * might not recognize the feature, and if it does recognize
0563: * it, it might not be able to fulfill the request.
0564: *
0565: * @param featureId The unique identifier (URI) of the feature.
0566: * @param state The requested state of the feature (true or false).
0567: *
0568: * @exception SAXNotRecognizedException If the requested feature is
0569: * not known.
0570: * @exception SAXNotSupportedException If the requested feature is
0571: * known, but the requested state
0572: * is not supported.
0573: */
0574: public void setFeature(String featureId, boolean state)
0575: throws SAXNotRecognizedException, SAXNotSupportedException {
0576:
0577: //
0578: // SAX2 core features
0579: //
0580:
0581: if (featureId.startsWith(SAX2_FEATURES_PREFIX)) {
0582: //
0583: // No additional SAX properties defined for DOMParser.
0584: // Pass request off to XMLParser for the common cases.
0585: //
0586: }
0587:
0588: //
0589: // Xerces features
0590: //
0591:
0592: else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) {
0593: String feature = featureId.substring(XERCES_FEATURES_PREFIX
0594: .length());
0595: //
0596: // http://apache.org/xml/features/dom/defer-node-expansion
0597: // Allows the document tree returned by getDocument()
0598: // to be constructed lazily. In other words, the DOM
0599: // nodes are constructed as the tree is traversed.
0600: // This allows the document to be returned sooner with
0601: // the expense of holding all of the blocks of character
0602: // data held in memory. Then again, lots of DOM nodes
0603: // use a lot of memory as well.
0604: //
0605: if (feature.equals("dom/defer-node-expansion")) {
0606: if (fParseInProgress) {
0607: throw new SAXNotSupportedException(
0608: "PAR004 Cannot setFeature(" + featureId
0609: + "): parse is in progress." + "\n"
0610: + featureId);
0611: }
0612: setDeferNodeExpansion(state);
0613: return;
0614: }
0615: //
0616: // http://apache.org/xml/features/dom/create-entity-ref-nodes
0617: // This feature determines whether entity references within
0618: // the document are included in the document tree as
0619: // EntityReference nodes.
0620: // Note: The children of the entity reference are always
0621: // added to the document. This feature only affects
0622: // whether an EntityReference node is also included
0623: // as the parent of the entity reference children.
0624: //
0625: if (feature.equals("dom/create-entity-ref-nodes")) {
0626: setCreateEntityReferenceNodes(state);
0627: return;
0628: }
0629:
0630: //
0631: // http://apache.org/xml/features/dom/include-ignorable-whitespace
0632: // This feature determines whether text nodes that can be
0633: // considered "ignorable whitespace" are included in the DOM
0634: // tree.
0635: // Note: The only way that the parser can determine if text
0636: // is ignorable is by reading the associated grammar
0637: // and having a content model for the document. When
0638: // ignorable whitespace text nodes *are* included in
0639: // the DOM tree, they will be flagged as ignorable.
0640: // The ignorable flag can be queried by calling the
0641: // TextImpl#isIgnorableWhitespace():boolean method.
0642: //
0643: if (feature.equals("dom/include-ignorable-whitespace")) {
0644: setIncludeIgnorableWhitespace(state);
0645: return;
0646: }
0647:
0648: //
0649: // Experimental features
0650: //
0651:
0652: //
0653: // http://apache.org/xml/features/domx/grammar-access
0654: // Allows grammar access in the DOM tree. Currently, this
0655: // means that there is an XML Schema document tree as a
0656: // child of the Doctype node.
0657: //
0658: if (feature.equals("domx/grammar-access")) {
0659: fGrammarAccess = state;
0660: return;
0661: }
0662:
0663: //
0664: // Pass request off to XMLParser for the common cases.
0665: //
0666: }
0667:
0668: //
0669: // Pass request off to XMLParser for the common cases.
0670: //
0671: super .setFeature(featureId, state);
0672:
0673: } // setFeature(String,boolean)
0674:
0675: /**
0676: * Query the current state of any feature in a SAX2 parser. The
0677: * parser might not recognize the feature.
0678: *
0679: * @param featureId The unique identifier (URI) of the feature
0680: * being set.
0681: *
0682: * @return The current state of the feature.
0683: *
0684: * @exception SAXNotRecognizedException If the requested feature is
0685: * not known.
0686: */
0687: public boolean getFeature(String featureId)
0688: throws SAXNotRecognizedException, SAXNotSupportedException {
0689:
0690: //
0691: // SAX2 core features
0692: //
0693:
0694: if (featureId.startsWith(SAX2_FEATURES_PREFIX)) {
0695: //
0696: // No additional SAX properties defined for DOMParser.
0697: // Pass request off to XMLParser for the common cases.
0698: //
0699: }
0700:
0701: //
0702: // Xerces features
0703: //
0704:
0705: else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) {
0706: String feature = featureId.substring(XERCES_FEATURES_PREFIX
0707: .length());
0708: //
0709: // http://apache.org/xml/features/dom/defer-node-expansion
0710: // Allows the document tree returned by getDocument()
0711: // to be constructed lazily. In other words, the DOM
0712: // nodes are constructed as the tree is traversed.
0713: // This allows the document to be returned sooner with
0714: // the expense of holding all of the blocks of character
0715: // data held in memory. Then again, lots of DOM nodes
0716: // use a lot of memory as well.
0717: //
0718: if (feature.equals("dom/defer-node-expansion")) {
0719: return getDeferNodeExpansion();
0720: }
0721: //
0722: // http://apache.org/xml/features/dom/create-entity-ref-nodes
0723: // This feature determines whether entity references within
0724: // the document are included in the document tree as
0725: // EntityReference nodes.
0726: // Note: The children of the entity reference are always
0727: // added to the document. This feature only affects
0728: // whether an EntityReference node is also included
0729: // as the parent of the entity reference children.
0730: //
0731: else if (feature.equals("dom/create-entity-ref-nodes")) {
0732: return getCreateEntityReferenceNodes();
0733: }
0734:
0735: //
0736: // http://apache.org/xml/features/dom/include-ignorable-whitespace
0737: // This feature determines whether text nodes that can be
0738: // considered "ignorable whitespace" are included in the DOM
0739: // tree.
0740: // Note: The only way that the parser can determine if text
0741: // is ignorable is by reading the associated grammar
0742: // and having a content model for the document. When
0743: // ignorable whitespace text nodes *are* included in
0744: // the DOM tree, they will be flagged as ignorable.
0745: // The ignorable flag can be queried by calling the
0746: // TextImpl#isIgnorableWhitespace():boolean method.
0747: //
0748: if (feature.equals("dom/include-ignorable-whitespace")) {
0749: return getIncludeIgnorableWhitespace();
0750: }
0751:
0752: //
0753: // Experimental features
0754: //
0755:
0756: //
0757: // http://apache.org/xml/features/domx/grammar-access
0758: // Allows grammar access in the DOM tree. Currently, this
0759: // means that there is an XML Schema document tree as a
0760: // child of the Doctype node.
0761: //
0762: if (feature.equals("domx/grammar-access")) {
0763: return fGrammarAccess;
0764: }
0765:
0766: //
0767: // Pass request off to XMLParser for the common cases.
0768: //
0769: }
0770:
0771: //
0772: // Pass request off to XMLParser for the common cases.
0773: //
0774: return super .getFeature(featureId);
0775:
0776: } // getFeature(String):boolean
0777:
0778: /**
0779: * Set the value of any property in a SAX2 parser. The parser
0780: * might not recognize the property, and if it does recognize
0781: * it, it might not support the requested value.
0782: *
0783: * @param propertyId The unique identifier (URI) of the property
0784: * being set.
0785: * @param Object The value to which the property is being set.
0786: *
0787: * @exception SAXNotRecognizedException If the requested property is
0788: * not known.
0789: * @exception SAXNotSupportedException If the requested property is
0790: * known, but the requested
0791: * value is not supported.
0792: */
0793: public void setProperty(String propertyId, Object value)
0794: throws SAXNotRecognizedException, SAXNotSupportedException {
0795:
0796: //
0797: // Xerces properties
0798: //
0799:
0800: if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) {
0801: String property = propertyId
0802: .substring(XERCES_PROPERTIES_PREFIX.length());
0803: //
0804: // http://apache.org/xml/properties/dom/current-element-node
0805: // Returns the current element node as the DOM Parser is
0806: // parsing. This property is useful for determining the
0807: // relative location of the document when an error is
0808: // encountered. Note that this feature does *not* work
0809: // when the http://apache.org/xml/features/dom/defer-node-expansion
0810: // is set to true.
0811: //
0812: if (property.equals("dom/current-element-node")) {
0813: throw new SAXNotSupportedException(
0814: "PAR005 Property, \"" + propertyId
0815: + "\" is read-only.\n" + propertyId);
0816: }
0817: //
0818: // http://apache.org/xml/properties/dom/document-class-name
0819: // This property can be used to set/query the name of the
0820: // document factory.
0821: //
0822: else if (property.equals("dom/document-class-name")) {
0823: if (value != null && !(value instanceof String)) {
0824: throw new SAXNotSupportedException(
0825: "PAR006 Property value must be of type java.lang.String.");
0826: }
0827: setDocumentClassName((String) value);
0828: return;
0829: }
0830: }
0831:
0832: //
0833: // Pass request off to XMLParser for the common cases.
0834: //
0835: super .setProperty(propertyId, value);
0836:
0837: } // setProperty(String,Object)
0838:
0839: /**
0840: * Return the current value of a property in a SAX2 parser.
0841: * The parser might not recognize the property.
0842: *
0843: * @param propertyId The unique identifier (URI) of the property
0844: * being set.
0845: *
0846: * @return The current value of the property.
0847: *
0848: * @exception SAXNotRecognizedException If the requested property is
0849: * not known.
0850: *
0851: * @see Configurable#getProperty
0852: */
0853: public Object getProperty(String propertyId)
0854: throws SAXNotRecognizedException, SAXNotSupportedException {
0855:
0856: //
0857: // Xerces properties
0858: //
0859:
0860: if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) {
0861: String property = propertyId
0862: .substring(XERCES_PROPERTIES_PREFIX.length());
0863: //
0864: // http://apache.org/xml/properties/dom/current-element-node
0865: // Returns the current element node as the DOM Parser is
0866: // parsing. This property is useful for determining the
0867: // relative location of the document when an error is
0868: // encountered. Note that this feature does *not* work
0869: // when the http://apache.org/xml/features/dom/defer-node-expansion
0870: // is set to true.
0871: //
0872: if (property.equals("dom/current-element-node")) {
0873: boolean throwException = false;
0874: try {
0875: throwException = getFeature(XERCES_FEATURES_PREFIX
0876: + "dom/defer-node-expansion");
0877: } catch (SAXNotSupportedException e) {
0878: // ignore
0879: } catch (SAXNotRecognizedException e) {
0880: // ignore
0881: }
0882: if (throwException) {
0883: throw new SAXNotSupportedException(
0884: "PAR007 Current element node cannot be queried when node expansion is deferred.");
0885: }
0886: return getCurrentElementNode();
0887: }
0888: //
0889: // http://apache.org/xml/properties/dom/document-class-name
0890: // This property can be used to set/query the name of the
0891: // document factory.
0892: //
0893: else if (property.equals("dom/document-class-name")) {
0894: return getDocumentClassName();
0895: }
0896: }
0897:
0898: //
0899: // Pass request off to XMLParser for the common cases.
0900: //
0901: return super .getProperty(propertyId);
0902:
0903: } // getProperty(String):Object
0904:
0905: //
0906: // XMLParser methods
0907: //
0908:
0909: /** Start document. */
0910: public void startDocument() {
0911:
0912: // deferred expansion
0913: String documentClassName = null;
0914: try {
0915: documentClassName = getDocumentClassName();
0916: } catch (SAXException e) {
0917: throw new RuntimeException(
0918: "PAR008 Fatal error getting document factory.");
0919: }
0920: boolean deferNodeExpansion = true;
0921: try {
0922: deferNodeExpansion = getDeferNodeExpansion();
0923: } catch (SAXException e) {
0924: throw new RuntimeException(
0925: "PAR009 Fatal error reading expansion mode.");
0926: }
0927: try {
0928: boolean isDocumentImpl = fDocumentClassName
0929: .equals(DEFAULT_DOCUMENT_CLASS_NAME);
0930: boolean isDeferredImpl = fDocumentClassName
0931: .equals(DEFAULT_DEFERRED_DOCUMENT_CLASS_NAME);
0932: if (deferNodeExpansion
0933: && (isDocumentImpl || isDeferredImpl)) {
0934: boolean nsEnabled = false;
0935: try {
0936: nsEnabled = getNamespaces();
0937: } catch (SAXException s) {
0938: }
0939: fDeferredDocumentImpl = new DeferredDocumentImpl(
0940: fStringPool, nsEnabled, fGrammarAccess);
0941: fStringPoolInUse = true;
0942: fDocument = fDeferredDocumentImpl;
0943: fDocumentIndex = fDeferredDocumentImpl.createDocument();
0944: fCurrentNodeIndex = fDocumentIndex;
0945: }
0946:
0947: // full expansion
0948: else {
0949: if (isDocumentImpl) {
0950: fDocumentImpl = new DocumentImpl(fGrammarAccess);
0951: fDocument = fDocumentImpl;
0952: // set DOM error checking off
0953: fDocumentImpl.setErrorChecking(false);
0954: } else {
0955: Class documentClass = Class
0956: .forName(documentClassName);
0957: try {
0958: fDocument = (Document) documentClass
0959: .newInstance();
0960: } catch (Exception e) {
0961: // REVISIT: Localize this message.
0962: throw new RuntimeException(
0963: "Failed to create document object of class: "
0964: + documentClassName);
0965: }
0966: // if subclass of our own class that's cool too
0967: Class defaultDocClass = Class
0968: .forName(DEFAULT_DOCUMENT_CLASS_NAME);
0969: if (defaultDocClass.isAssignableFrom(documentClass)) {
0970: fDocumentImpl = (DocumentImpl) fDocument;
0971: // set DOM error checking off
0972: fDocumentImpl.setErrorChecking(false);
0973: }
0974: }
0975: fCurrentElementNode = fDocument;
0976: }
0977: } catch (ClassNotFoundException e) {
0978: // REVISIT: Localize this message.
0979: throw new RuntimeException(documentClassName);
0980: }
0981:
0982: } // startDocument()
0983:
0984: /** End document. */
0985: public void endDocument() throws Exception {
0986: // set DOM error checking back on
0987: if (fDocumentImpl != null) {
0988: fDocumentImpl.setErrorChecking(true);
0989:
0990: if (fDocumentType != null) {
0991: // set entities and notations read_only per DOM spec
0992: ((DocumentTypeImpl) fDocumentType).setReadOnly(true,
0993: false);
0994: }
0995: }
0996: }
0997:
0998: /** XML declaration. */
0999: public void xmlDecl(int versionIndex, int encodingIndex,
1000: int standaloneIndex) throws Exception {
1001: boolean standalone = (standaloneIndex != -1) ? (fStringPool
1002: .toString(standaloneIndex).equals("yes")) ? true
1003: : false : false;
1004: if (fDocumentImpl != null) { //full node expansion
1005: fDocumentImpl
1006: .setVersion(fStringPool.toString(versionIndex));
1007: fDocumentImpl.setEncoding(fStringPool
1008: .toString(encodingIndex));
1009: fDocumentImpl.setStandalone(standalone);
1010: } else if (fDeferredDocumentImpl != null) {
1011: fDeferredDocumentImpl.setVersion(fStringPool
1012: .toString(versionIndex));
1013: fDeferredDocumentImpl.setEncoding(fStringPool
1014: .toString(encodingIndex));
1015: fDeferredDocumentImpl.setStandalone(standalone);
1016: } else {
1017: //non xerces implementation
1018: }
1019:
1020: }
1021:
1022: /** Text declaration.
1023: * added DOM Level 3 WD support - experimental
1024: */
1025: public void textDecl(int versionIndex, int encodingIndex)
1026: throws Exception {
1027: if (fDeferredDocumentImpl != null) {
1028: String name = fStringPool.toString(fCurrentEntityName);
1029: // we only support one context for entity references (name !=null)
1030: if (fDocumentTypeIndex != -1 && name != null) {
1031: // find Entity decl for fCurrentEntityName.
1032: int entityDecl = fDeferredDocumentImpl.getLastChild(
1033: fDocumentTypeIndex, false);
1034: while (entityDecl != -1) {
1035: if (fDeferredDocumentImpl.getNodeType(entityDecl,
1036: false) == Node.ENTITY_NODE
1037: && fDeferredDocumentImpl.getNodeNameString(
1038: entityDecl, false).equals(name)) {
1039: break;
1040: }
1041: entityDecl = fDeferredDocumentImpl.getPrevSibling(
1042: entityDecl, false);
1043: }
1044: fCurrentEntityNode = entityDecl;
1045: fDeferredDocumentImpl.setEntityInfo(entityDecl,
1046: versionIndex, encodingIndex);
1047: }
1048: }
1049: // full node expansion
1050: else if (fDocumentImpl != null) {
1051: NamedNodeMap entities = fDocumentType.getEntities();
1052: if (entities != null) {
1053: EntityImpl entityNode = (EntityImpl) entities
1054: .getNamedItem(fCurrentElementNode.getNodeName());
1055: if (entityNode != null) {
1056: entityNode.setVersion(fStringPool
1057: .toString(versionIndex));
1058: entityNode.setEncoding(fStringPool
1059: .toString(encodingIndex));
1060: }
1061: }
1062: } else {
1063: //non xerces implementation
1064: }
1065: }
1066:
1067: /** Report the start of the scope of a namespace declaration. */
1068: public void startNamespaceDeclScope(int prefix, int uri)
1069: throws Exception {
1070: }
1071:
1072: /** Report the end of the scope of a namespace declaration. */
1073: public void endNamespaceDeclScope(int prefix) throws Exception {
1074: }
1075:
1076: /** Start element. */
1077: public void startElement(QName elementQName,
1078: XMLAttrList xmlAttrList, int attrListIndex)
1079: throws Exception {
1080:
1081: // deferred expansion
1082: if (fDeferredDocumentImpl != null) {
1083:
1084: // copy schema grammar, if needed
1085: if (!fSeenRootElement) {
1086: fSeenRootElement = true;
1087: // REVISIT: How do we know which grammar is in use?
1088: //Document schemaDocument = fValidator.getSchemaDocument();
1089: if (fGrammarAccess && fGrammarResolver.size() > 0) {
1090: if (fDocumentTypeIndex == -1) {
1091: fDocumentTypeIndex = fDeferredDocumentImpl
1092: .createDocumentType(
1093: elementQName.rawname, -1, -1);
1094: fDeferredDocumentImpl.appendChild(0,
1095: fDocumentTypeIndex);
1096: }
1097: Enumeration schemas = fGrammarResolver
1098: .nameSpaceKeys();
1099: Document schemaDocument = fGrammarResolver
1100: .getGrammar((String) schemas.nextElement())
1101: .getGrammarDocument();
1102: if (schemaDocument != null) {
1103: Element schema = schemaDocument
1104: .getDocumentElement();
1105: copyInto(schema, fDocumentTypeIndex);
1106: }
1107: }
1108: }
1109:
1110: int element = fDeferredDocumentImpl.createElement(
1111: elementQName.rawname, elementQName.uri,
1112: xmlAttrList, attrListIndex);
1113: fDeferredDocumentImpl.appendChild(fCurrentNodeIndex,
1114: element);
1115: fCurrentNodeIndex = element;
1116: fWithinElement = true;
1117:
1118: // identifier registration
1119: int index = xmlAttrList.getFirstAttr(attrListIndex);
1120: while (index != -1) {
1121: if (xmlAttrList.getAttType(index) == fStringPool
1122: .addSymbol("ID")) {
1123: int nameIndex = xmlAttrList.getAttValue(index);
1124: fDeferredDocumentImpl.putIdentifier(nameIndex,
1125: element);
1126: }
1127: index = xmlAttrList.getNextAttr(index);
1128: }
1129: }
1130:
1131: // full expansion
1132: else {
1133:
1134: boolean nsEnabled = false;
1135: try {
1136: nsEnabled = getNamespaces();
1137: } catch (SAXException s) {
1138: }
1139:
1140: String elementName = fStringPool
1141: .toString(elementQName.rawname);
1142:
1143: // copy schema grammar, if needed
1144: if (!fSeenRootElement) {
1145: fSeenRootElement = true;
1146: if (fDocumentImpl != null && fGrammarAccess
1147: && fGrammarResolver.size() > 0) {
1148: if (fDocumentType == null) {
1149: String rootName = elementName;
1150: String systemId = ""; // REVISIT: How do we get this value? -Ac
1151: String publicId = ""; // REVISIT: How do we get this value? -Ac
1152: fDocumentType = fDocumentImpl
1153: .createDocumentType(rootName, publicId,
1154: systemId);
1155: fDocument.appendChild(fDocumentType);
1156: // REVISIT: We could use introspection to get the
1157: // DOMImplementation#createDocumentType method
1158: // for DOM Level 2 implementations. The only
1159: // problem is that the owner document for the
1160: // node created is null. How does it get set
1161: // for document when appended? A cursory look
1162: // at the DOM Level 2 CR didn't yield any
1163: // information. -Ac
1164: }
1165: Enumeration schemas = fGrammarResolver
1166: .nameSpaceKeys();
1167: Document schemaDocument = fGrammarResolver
1168: .getGrammar((String) schemas.nextElement())
1169: .getGrammarDocument();
1170: if (schemaDocument != null) {
1171: Element schema = schemaDocument
1172: .getDocumentElement();
1173: XUtil.copyInto(schema, fDocumentType);
1174: }
1175: }
1176: }
1177:
1178: Element e;
1179: if (nsEnabled) {
1180: String namespaceURI = fStringPool
1181: .toString(elementQName.uri);
1182: // hide the fact that our parser uses an empty string for null
1183: if (namespaceURI.length() == 0) {
1184: namespaceURI = null;
1185: }
1186: e = fDocument
1187: .createElementNS(namespaceURI, elementName);
1188: } else {
1189: e = fDocument.createElement(elementName);
1190: }
1191: int attrHandle = xmlAttrList.getFirstAttr(attrListIndex);
1192: while (attrHandle != -1) {
1193: int attName = xmlAttrList.getAttrName(attrHandle);
1194: String attrName = fStringPool.toString(attName);
1195: String attrValue = fStringPool.toString(xmlAttrList
1196: .getAttValue(attrHandle));
1197: if (nsEnabled) {
1198: int nsURIIndex = xmlAttrList.getAttrURI(attrHandle);
1199: String namespaceURI = fStringPool
1200: .toString(nsURIIndex);
1201: // DOM Level 2 wants all namespace declaration attributes
1202: // to be bound to "http://www.w3.org/2000/xmlns/"
1203: // So as long as the XML parser doesn't do it, it needs to
1204: // done here.
1205: int prefixIndex = xmlAttrList
1206: .getAttrPrefix(attrHandle);
1207: String prefix = fStringPool.toString(prefixIndex);
1208: // hide that our parser uses an empty string for null
1209: if (namespaceURI.length() == 0) {
1210: namespaceURI = null;
1211: }
1212: if (namespaceURI == null) {
1213: if (prefix != null) {
1214: if (prefix.equals("xmlns")) {
1215: namespaceURI = "http://www.w3.org/2000/xmlns/";
1216: }
1217: } else if (attrName.equals("xmlns")) {
1218: namespaceURI = "http://www.w3.org/2000/xmlns/";
1219: }
1220: }
1221: e.setAttributeNS(namespaceURI, attrName, attrValue);
1222: } else {
1223: e.setAttribute(attrName, attrValue);
1224: }
1225: if (fDocumentImpl != null
1226: && !xmlAttrList.isSpecified(attrHandle)) {
1227: ((AttrImpl) e.getAttributeNode(attrName))
1228: .setSpecified(false);
1229: }
1230: attrHandle = xmlAttrList.getNextAttr(attrHandle);
1231: }
1232: fCurrentElementNode.appendChild(e);
1233: fCurrentElementNode = e;
1234: fWithinElement = true;
1235:
1236: // identifier registration
1237: if (fDocumentImpl != null) {
1238: int index = xmlAttrList.getFirstAttr(attrListIndex);
1239: while (index != -1) {
1240: if (xmlAttrList.getAttType(index) == fStringPool
1241: .addSymbol("ID")) {
1242: String name = fStringPool.toString(xmlAttrList
1243: .getAttValue(index));
1244: fDocumentImpl.putIdentifier(name, e);
1245: }
1246: index = xmlAttrList.getNextAttr(index);
1247: }
1248: }
1249:
1250: // release attributes
1251: xmlAttrList.releaseAttrList(attrListIndex);
1252: }
1253:
1254: } // startElement(QName,XMLAttrList,int)
1255:
1256: /** End element. */
1257: public void endElement(QName elementQName) throws Exception {
1258:
1259: // deferred node expansion
1260: if (fDeferredDocumentImpl != null) {
1261: fCurrentNodeIndex = fDeferredDocumentImpl.getParentNode(
1262: fCurrentNodeIndex, false);
1263: fWithinElement = false;
1264: }
1265:
1266: // full node expansion
1267: else {
1268: fCurrentElementNode = fCurrentElementNode.getParentNode();
1269: fWithinElement = false;
1270: }
1271:
1272: } // endElement(QName)
1273:
1274: /** Characters. */
1275: public void characters(int dataIndex) throws Exception {
1276:
1277: // deferred node expansion
1278: if (fDeferredDocumentImpl != null) {
1279:
1280: int text;
1281:
1282: if (fInCDATA) {
1283: text = fDeferredDocumentImpl.createCDATASection(
1284: dataIndex, false);
1285: } else {
1286: // The Text normalization is taken care of within the Text Node
1287: // in the DEFERRED case.
1288: text = fDeferredDocumentImpl.createTextNode(dataIndex,
1289: false);
1290: }
1291: fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, text);
1292: }
1293:
1294: // full node expansion
1295: else {
1296:
1297: Text text;
1298:
1299: if (fInCDATA) {
1300: text = fDocument.createCDATASection(fStringPool
1301: .orphanString(dataIndex));
1302: } else {
1303:
1304: if (fWithinElement
1305: && fCurrentElementNode.getNodeType() == Node.ELEMENT_NODE) {
1306: Node lastChild = fCurrentElementNode.getLastChild();
1307: if (lastChild != null
1308: && lastChild.getNodeType() == Node.TEXT_NODE) {
1309: // Normalization of Text Nodes - append rather than create.
1310: ((Text) lastChild).appendData(fStringPool
1311: .orphanString(dataIndex));
1312: return;
1313: }
1314: }
1315: text = fDocument.createTextNode(fStringPool
1316: .orphanString(dataIndex));
1317: }
1318:
1319: fCurrentElementNode.appendChild(text);
1320:
1321: }
1322:
1323: } // characters(int)
1324:
1325: /** Ignorable whitespace. */
1326: public void ignorableWhitespace(int dataIndex) throws Exception {
1327:
1328: // ignore the whitespace
1329: if (!fIncludeIgnorableWhitespace) {
1330: fStringPool.orphanString(dataIndex);
1331: return;
1332: }
1333:
1334: // deferred node expansion
1335: if (fDeferredDocumentImpl != null) {
1336:
1337: int text;
1338:
1339: if (fInCDATA) {
1340: text = fDeferredDocumentImpl.createCDATASection(
1341: dataIndex, true);
1342: } else {
1343: // The Text normalization is taken care of within the Text Node
1344: // in the DEFERRED case.
1345: text = fDeferredDocumentImpl.createTextNode(dataIndex,
1346: true);
1347: }
1348: fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, text);
1349: }
1350:
1351: // full node expansion
1352: else {
1353:
1354: Text text;
1355:
1356: if (fInCDATA) {
1357: text = fDocument.createCDATASection(fStringPool
1358: .orphanString(dataIndex));
1359: } else {
1360:
1361: if (fWithinElement
1362: && fCurrentElementNode.getNodeType() == Node.ELEMENT_NODE) {
1363: Node lastChild = fCurrentElementNode.getLastChild();
1364: if (lastChild != null
1365: && lastChild.getNodeType() == Node.TEXT_NODE) {
1366: // Normalization of Text Nodes - append rather than create.
1367: ((Text) lastChild).appendData(fStringPool
1368: .orphanString(dataIndex));
1369: return;
1370: }
1371: }
1372: text = fDocument.createTextNode(fStringPool
1373: .orphanString(dataIndex));
1374: }
1375:
1376: if (fDocumentImpl != null) {
1377: ((TextImpl) text).setIgnorableWhitespace(true);
1378: }
1379:
1380: fCurrentElementNode.appendChild(text);
1381:
1382: }
1383:
1384: } // ignorableWhitespace(int)
1385:
1386: /** Processing instruction. */
1387: public void processingInstruction(int targetIndex, int dataIndex)
1388: throws Exception {
1389:
1390: // deferred node expansion
1391: if (fDeferredDocumentImpl != null) {
1392: int pi = fDeferredDocumentImpl.createProcessingInstruction(
1393: targetIndex, dataIndex);
1394: fDeferredDocumentImpl.appendChild(fCurrentNodeIndex, pi);
1395: }
1396:
1397: // full node expansion
1398: else {
1399: String target = fStringPool.orphanString(targetIndex);
1400: String data = fStringPool.orphanString(dataIndex);
1401: ProcessingInstruction pi = fDocument
1402: .createProcessingInstruction(target, data);
1403: fCurrentElementNode.appendChild(pi);
1404: }
1405:
1406: } // processingInstruction(int,int)
1407:
1408: /** Comment. */
1409: public void comment(int dataIndex) throws Exception {
1410:
1411: if (fInDTD && !fGrammarAccess) {
1412: fStringPool.orphanString(dataIndex);
1413: } else {
1414: // deferred node expansion
1415: if (fDeferredDocumentImpl != null) {
1416: int comment = fDeferredDocumentImpl
1417: .createComment(dataIndex);
1418: fDeferredDocumentImpl.appendChild(fCurrentNodeIndex,
1419: comment);
1420: }
1421:
1422: // full node expansion
1423: else {
1424: Comment comment = fDocument.createComment(fStringPool
1425: .orphanString(dataIndex));
1426: fCurrentElementNode.appendChild(comment);
1427: }
1428: }
1429:
1430: } // comment(int)
1431:
1432: // Callers who know they're interacting with this parser should use
1433: // characters(int); callers who don't know which parser they
1434: // are interacting with, or who can't be sure of sharing
1435: // the same stringPool, should use this method.
1436: public void characters(char ch[], int start, int length)
1437: throws Exception {
1438: characters(fStringPool.addSymbol(new String(ch, start, length)));
1439: } // characters(char[], int, int)
1440:
1441: /** Not called. */
1442: public void ignorableWhitespace(char ch[], int start, int length)
1443: throws Exception {
1444: }
1445:
1446: //
1447: // XMLDocumentScanner methods
1448: //
1449:
1450: /** Start CDATA section. */
1451: public void startCDATA() throws Exception {
1452: fInCDATA = true;
1453: }
1454:
1455: /** End CDATA section. */
1456: public void endCDATA() throws Exception {
1457: fInCDATA = false;
1458: }
1459:
1460: //
1461: // XMLEntityHandler methods
1462: //
1463:
1464: /** Start entity reference. */
1465: public void startEntityReference(int entityName, int entityType,
1466: int entityContext) throws Exception {
1467:
1468: fCurrentEntityName = entityName;
1469: // are we ignoring entity reference nodes?
1470: if (!fCreateEntityReferenceNodes) {
1471: return;
1472: }
1473:
1474: // ignore built-in entities
1475: if (entityName == fAmpIndex || entityName == fGtIndex
1476: || entityName == fLtIndex || entityName == fAposIndex
1477: || entityName == fQuotIndex) {
1478: return;
1479: }
1480:
1481: // we only support one context for entity references right now...
1482: if (entityContext != XMLEntityHandler.ENTITYREF_IN_CONTENT) {
1483: return;
1484: }
1485:
1486: // deferred node expansion
1487:
1488: if (fDeferredDocumentImpl != null) {
1489:
1490: int entityRefIndex = fDeferredDocumentImpl
1491: .createEntityReference(entityName);
1492: fDeferredDocumentImpl.appendChild(fCurrentNodeIndex,
1493: entityRefIndex);
1494:
1495: fCurrentNodeIndex = entityRefIndex;
1496:
1497: }
1498:
1499: // full node expansion
1500: else {
1501:
1502: EntityReference er = fDocument
1503: .createEntityReference(fStringPool
1504: .toString(entityName));
1505:
1506: fCurrentElementNode.appendChild(er);
1507: fCurrentElementNode = er;
1508: }
1509:
1510: } // startEntityReference(int,int,int)
1511:
1512: /** End entity reference. */
1513: public void endEntityReference(int entityName, int entityType,
1514: int entityContext) throws Exception {
1515: // are we ignoring entity reference nodes?
1516: if (!fCreateEntityReferenceNodes) {
1517: return;
1518: }
1519:
1520: // ignore built-in entities
1521: if (entityName == fAmpIndex || entityName == fGtIndex
1522: || entityName == fLtIndex || entityName == fAposIndex
1523: || entityName == fQuotIndex) {
1524: return;
1525: }
1526:
1527: // we only support one context for entity references right now...
1528: if (entityContext != XMLEntityHandler.ENTITYREF_IN_CONTENT) {
1529: return;
1530: }
1531:
1532: // deferred node expansion
1533: if (fDeferredDocumentImpl != null) {
1534:
1535: String name = fStringPool.toString(entityName);
1536:
1537: int erChild = fCurrentNodeIndex;
1538: fCurrentNodeIndex = fDeferredDocumentImpl.getParentNode(
1539: erChild, false);
1540:
1541: // should never be true - we should not return here.
1542: if (fDeferredDocumentImpl.getNodeType(erChild, false) != Node.ENTITY_REFERENCE_NODE)
1543: return;
1544:
1545: erChild = fDeferredDocumentImpl
1546: .getLastChild(erChild, false); // first Child of EntityReference
1547: if (fDocumentTypeIndex != -1) {
1548: // if we have seen <?xml..> decl then Entity decl was found and
1549: // set in textDecl() using fCurrentEntityNode
1550: if (fCurrentEntityNode == -1) {
1551: // find Entity decl for this EntityReference.
1552: int entityDecl = fDeferredDocumentImpl
1553: .getLastChild(fDocumentTypeIndex, false);
1554: while (entityDecl != -1) {
1555: if (fDeferredDocumentImpl.getNodeType(
1556: entityDecl, false) == Node.ENTITY_NODE
1557: && fDeferredDocumentImpl
1558: .getNodeNameString(entityDecl,
1559: false).equals(name)) // string compare...
1560: {
1561: break;
1562: }
1563: entityDecl = fDeferredDocumentImpl
1564: .getPrevSibling(entityDecl, false);
1565: }
1566: fCurrentEntityNode = entityDecl;
1567: }
1568: if (fCurrentEntityNode != -1
1569: && fDeferredDocumentImpl.getLastChild(
1570: fCurrentEntityNode, false) == -1) {
1571: // found entityDecl with same name as this reference
1572: // AND it doesn't have any children.
1573:
1574: // we don't need to iterate, because the whole structure
1575: // should already be connected to the 1st child.
1576: fDeferredDocumentImpl.setAsLastChild(
1577: fCurrentEntityNode, erChild);
1578: }
1579: // done with current entity reference.
1580: // reset values
1581: fCurrentEntityNode = -1;
1582: fCurrentEntityName = -1;
1583: }
1584:
1585: }
1586:
1587: // full node expansion
1588: else {
1589:
1590: Node erNode = fCurrentElementNode;//fCurrentElementNode.getParentNode();
1591: fCurrentElementNode = erNode.getParentNode();
1592:
1593: // if necessary populate the related entity now
1594: if (fDocumentImpl != null) {
1595: NamedNodeMap entities = fDocumentType.getEntities();
1596: String name = fStringPool.toString(entityName);
1597: Node entityNode = entities.getNamedItem(name);
1598:
1599: // simply return here if there is no entity for
1600: // the reference or if the entity is already populated.
1601: if (entityNode == null || entityNode.hasChildNodes()) {
1602: return;
1603: }
1604:
1605: EntityImpl entity = (EntityImpl) entityNode;
1606: for (Node child = erNode.getFirstChild(); child != null; child = child
1607: .getNextSibling()) {
1608: Node childClone = child.cloneNode(true);
1609: entity.appendChild(childClone);
1610: }
1611: }
1612: }
1613:
1614: } // endEntityReference(int,int,int)
1615:
1616: //
1617: // DTDValidator.EventHandler methods
1618: //
1619:
1620: /**
1621: * This function will be called when a <!DOCTYPE...> declaration is
1622: * encountered.
1623: */
1624: public void startDTD(QName rootElement, int publicId, int systemId)
1625: throws Exception {
1626:
1627: fInDTD = true;
1628:
1629: // full expansion
1630: if (fDocumentImpl != null) {
1631: String rootElementName = fStringPool
1632: .toString(rootElement.rawname);
1633: String publicString = fStringPool.toString(publicId);
1634: String systemString = fStringPool.toString(systemId);
1635: fDocumentType = fDocumentImpl.createDocumentType(
1636: rootElementName, publicString, systemString);
1637: fDocumentImpl.appendChild(fDocumentType);
1638:
1639: if (fGrammarAccess) {
1640: Element schema = fDocument.createElement("schema");
1641: // REVISIT: What should the namespace be? -Ac
1642: schema.setAttribute("xmlns",
1643: SchemaSymbols.URI_SCHEMAFORSCHEMA);
1644: ((AttrImpl) schema.getAttributeNode("xmlns"))
1645: .setSpecified(false);
1646: schema.setAttribute("finalDefault", "");
1647: ((AttrImpl) schema.getAttributeNode("finalDefault"))
1648: .setSpecified(false);
1649: schema.setAttribute("exactDefault", "");
1650: ((AttrImpl) schema.getAttributeNode("exactDefault"))
1651: .setSpecified(false);
1652: fDocumentType.appendChild(schema);
1653: fCurrentElementNode = schema;
1654: }
1655: }
1656:
1657: // deferred expansion
1658: else if (fDeferredDocumentImpl != null) {
1659: fDocumentTypeIndex = fDeferredDocumentImpl
1660: .createDocumentType(rootElement.rawname, publicId,
1661: systemId);
1662: fDeferredDocumentImpl.appendChild(fDocumentIndex,
1663: fDocumentTypeIndex);
1664:
1665: if (fGrammarAccess) {
1666: int handle = fAttrList.startAttrList();
1667: fAttrList
1668: .addAttr(
1669: fStringPool.addSymbol("xmlns"),
1670: fStringPool
1671: .addString(SchemaSymbols.URI_SCHEMAFORSCHEMA),
1672: fStringPool.addSymbol("CDATA"), false,
1673: false); // search
1674: fAttrList.addAttr(
1675: fStringPool.addSymbol("finalDefault"),
1676: fStringPool.addString(""), fStringPool
1677: .addSymbol("CDATA"), false, false); // search
1678: fAttrList.addAttr(
1679: fStringPool.addSymbol("exactDefault"),
1680: fStringPool.addString(""), fStringPool
1681: .addSymbol("CDATA"), false, false); // search
1682: fAttrList.endAttrList();
1683: int schemaIndex = fDeferredDocumentImpl.createElement(
1684: fStringPool.addSymbol("schema"), fAttrList,
1685: handle);
1686: // REVISIT: What should the namespace be? -Ac
1687: fDeferredDocumentImpl.appendChild(fDocumentTypeIndex,
1688: schemaIndex);
1689: fCurrentNodeIndex = schemaIndex;
1690: }
1691: }
1692:
1693: } // startDTD(int,int,int)
1694:
1695: /**
1696: * Supports DOM Level 2 internalSubset additions.
1697: * Called when the internal subset is completely scanned.
1698: */
1699: public void internalSubset(int internalSubset) {
1700:
1701: //System.out.println("internalSubset callback:"+fStringPool.toString(internalSubset));
1702:
1703: // full expansion
1704: if (fDocumentImpl != null && fDocumentType != null) {
1705: ((DocumentTypeImpl) fDocumentType)
1706: .setInternalSubset(fStringPool
1707: .toString(internalSubset));
1708: }
1709:
1710: // deferred expansion
1711: else if (fDeferredDocumentImpl != null) {
1712: fDeferredDocumentImpl.setInternalSubset(fDocumentTypeIndex,
1713: internalSubset);
1714: }
1715:
1716: }
1717:
1718: /**
1719: * This function will be called at the end of the DTD.
1720: */
1721: public void endDTD() throws Exception {
1722:
1723: fInDTD = false;
1724:
1725: if (fGrammarAccess) {
1726: if (fDocumentImpl != null) {
1727: fCurrentElementNode = fDocumentImpl;
1728: } else if (fDeferredDocumentImpl != null) {
1729: fCurrentNodeIndex = 0;
1730: }
1731: }
1732:
1733: } // endDTD()
1734:
1735: /**
1736: * <!ELEMENT Name contentspec>
1737: */
1738: public void elementDecl(QName elementDecl, int contentSpecType,
1739: int contentSpecIndex,
1740: XMLContentSpec.Provider contentSpecProvider)
1741: throws Exception {
1742:
1743: if (DEBUG_ATTLIST_DECL) {
1744: String contentModel = XMLContentSpec.toString(
1745: contentSpecProvider, fStringPool, contentSpecIndex);
1746: System.out.println("elementDecl("
1747: + fStringPool.toString(elementDecl.rawname) + ", "
1748: + contentModel + ")");
1749: }
1750:
1751: //
1752: // Create element declaration
1753: //
1754: if (fGrammarAccess) {
1755:
1756: if (fDeferredDocumentImpl != null) {
1757:
1758: //
1759: // Build element
1760: //
1761:
1762: // get element declaration; create if necessary
1763: int schemaIndex = getLastChildElement(
1764: fDocumentTypeIndex, "schema");
1765: String elementName = fStringPool
1766: .toString(elementDecl.rawname);
1767: int elementIndex = getLastChildElement(schemaIndex,
1768: "element", "name", elementName);
1769: if (elementIndex == -1) {
1770: int handle = fAttrList.startAttrList();
1771: fAttrList.addAttr(fStringPool.addSymbol("name"),
1772: fStringPool.addString(elementName),
1773: fStringPool.addSymbol("NMTOKEN"), true,
1774: false); // search
1775: fAttrList.addAttr(fStringPool
1776: .addSymbol("minOccurs"), // name
1777: fStringPool.addString("1"), // value
1778: fStringPool.addSymbol("NMTOKEN"), // type
1779: false, // specified
1780: false); // search
1781: fAttrList.addAttr(
1782: fStringPool.addSymbol("nillable"), // name
1783: fStringPool.addString("false"), // value
1784: fStringPool.addSymbol("ENUMERATION"), // type
1785: false, // specified
1786: false); // search
1787: fAttrList.addAttr(
1788: fStringPool.addSymbol("abstract"), // name
1789: fStringPool.addString("false"), // value
1790: fStringPool.addSymbol("ENUMERATION"), // type
1791: false, // specified
1792: false); // search
1793: fAttrList.addAttr(fStringPool.addSymbol("final"), // name
1794: fStringPool.addString("false"), // value
1795: fStringPool.addSymbol("ENUMERATION"), // type
1796: false, // specified
1797: false); // search
1798: fAttrList.endAttrList();
1799: elementIndex = fDeferredDocumentImpl.createElement(
1800: fStringPool.addSymbol("element"),
1801: fAttrList, handle);
1802: fDeferredDocumentImpl.appendChild(schemaIndex,
1803: elementIndex);
1804: }
1805:
1806: //
1807: // Build content model
1808: //
1809:
1810: // get type element; create if necessary
1811: int typeIndex = getLastChildElement(elementIndex,
1812: "complexType");
1813: if (typeIndex == -1
1814: && contentSpecType != XMLElementDecl.TYPE_MIXED_SIMPLE) {
1815: typeIndex = fDeferredDocumentImpl.createElement(
1816: fStringPool.addSymbol("complexType"), null,
1817: -1);
1818: // REVISIT: Check for type redeclaration? -Ac
1819: fDeferredDocumentImpl.insertBefore(elementIndex,
1820: typeIndex,
1821: getFirstChildElement(elementIndex));
1822: }
1823:
1824: // create models
1825: switch (contentSpecType) {
1826: case XMLElementDecl.TYPE_EMPTY: {
1827: int attributeIndex = fDeferredDocumentImpl
1828: .createAttribute(fStringPool
1829: .addSymbol("content"), fStringPool
1830: .addString("empty"), true);
1831: fDeferredDocumentImpl.setAttributeNode(typeIndex,
1832: attributeIndex);
1833: break;
1834: }
1835: case XMLElementDecl.TYPE_ANY: {
1836: int anyIndex = fDeferredDocumentImpl.createElement(
1837: fStringPool.addSymbol("any"), null, -1);
1838: fDeferredDocumentImpl.insertBefore(typeIndex,
1839: anyIndex, getFirstChildElement(typeIndex));
1840: break;
1841: }
1842: case XMLElementDecl.TYPE_MIXED_SIMPLE: {
1843: XMLContentSpec contentSpec = new XMLContentSpec();
1844: contentSpecProvider.getContentSpec(
1845: contentSpecIndex, contentSpec);
1846: contentSpecIndex = contentSpec.value;
1847: if (contentSpecIndex == -1) {
1848: int attributeIndex = fDeferredDocumentImpl
1849: .createAttribute(fStringPool
1850: .addSymbol("type"), fStringPool
1851: .addString("string"), true);
1852: fDeferredDocumentImpl.setAttributeNode(
1853: elementIndex, attributeIndex);
1854: } else {
1855: if (typeIndex == -1) {
1856: typeIndex = fDeferredDocumentImpl
1857: .createElement(fStringPool
1858: .addSymbol("complexType"),
1859: null, -1);
1860: // REVISIT: Check for type redeclaration? -Ac
1861: fDeferredDocumentImpl.insertBefore(
1862: elementIndex, typeIndex,
1863: getFirstChildElement(elementIndex));
1864: }
1865: int attributeIndex = fDeferredDocumentImpl
1866: .createAttribute(fStringPool
1867: .addSymbol("content"),
1868: fStringPool.addString("mixed"),
1869: true);
1870: fDeferredDocumentImpl.setAttributeNode(
1871: typeIndex, attributeIndex);
1872: int handle = fAttrList.startAttrList();
1873: fAttrList.addAttr(fStringPool
1874: .addSymbol("minOccurs"), fStringPool
1875: .addString("0"), fStringPool
1876: .addSymbol("NMTOKEN"), true, false); // search
1877: fAttrList.addAttr(fStringPool
1878: .addSymbol("maxOccurs"), fStringPool
1879: .addString("unbounded"), fStringPool
1880: .addSymbol("CDATA"), true, false); // search
1881: fAttrList.endAttrList();
1882: int choiceIndex = fDeferredDocumentImpl
1883: .createElement(fStringPool
1884: .addSymbol("choice"),
1885: fAttrList, handle);
1886: fDeferredDocumentImpl.appendChild(typeIndex,
1887: choiceIndex);
1888: while (contentSpecIndex != -1) {
1889:
1890: // get node
1891: contentSpecProvider.getContentSpec(
1892: contentSpecIndex, contentSpec);
1893: int type = contentSpec.type;
1894: int left = contentSpec.value;
1895: int right = contentSpec.otherValue;
1896:
1897: // if leaf, skip "#PCDATA" and stop
1898: if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
1899: break;
1900: }
1901:
1902: // add right hand leaf
1903: contentSpecProvider.getContentSpec(right,
1904: contentSpec);
1905: handle = fAttrList.startAttrList();
1906: fAttrList
1907: .addAttr(
1908: fStringPool
1909: .addSymbol("ref"),
1910: fStringPool
1911: .addString(fStringPool
1912: .toString(contentSpec.value)),
1913: fStringPool
1914: .addSymbol("NMTOKEN"),
1915: true, false); //search
1916: fAttrList.endAttrList();
1917: int rightIndex = fDeferredDocumentImpl
1918: .createElement(fStringPool
1919: .addSymbol("element"),
1920: fAttrList, handle);
1921: int refIndex = getFirstChildElement(choiceIndex);
1922: fDeferredDocumentImpl.insertBefore(
1923: choiceIndex, rightIndex, refIndex);
1924:
1925: // go to next node
1926: contentSpecIndex = left;
1927: }
1928: }
1929: break;
1930: }
1931: case XMLElementDecl.TYPE_CHILDREN: {
1932: int attributeIndex = fDeferredDocumentImpl
1933: .createAttribute(fStringPool
1934: .addSymbol("content"), fStringPool
1935: .addString("elementOnly"), true);
1936: fDeferredDocumentImpl.setAttributeNode(typeIndex,
1937: attributeIndex);
1938: int children = createChildren(contentSpecProvider,
1939: contentSpecIndex, new XMLContentSpec(),
1940: fDeferredDocumentImpl, -1);
1941: fDeferredDocumentImpl.insertBefore(typeIndex,
1942: children, getFirstChildElement(typeIndex));
1943: break;
1944: }
1945: }
1946:
1947: } // if defer-node-expansion
1948:
1949: else if (fDocumentImpl != null) {
1950:
1951: //
1952: // Build element
1953: //
1954:
1955: // get element declaration; create if necessary
1956: Element schema = XUtil.getLastChildElement(
1957: fDocumentType, "schema");
1958: String elementName = fStringPool
1959: .toString(elementDecl.rawname);
1960: Element element = XUtil.getLastChildElement(schema,
1961: "element", "name", elementName);
1962: if (element == null) {
1963: element = fDocumentImpl.createElement("element");
1964: element.setAttribute("name", elementName);
1965: element.setAttribute("minOccurs", "1");
1966: ((AttrImpl) element.getAttributeNode("minOccurs"))
1967: .setSpecified(false);
1968: element.setAttribute("nillable", "false");
1969: ((AttrImpl) element.getAttributeNode("nillable"))
1970: .setSpecified(false);
1971: element.setAttribute("abstract", "false");
1972: ((AttrImpl) element.getAttributeNode("abstract"))
1973: .setSpecified(false);
1974: element.setAttribute("final", "false");
1975: ((AttrImpl) element.getAttributeNode("final"))
1976: .setSpecified(false);
1977: schema.appendChild(element);
1978: }
1979:
1980: //
1981: // Build content model
1982: //
1983:
1984: // get type element; create if necessary
1985: Element type = XUtil.getLastChildElement(element,
1986: "complexType");
1987: if (type == null
1988: && contentSpecType != XMLElementDecl.TYPE_MIXED_SIMPLE) {
1989: type = fDocumentImpl.createElement("complexType");
1990: // REVISIT: Check for type redeclaration? -Ac
1991: element.insertBefore(type, XUtil
1992: .getFirstChildElement(element));
1993: }
1994:
1995: // create models
1996: switch (contentSpecType) {
1997: case XMLElementDecl.TYPE_EMPTY: {
1998: type.setAttribute("content", "empty");
1999: break;
2000: }
2001: case XMLElementDecl.TYPE_ANY: {
2002: Element any = fDocumentImpl.createElement("any");
2003: type.insertBefore(any, XUtil
2004: .getFirstChildElement(type));
2005: break;
2006: }
2007: case XMLElementDecl.TYPE_MIXED_SIMPLE: {
2008: XMLContentSpec contentSpec = new XMLContentSpec();
2009: contentSpecProvider.getContentSpec(
2010: contentSpecIndex, contentSpec);
2011: contentSpecIndex = contentSpec.value;
2012: if (contentSpecIndex == -1) {
2013: element.setAttribute("type", "string");
2014: } else {
2015: if (type == null) {
2016: type = fDocumentImpl
2017: .createElement("complexType");
2018: // REVISIT: Check for type redeclaration? -Ac
2019: element.insertBefore(type, XUtil
2020: .getFirstChildElement(element));
2021: }
2022: type.setAttribute("content", "mixed");
2023: Element choice = fDocumentImpl
2024: .createElement("choice");
2025: choice.setAttribute("minOccurs", "0");
2026: choice.setAttribute("maxOccurs", "unbounded");
2027: type.appendChild(choice);
2028: while (contentSpecIndex != -1) {
2029:
2030: // get node
2031: contentSpecProvider.getContentSpec(
2032: contentSpecIndex, contentSpec);
2033: int cstype = contentSpec.type;
2034: int csleft = contentSpec.value;
2035: int csright = contentSpec.otherValue;
2036:
2037: // if leaf, skip "#PCDATA" and stop
2038: if (cstype == XMLContentSpec.CONTENTSPECNODE_LEAF) {
2039: break;
2040: }
2041:
2042: // add right hand leaf
2043: contentSpecProvider.getContentSpec(csright,
2044: contentSpec);
2045: Element right = fDocumentImpl
2046: .createElement("element");
2047: right.setAttribute("ref", fStringPool
2048: .toString(contentSpec.value));
2049: Element ref = XUtil
2050: .getFirstChildElement(choice);
2051: choice.insertBefore(right, ref);
2052:
2053: // go to next node
2054: contentSpecIndex = csleft;
2055: }
2056: }
2057: break;
2058: }
2059: case XMLElementDecl.TYPE_CHILDREN: {
2060: type.setAttribute("content", "elementOnly");
2061: Element children = createChildren(
2062: contentSpecProvider, contentSpecIndex,
2063: new XMLContentSpec(), fDocumentImpl, null);
2064: type.insertBefore(children, XUtil
2065: .getFirstChildElement(type));
2066: break;
2067: }
2068: }
2069:
2070: } // if NOT defer-node-expansion
2071:
2072: } // if grammar-access
2073:
2074: } // elementDecl(int,String)
2075:
2076: /**
2077: * <!ATTLIST Name AttDef>
2078: */
2079: public void attlistDecl(QName elementDecl, QName attributeDecl,
2080: int attType, boolean attList, String enumString,
2081: int attDefaultType, int attDefaultValue) throws Exception {
2082:
2083: if (DEBUG_ATTLIST_DECL) {
2084: System.out.println("attlistDecl("
2085: + fStringPool.toString(elementDecl.rawname) + ", "
2086: + fStringPool.toString(attributeDecl.rawname)
2087: + ", " + fStringPool.toString(attType) + ", "
2088: + enumString + ", "
2089: + fStringPool.toString(attDefaultType) + ", "
2090: + fStringPool.toString(attDefaultValue) + ")");
2091: }
2092:
2093: // deferred expansion
2094: if (fDeferredDocumentImpl != null) {
2095:
2096: // get the default value
2097: if (attDefaultValue != -1) {
2098: if (DEBUG_ATTLIST_DECL) {
2099: System.out
2100: .println(" adding default attribute value: "
2101: + fStringPool
2102: .toString(attDefaultValue));
2103: }
2104:
2105: // get element definition
2106: int elementDefIndex = fDeferredDocumentImpl
2107: .lookupElementDefinition(elementDecl.rawname);
2108:
2109: // create element definition if not already there
2110: if (elementDefIndex == -1) {
2111: elementDefIndex = fDeferredDocumentImpl
2112: .createElementDefinition(elementDecl.rawname);
2113: fDeferredDocumentImpl.appendChild(
2114: fDocumentTypeIndex, elementDefIndex);
2115: }
2116:
2117: // add default attribute
2118: int attrIndex = fDeferredDocumentImpl.createAttribute(
2119: attributeDecl.rawname, attributeDecl.uri,
2120: attDefaultValue, false);
2121: fDeferredDocumentImpl.appendChild(elementDefIndex,
2122: attrIndex);
2123:
2124: }
2125:
2126: //
2127: // Create attribute declaration
2128: //
2129: if (fGrammarAccess) {
2130:
2131: // get element declaration; create it if necessary
2132: int schemaIndex = getLastChildElement(
2133: fDocumentTypeIndex, "schema");
2134: String elementName = fStringPool
2135: .toString(elementDecl.rawname);
2136: int elementIndex = getLastChildElement(schemaIndex,
2137: "element", "name", elementName);
2138: if (elementIndex == -1) {
2139: int handle = fAttrList.startAttrList();
2140: fAttrList.addAttr(fStringPool.addSymbol("name"),
2141: fStringPool.addString(elementName),
2142: fStringPool.addSymbol("NMTOKEN"), true,
2143: false); //search
2144: fAttrList.endAttrList();
2145: elementIndex = fDeferredDocumentImpl.createElement(
2146: fStringPool.addSymbol("element"),
2147: fAttrList, handle);
2148: fDeferredDocumentImpl.appendChild(schemaIndex,
2149: elementIndex);
2150: }
2151:
2152: // get type element; create it if necessary
2153: int typeIndex = getLastChildElement(elementIndex,
2154: "complexType");
2155: if (typeIndex == -1) {
2156: typeIndex = fDeferredDocumentImpl.createElement(
2157: fStringPool.addSymbol("complexType"), null,
2158: -1);
2159: fDeferredDocumentImpl.insertBefore(elementIndex,
2160: typeIndex,
2161: getLastChildElement(elementIndex));
2162: }
2163:
2164: // create attribute and set its attributes
2165: String attributeName = fStringPool
2166: .toString(attributeDecl.rawname);
2167: int attributeIndex = getLastChildElement(elementIndex,
2168: "attribute", "name", attributeName);
2169: if (attributeIndex == -1) {
2170: int handle = fAttrList.startAttrList();
2171: fAttrList.addAttr(fStringPool.addSymbol("name"),
2172: fStringPool.addString(attributeName),
2173: fStringPool.addSymbol("NMTOKEN"), true,
2174: false); // search
2175: fAttrList.addAttr(fStringPool
2176: .addSymbol("maxOccurs"), fStringPool
2177: .addString("1"), fStringPool
2178: .addSymbol("CDATA"), false, false); // search
2179: fAttrList.endAttrList();
2180: attributeIndex = fDeferredDocumentImpl
2181: .createElement(fStringPool
2182: .addSymbol("attribute"), fAttrList,
2183: handle);
2184: fDeferredDocumentImpl.appendChild(typeIndex,
2185: attributeIndex);
2186:
2187: // attribute type: CDATA, ENTITY, ... , NMTOKENS; ENUMERATION
2188: if (attType == XMLAttributeDecl.TYPE_ENUMERATION) {
2189: handle = fAttrList.startAttrList();
2190: fAttrList.addAttr(
2191: fStringPool.addSymbol("base"),
2192: fStringPool.addString("NMTOKEN"),
2193: fStringPool.addSymbol("NMTOKEN"), true,
2194: false); // search
2195: fAttrList.endAttrList();
2196: int simpleTypeIndex = fDeferredDocumentImpl
2197: .createElement(fStringPool
2198: .addSymbol("simpleType"),
2199: fAttrList, handle);
2200: fDeferredDocumentImpl.appendChild(
2201: attributeIndex, simpleTypeIndex);
2202: String tokenizerString = enumString.substring(
2203: 1, enumString.length() - 1);
2204: StringTokenizer tokenizer = new StringTokenizer(
2205: tokenizerString, "|");
2206: while (tokenizer.hasMoreTokens()) {
2207: handle = fAttrList.startAttrList();
2208: fAttrList.addAttr(fStringPool
2209: .addSymbol("value"), fStringPool
2210: .addString(tokenizer.nextToken()),
2211: fStringPool.addSymbol("CDATA"),
2212: true, false); // search
2213: fAttrList.endAttrList();
2214: int enumerationIndex = fDeferredDocumentImpl
2215: .createElement(fStringPool
2216: .addSymbol("enumeration"),
2217: fAttrList, handle);
2218: fDeferredDocumentImpl.appendChild(
2219: simpleTypeIndex, enumerationIndex);
2220: }
2221: } else {
2222: int typeNameIndex = -1;
2223: switch (attType) {
2224: case XMLAttributeDecl.TYPE_ENTITY: {
2225: typeNameIndex = fStringPool
2226: .addString(attList ? "ENTITIES"
2227: : "ENTITY");
2228: break;
2229: }
2230: case XMLAttributeDecl.TYPE_ID: {
2231: typeNameIndex = fStringPool.addString("ID");
2232: break;
2233: }
2234: case XMLAttributeDecl.TYPE_IDREF: {
2235: typeNameIndex = fStringPool
2236: .addString(attList ? "IDREFS"
2237: : "IDREF");
2238: break;
2239: }
2240: case XMLAttributeDecl.TYPE_NMTOKEN: {
2241: typeNameIndex = fStringPool
2242: .addString(attList ? "NMTOKENS"
2243: : "NMTOKEN");
2244: break;
2245: }
2246: case XMLAttributeDecl.TYPE_NOTATION: {
2247: typeNameIndex = fStringPool
2248: .addString("NOTATION");
2249: break;
2250: }
2251: case XMLAttributeDecl.TYPE_CDATA:
2252: default: {
2253: typeNameIndex = fStringPool
2254: .addString("string");
2255: break;
2256: }
2257: }
2258: int attrIndex = fDeferredDocumentImpl
2259: .createAttribute(fStringPool
2260: .addSymbol("type"),
2261: typeNameIndex, true);
2262: fDeferredDocumentImpl.setAttributeNode(
2263: attributeIndex, attrIndex);
2264: }
2265:
2266: // attribute default type: #IMPLIED, #REQUIRED, #FIXED
2267: boolean fixed = false;
2268: switch (attDefaultType) {
2269: case XMLAttributeDecl.DEFAULT_TYPE_REQUIRED: {
2270: int useAttrIndex = fDeferredDocumentImpl
2271: .createAttribute(fStringPool
2272: .addSymbol("use"), fStringPool
2273: .addString("required"), true);
2274: fDeferredDocumentImpl.setAttributeNode(
2275: attributeIndex, useAttrIndex);
2276: break;
2277: }
2278: case XMLAttributeDecl.DEFAULT_TYPE_FIXED: {
2279: fixed = true;
2280: int useAttrIndex = fDeferredDocumentImpl
2281: .createAttribute(fStringPool
2282: .addSymbol("use"), fStringPool
2283: .addString("fixed"), true);
2284: fDeferredDocumentImpl.setAttributeNode(
2285: attributeIndex, useAttrIndex);
2286: break;
2287: }
2288: }
2289:
2290: // attribute default value
2291: if (attDefaultValue != -1) {
2292: if (!fixed) {
2293: int useAttrIndex = fDeferredDocumentImpl
2294: .createAttribute(
2295: fStringPool
2296: .addSymbol("use"),
2297: fStringPool
2298: .addString("default"),
2299: true);
2300: fDeferredDocumentImpl.setAttributeNode(
2301: attributeIndex, useAttrIndex);
2302: }
2303: int valueAttrIndex = fDeferredDocumentImpl
2304: .createAttribute(fStringPool
2305: .addSymbol("value"),
2306: attDefaultValue, true);
2307: fDeferredDocumentImpl.setAttributeNode(
2308: attributeIndex, valueAttrIndex);
2309: }
2310: }
2311: }
2312: }
2313:
2314: // full expansion
2315: else if (fDocumentImpl != null) {
2316:
2317: // get the default value
2318: if (attDefaultValue != -1) {
2319: if (DEBUG_ATTLIST_DECL) {
2320: System.out
2321: .println(" adding default attribute value: "
2322: + fStringPool
2323: .toString(attDefaultValue));
2324: }
2325:
2326: // get element name
2327: String elementName = fStringPool
2328: .toString(elementDecl.rawname);
2329:
2330: // get element definition node
2331: NamedNodeMap elements = ((DocumentTypeImpl) fDocumentType)
2332: .getElements();
2333: ElementDefinitionImpl elementDef = (ElementDefinitionImpl) elements
2334: .getNamedItem(elementName);
2335: if (elementDef == null) {
2336: elementDef = fDocumentImpl
2337: .createElementDefinition(elementName);
2338: ((DocumentTypeImpl) fDocumentType).getElements()
2339: .setNamedItem(elementDef);
2340: }
2341:
2342: // REVISIT: Check for uniqueness of element name? -Ac
2343:
2344: // get attribute name and value index
2345: String attrName = fStringPool
2346: .toString(attributeDecl.rawname);
2347: String attrValue = fStringPool
2348: .toString(attDefaultValue);
2349:
2350: // create attribute and set properties
2351: boolean nsEnabled = false;
2352: try {
2353: nsEnabled = getNamespaces();
2354: } catch (SAXException s) {
2355: }
2356: AttrImpl attr;
2357: if (nsEnabled) {
2358: String namespaceURI = fStringPool
2359: .toString(attributeDecl.uri);
2360: // DOM Level 2 wants all namespace declaration attributes
2361: // to be bound to "http://www.w3.org/2000/xmlns/"
2362: // So as long as the XML parser doesn't do it, it needs to
2363: // done here.
2364: String prefix = fStringPool
2365: .toString(attributeDecl.prefix);
2366: // hide that our parser uses an empty string for null
2367: if (namespaceURI.length() == 0) {
2368: namespaceURI = null;
2369: }
2370: if (namespaceURI == null) {
2371: if (prefix != null) {
2372: if (prefix.equals("xmlns")) {
2373: namespaceURI = "http://www.w3.org/2000/xmlns/";
2374: }
2375: } else if (attrName.equals("xmlns")) {
2376: namespaceURI = "http://www.w3.org/2000/xmlns/";
2377: }
2378: }
2379: attr = (AttrImpl) fDocumentImpl.createAttributeNS(
2380: namespaceURI, attrName);
2381: } else {
2382: attr = (AttrImpl) fDocumentImpl
2383: .createAttribute(attrName);
2384: }
2385: attr.setValue(attrValue);
2386: attr.setSpecified(false);
2387:
2388: // add default attribute to element definition
2389: if (nsEnabled) {
2390: elementDef.getAttributes().setNamedItemNS(attr);
2391: } else {
2392: elementDef.getAttributes().setNamedItem(attr);
2393: }
2394: }
2395:
2396: //
2397: // Create attribute declaration
2398: //
2399: try {
2400: if (fGrammarAccess) {
2401:
2402: // get element declaration; create it if necessary
2403: Element schema = XUtil.getLastChildElement(
2404: fDocumentType, "schema");
2405: String elementName = fStringPool
2406: .toString(elementDecl.rawname);
2407: Element element = XUtil.getLastChildElement(schema,
2408: "element", "name", elementName);
2409: if (element == null) {
2410: element = fDocumentImpl
2411: .createElement("element");
2412: element.setAttribute("name", elementName);
2413: schema.appendChild(element);
2414: }
2415:
2416: // get type element; create it if necessary
2417: Element type = XUtil.getLastChildElement(element,
2418: "complexType");
2419: if (type == null) {
2420: type = fDocumentImpl
2421: .createElement("complexType");
2422: element.insertBefore(type, XUtil
2423: .getLastChildElement(element));
2424: }
2425:
2426: // create attribute and set its attributes
2427: String attributeName = fStringPool
2428: .toString(attributeDecl.rawname);
2429: Element attribute = XUtil
2430: .getLastChildElement(element, "attribute",
2431: "name", attributeName);
2432: if (attribute == null) {
2433: attribute = fDocumentImpl
2434: .createElement("attribute");
2435: attribute.setAttribute("name", attributeName);
2436: attribute.setAttribute("maxOccurs", "1");
2437: ((AttrImpl) attribute
2438: .getAttributeNode("maxOccurs"))
2439: .setSpecified(false);
2440: type.appendChild(attribute);
2441:
2442: // attribute type: CDATA, ENTITY, ... , NMTOKENS; ENUMERATION
2443: if (attType == XMLAttributeDecl.TYPE_ENUMERATION) {
2444: Element simpleType = fDocumentImpl
2445: .createElement("simpleType");
2446: simpleType.setAttribute("base", "NMTOKEN");
2447: attribute.appendChild(simpleType);
2448: String tokenizerString = enumString
2449: .substring(1,
2450: enumString.length() - 1);
2451: StringTokenizer tokenizer = new StringTokenizer(
2452: tokenizerString, "|");
2453: while (tokenizer.hasMoreTokens()) {
2454: Element enumeration = fDocumentImpl
2455: .createElement("enumeration");
2456: enumeration.setAttribute("value",
2457: tokenizer.nextToken());
2458: simpleType.appendChild(enumeration);
2459: }
2460: } else {
2461: String typeName = null;
2462: switch (attType) {
2463: case XMLAttributeDecl.TYPE_ENTITY: {
2464: typeName = attList ? "ENTITIES"
2465: : "ENTITY";
2466: break;
2467: }
2468: case XMLAttributeDecl.TYPE_ID: {
2469: typeName = "ID";
2470: break;
2471: }
2472: case XMLAttributeDecl.TYPE_IDREF: {
2473: typeName = attList ? "IDREFS" : "IDREF";
2474: break;
2475: }
2476: case XMLAttributeDecl.TYPE_NMTOKEN: {
2477: typeName = attList ? "NMTOKENS"
2478: : "NMTOKEN";
2479: break;
2480: }
2481: case XMLAttributeDecl.TYPE_NOTATION: {
2482: typeName = "NOTATION";
2483: break;
2484: }
2485: case XMLAttributeDecl.TYPE_CDATA:
2486: default: {
2487: typeName = "string";
2488: break;
2489: }
2490: }
2491: attribute.setAttribute("type", typeName);
2492: }
2493:
2494: // attribute default type: #IMPLIED, #REQUIRED, #FIXED
2495: boolean fixed = false;
2496: switch (attDefaultType) {
2497: case XMLAttributeDecl.DEFAULT_TYPE_REQUIRED: {
2498: attribute.setAttribute("use", "required");
2499: break;
2500: }
2501: case XMLAttributeDecl.DEFAULT_TYPE_FIXED: {
2502: attribute.setAttribute("use", "fixed");
2503: fixed = true;
2504: break;
2505: }
2506: }
2507:
2508: // attribute default value
2509: if (attDefaultValue != -1) {
2510: if (!fixed) {
2511: attribute
2512: .setAttribute("use", "default");
2513: }
2514: attribute.setAttribute("value", fStringPool
2515: .toString(attDefaultValue));
2516: }
2517: }
2518: }
2519: } catch (Exception e) {
2520: e.printStackTrace(System.err);
2521: }
2522:
2523: } // if NOT defer-node-expansion
2524:
2525: } // attlistDecl(int,int,int,String,int,int)
2526:
2527: /**
2528: * <!ENTITY % Name EntityValue> (internal)
2529: */
2530: public void internalPEDecl(int entityNameIndex, int entityValueIndex)
2531: throws Exception {
2532: if (fDeferredDocumentImpl != null) {
2533: if (fGrammarAccess) {
2534: StringBuffer str = new StringBuffer();
2535: str.append("<!ENTITY % ");
2536: str.append(fStringPool.toString(entityNameIndex));
2537: str.append(" \"");
2538: str.append(fStringPool.toString(entityValueIndex));
2539: str.append("\">");
2540: int commentIndex = fStringPool
2541: .addString(str.toString());
2542: int internalPEEntityIndex = fDeferredDocumentImpl
2543: .createComment(commentIndex);
2544: int schemaIndex = getFirstChildElement(
2545: fDocumentTypeIndex, "schema");
2546: fDeferredDocumentImpl.appendChild(schemaIndex,
2547: internalPEEntityIndex);
2548: }
2549: } else if (fDocumentImpl != null) {
2550: if (fGrammarAccess) {
2551: StringBuffer str = new StringBuffer();
2552: str.append("<!ENTITY % ");
2553: str.append(fStringPool.toString(entityNameIndex));
2554: str.append(" \"");
2555: str.append(fStringPool.toString(entityValueIndex));
2556: str.append("\">");
2557: Node internalPEEntity = fDocumentImpl.createComment(str
2558: .toString());
2559: Node schema = XUtil.getFirstChildElement(fDocumentType,
2560: "schema");
2561: schema.appendChild(internalPEEntity);
2562: }
2563: } else {
2564: fStringPool.orphanString(entityValueIndex);
2565: }
2566: }
2567:
2568: /**
2569: * <!ENTITY % Name ExternalID> (external)
2570: */
2571: public void externalPEDecl(int entityNameIndex, int publicIdIndex,
2572: int systemIdIndex) throws Exception {
2573: if (fDeferredDocumentImpl != null) {
2574: if (fGrammarAccess) {
2575: StringBuffer str = new StringBuffer();
2576: str.append("<!ENTITY ");
2577: str.append(fStringPool.toString(entityNameIndex));
2578: str.append(' ');
2579: if (publicIdIndex != -1) {
2580: str.append("PUBLIC \"");
2581: str.append(fStringPool.toString(publicIdIndex));
2582: str.append('"');
2583: if (systemIdIndex != -1) {
2584: str.append(" \"");
2585: str.append(fStringPool.toString(systemIdIndex));
2586: str.append('"');
2587: }
2588: } else if (systemIdIndex != -1) {
2589: str.append("SYSTEM \"");
2590: str.append(fStringPool.toString(systemIdIndex));
2591: str.append('"');
2592: }
2593: str.append('>');
2594: int commentIndex = fStringPool
2595: .addString(str.toString());
2596: int externalPEEntityIndex = fDeferredDocumentImpl
2597: .createComment(commentIndex);
2598: int schemaIndex = getFirstChildElement(
2599: fDocumentTypeIndex, "schema");
2600: fDeferredDocumentImpl.appendChild(schemaIndex,
2601: externalPEEntityIndex);
2602: }
2603: } else if (fDocumentImpl != null) {
2604: if (fGrammarAccess) {
2605: StringBuffer str = new StringBuffer();
2606: str.append("<!ENTITY ");
2607: str.append(fStringPool.toString(entityNameIndex));
2608: str.append(' ');
2609: if (publicIdIndex != -1) {
2610: str.append("PUBLIC \"");
2611: str.append(fStringPool.toString(publicIdIndex));
2612: str.append('"');
2613: if (systemIdIndex != -1) {
2614: str.append(" \"");
2615: str.append(fStringPool.toString(systemIdIndex));
2616: str.append('"');
2617: }
2618: } else if (systemIdIndex != -1) {
2619: str.append("SYSTEM \"");
2620: str.append(fStringPool.toString(systemIdIndex));
2621: str.append('"');
2622: }
2623: str.append('>');
2624: Node externalPEEntity = fDocumentImpl.createComment(str
2625: .toString());
2626: Node schema = XUtil.getFirstChildElement(fDocumentType,
2627: "schema");
2628: schema.appendChild(externalPEEntity);
2629: }
2630: }
2631: }
2632:
2633: /**
2634: * <!ENTITY Name EntityValue> (internal)
2635: */
2636: public void internalEntityDecl(int entityNameIndex,
2637: int entityValueIndex) throws Exception {
2638:
2639: // deferred expansion
2640: if (fDeferredDocumentImpl != null) {
2641:
2642: if (fDocumentTypeIndex == -1)
2643: return; //revisit: should never happen. Exception?
2644:
2645: //revisit: how to check if entity was already declared.
2646: // XML spec says that 1st Entity decl is binding.
2647:
2648: int newEntityIndex = fDeferredDocumentImpl.createEntity(
2649: entityNameIndex, -1, -1, -1);
2650: fDeferredDocumentImpl.appendChild(fDocumentTypeIndex,
2651: newEntityIndex);
2652:
2653: // REVISIT: Entities were removed from latest working draft. -Ac
2654: // create internal entity declaration
2655: if (fGrammarAccess) {
2656: StringBuffer str = new StringBuffer();
2657: str.append("<!ENTITY ");
2658: str.append(fStringPool.toString(entityNameIndex));
2659: str.append(" \"");
2660: str.append(fStringPool.toString(entityValueIndex));
2661: str.append("\">");
2662: int commentIndex = fStringPool
2663: .addString(str.toString());
2664: int textEntityIndex = fDeferredDocumentImpl
2665: .createComment(commentIndex);
2666: int schemaIndex = getFirstChildElement(
2667: fDocumentTypeIndex, "schema");
2668: fDeferredDocumentImpl.appendChild(schemaIndex,
2669: textEntityIndex);
2670: }
2671: }
2672:
2673: // full expansion
2674: else if (fDocumentImpl != null) {
2675: if (fDocumentType == null)
2676: return; //revisit: should never happen. Exception?
2677:
2678: //revisit: how to check if entity was already declared.
2679: // XML spec says that 1st Entity decl is binding.
2680:
2681: String entityName = fStringPool.toString(entityNameIndex);
2682:
2683: Entity entity = fDocumentImpl.createEntity(entityName);
2684: fDocumentType.getEntities().setNamedItem(entity);
2685:
2686: // REVISIT: Entities were removed from latest working draft. -Ac
2687: // create internal entity declaration
2688: if (fGrammarAccess) {
2689: StringBuffer str = new StringBuffer();
2690: str.append("<!ENTITY ");
2691: str.append(fStringPool.toString(entityNameIndex));
2692: str.append(" \"");
2693: str.append(fStringPool.toString(entityValueIndex));
2694: str.append("\">");
2695: Node textEntity = fDocumentImpl.createComment(str
2696: .toString());
2697: Node schema = XUtil.getFirstChildElement(fDocumentType,
2698: "schema");
2699: schema.appendChild(textEntity);
2700: }
2701: }
2702:
2703: } // internalEntityDecl(int,int)
2704:
2705: /**
2706: * <!ENTITY Name ExternalID> (external)
2707: */
2708: public void externalEntityDecl(int entityNameIndex,
2709: int publicIdIndex, int systemIdIndex) throws Exception {
2710:
2711: // deferred expansion
2712: if (fDeferredDocumentImpl != null) {
2713:
2714: //revisit: how to check if entity was already declared.
2715: // XML spec says that 1st Entity decl is binding.
2716:
2717: int newEntityIndex = fDeferredDocumentImpl.createEntity(
2718: entityNameIndex, publicIdIndex, systemIdIndex, -1);
2719:
2720: fDeferredDocumentImpl.appendChild(fDocumentTypeIndex,
2721: newEntityIndex);
2722:
2723: // REVISIT: Entities were removed from latest working draft. -Ac
2724: // create external entity declaration
2725: if (fGrammarAccess) {
2726: StringBuffer str = new StringBuffer();
2727: str.append("<!ENTITY ");
2728: str.append(fStringPool.toString(entityNameIndex));
2729: str.append(' ');
2730: if (publicIdIndex != -1) {
2731: str.append("PUBLIC \"");
2732: str.append(fStringPool.toString(publicIdIndex));
2733: str.append('"');
2734: if (systemIdIndex != -1) {
2735: str.append(" \"");
2736: str.append(fStringPool.toString(systemIdIndex));
2737: str.append('"');
2738: }
2739: } else if (systemIdIndex != -1) {
2740: str.append("SYSTEM \"");
2741: str.append(fStringPool.toString(systemIdIndex));
2742: str.append('"');
2743: }
2744: str.append('>');
2745: int commentIndex = fStringPool
2746: .addString(str.toString());
2747: int externalEntityIndex = fDeferredDocumentImpl
2748: .createComment(commentIndex);
2749: int schemaIndex = getFirstChildElement(
2750: fDocumentTypeIndex, "schema");
2751: fDeferredDocumentImpl.appendChild(schemaIndex,
2752: externalEntityIndex);
2753: }
2754: }
2755:
2756: // full expansion
2757: else if (fDocumentImpl != null) {
2758:
2759: //revisit: how to check if entity was already declared.
2760: // XML spec says that 1st Entity decl is binding.
2761:
2762: String entityName = fStringPool.toString(entityNameIndex);
2763: String publicId = fStringPool.toString(publicIdIndex);
2764: String systemId = fStringPool.toString(systemIdIndex);
2765:
2766: EntityImpl entity = (EntityImpl) fDocumentImpl
2767: .createEntity(entityName);
2768: if (publicIdIndex != -1) {
2769: entity.setPublicId(publicId);
2770: }
2771: entity.setSystemId(systemId);
2772: fDocumentType.getEntities().setNamedItem(entity);
2773:
2774: // REVISIT: Entities were removed from latest working draft. -Ac
2775: // create external entity declaration
2776: if (fGrammarAccess) {
2777: StringBuffer str = new StringBuffer();
2778: str.append("<!ENTITY ");
2779: str.append(fStringPool.toString(entityNameIndex));
2780: str.append(' ');
2781: if (publicIdIndex != -1) {
2782: str.append("PUBLIC \"");
2783: str.append(fStringPool.toString(publicIdIndex));
2784: str.append('"');
2785: if (systemIdIndex != -1) {
2786: str.append(" \"");
2787: str.append(fStringPool.toString(systemIdIndex));
2788: str.append('"');
2789: }
2790: } else if (systemIdIndex != -1) {
2791: str.append("SYSTEM \"");
2792: str.append(fStringPool.toString(systemIdIndex));
2793: str.append('"');
2794: }
2795: str.append('>');
2796: Node externalEntity = fDocumentImpl.createComment(str
2797: .toString());
2798: Node schema = XUtil.getFirstChildElement(fDocumentType,
2799: "schema");
2800: schema.appendChild(externalEntity);
2801: }
2802: }
2803:
2804: } // externalEntityDecl(int,int,int)
2805:
2806: /**
2807: * <!ENTITY Name ExternalID NDataDecl> (unparsed)
2808: */
2809: public void unparsedEntityDecl(int entityNameIndex,
2810: int publicIdIndex, int systemIdIndex, int notationNameIndex)
2811: throws Exception {
2812:
2813: // deferred expansion
2814: if (fDeferredDocumentImpl != null) {
2815:
2816: //revisit: how to check if entity was already declared.
2817: // XML spec says that 1st Entity decl is binding.
2818:
2819: int newEntityIndex = fDeferredDocumentImpl.createEntity(
2820: entityNameIndex, publicIdIndex, systemIdIndex,
2821: notationNameIndex);
2822:
2823: fDeferredDocumentImpl.appendChild(fDocumentTypeIndex,
2824: newEntityIndex);
2825:
2826: // REVISIT: Entities were removed from latest working draft. -Ac
2827: // add unparsed entity declaration
2828: if (fGrammarAccess) {
2829: StringBuffer str = new StringBuffer();
2830: str.append("<!ENTITY ");
2831: str.append(fStringPool.toString(entityNameIndex));
2832: str.append(' ');
2833: if (publicIdIndex != -1) {
2834: str.append("PUBLIC \"");
2835: str.append(fStringPool.toString(publicIdIndex));
2836: str.append('"');
2837: if (systemIdIndex != -1) {
2838: str.append(" \"");
2839: str.append(fStringPool.toString(systemIdIndex));
2840: str.append('"');
2841: }
2842: } else if (systemIdIndex != -1) {
2843: str.append("SYSTEM \"");
2844: str.append(fStringPool.toString(systemIdIndex));
2845: str.append('"');
2846: }
2847: str.append(" NDATA ");
2848: str.append(fStringPool.toString(notationNameIndex));
2849: str.append('>');
2850: int commentIndex = fStringPool
2851: .addString(str.toString());
2852: int unparsedEntityIndex = fDeferredDocumentImpl
2853: .createComment(commentIndex);
2854: int schemaIndex = getFirstChildElement(
2855: fDocumentTypeIndex, "schema");
2856: fDeferredDocumentImpl.appendChild(schemaIndex,
2857: unparsedEntityIndex);
2858: }
2859: }
2860:
2861: // full expansion
2862: else if (fDocumentImpl != null) {
2863:
2864: //revisit: how to check if entity was already declared.
2865: // XML spec says that 1st Entity decl is binding.
2866:
2867: String entityName = fStringPool.toString(entityNameIndex);
2868: String publicId = fStringPool.toString(publicIdIndex);
2869: String systemId = fStringPool.toString(systemIdIndex);
2870: String notationName = fStringPool
2871: .toString(notationNameIndex);
2872:
2873: EntityImpl entity = (EntityImpl) fDocumentImpl
2874: .createEntity(entityName);
2875: if (publicIdIndex != -1) {
2876: entity.setPublicId(publicId);
2877: }
2878: entity.setSystemId(systemId);
2879: entity.setNotationName(notationName);
2880: fDocumentType.getEntities().setNamedItem(entity);
2881:
2882: // REVISIT: Entities were removed from latest working draft. -Ac
2883: // add unparsed entity declaration
2884: if (fGrammarAccess) {
2885: StringBuffer str = new StringBuffer();
2886: str.append("<!ENTITY ");
2887: str.append(fStringPool.toString(entityNameIndex));
2888: str.append(' ');
2889: if (publicIdIndex != -1) {
2890: str.append("PUBLIC \"");
2891: str.append(fStringPool.toString(publicIdIndex));
2892: str.append('"');
2893: if (systemIdIndex != -1) {
2894: str.append(" \"");
2895: str.append(fStringPool.toString(systemIdIndex));
2896: str.append('"');
2897: }
2898: } else if (systemIdIndex != -1) {
2899: str.append("SYSTEM \"");
2900: str.append(fStringPool.toString(systemIdIndex));
2901: str.append('"');
2902: }
2903: str.append(" NDATA ");
2904: str.append(fStringPool.toString(notationNameIndex));
2905: str.append('>');
2906: Node unparsedEntity = fDocumentImpl.createComment(str
2907: .toString());
2908: Node schema = XUtil.getFirstChildElement(fDocumentType,
2909: "schema");
2910: schema.appendChild(unparsedEntity);
2911: }
2912: }
2913:
2914: } // unparsedEntityDecl(int,int,int,int)
2915:
2916: /**
2917: * <!NOTATION Name ExternalId>
2918: */
2919: public void notationDecl(int notationNameIndex, int publicIdIndex,
2920: int systemIdIndex) throws Exception {
2921:
2922: // deferred expansion
2923: if (fDeferredDocumentImpl != null) {
2924:
2925: //revisit: how to check if entity was already declared.
2926: // XML spec says that 1st Entity decl is binding.
2927:
2928: int newNotationIndex = fDeferredDocumentImpl
2929: .createNotation(notationNameIndex, publicIdIndex,
2930: systemIdIndex);
2931:
2932: fDeferredDocumentImpl.appendChild(fDocumentTypeIndex,
2933: newNotationIndex);
2934:
2935: // create notation declaration
2936: if (fGrammarAccess) {
2937: int schemaIndex = getLastChildElement(
2938: fDocumentTypeIndex, "schema");
2939: String notationName = fStringPool
2940: .toString(notationNameIndex);
2941: int notationIndex = getLastChildElement(schemaIndex,
2942: "notation", "name", notationName);
2943: if (notationIndex == -1) {
2944: int handle = fAttrList.startAttrList();
2945: fAttrList.addAttr(fStringPool.addSymbol("name"),
2946: fStringPool.addString(notationName),
2947: fStringPool.addSymbol("NMTOKEN"), true,
2948: false); // search
2949: if (publicIdIndex != -1) {
2950: fAttrList.addAttr(fStringPool
2951: .addSymbol("public"), publicIdIndex,
2952: fStringPool.addSymbol("CDATA"), true,
2953: false); // search
2954: }
2955: if (systemIdIndex != -1) {
2956: fAttrList.addAttr(fStringPool
2957: .addSymbol("system"), systemIdIndex,
2958: fStringPool.addSymbol("CDATA"), true,
2959: false); // search
2960: }
2961: fAttrList.endAttrList();
2962: notationIndex = fDeferredDocumentImpl
2963: .createElement(fStringPool
2964: .addSymbol("notation"), fAttrList,
2965: handle);
2966: fDeferredDocumentImpl.appendChild(schemaIndex,
2967: notationIndex);
2968: }
2969: }
2970: }
2971:
2972: // full expansion
2973: else if (fDocumentImpl != null) {
2974:
2975: // REVISIT: how to check if entity was already declared.
2976: // XML spec says that 1st Entity decl is binding.
2977:
2978: String notationName = fStringPool
2979: .toString(notationNameIndex);
2980: String publicId = fStringPool.toString(publicIdIndex);
2981: String systemId = fStringPool.toString(systemIdIndex);
2982:
2983: NotationImpl notationImpl = (NotationImpl) fDocumentImpl
2984: .createNotation(notationName);
2985: notationImpl.setPublicId(publicId);
2986: if (systemIdIndex != -1) {
2987: notationImpl.setSystemId(systemId);
2988: }
2989:
2990: fDocumentType.getNotations().setNamedItem(notationImpl);
2991:
2992: // create notation declaration
2993: if (fGrammarAccess) {
2994: Element schema = XUtil.getFirstChildElement(
2995: fDocumentType, "schema");
2996: Element notation = XUtil.getFirstChildElement(schema,
2997: "notation", "name", notationName);
2998: if (notation == null) {
2999: notation = fDocument.createElement("notation");
3000: notation.setAttribute("name", notationName);
3001: //notation.setAttribute("export", "true");
3002: //((AttrImpl)notation.getAttributeNode("export")).setSpecified(false);
3003: if (publicId != null) {
3004: notation.setAttribute("public", publicId);
3005: }
3006: if (systemIdIndex != -1) {
3007: notation.setAttribute("system", systemId);
3008: }
3009: schema.appendChild(notation);
3010: }
3011: }
3012: }
3013:
3014: } // notationDecl(int,int,int)
3015:
3016: //
3017: // Private methods
3018: //
3019:
3020: /** Returns the first child element of the specified node. */
3021: private int getFirstChildElement(int nodeIndex) {
3022: int childIndex = getLastChildElement(nodeIndex);
3023: while (childIndex != -1) {
3024: int prevIndex = getPrevSiblingElement(childIndex);
3025: if (prevIndex == -1) {
3026: break;
3027: }
3028: childIndex = prevIndex;
3029: }
3030: return childIndex;
3031: }
3032:
3033: /** Returns the first child element of the specified node. */
3034: private int getFirstChildElement(int nodeIndex, String name) {
3035: int childIndex = getLastChildElement(nodeIndex);
3036: if (childIndex != -1) {
3037: int nameIndex = fStringPool.addSymbol(name);
3038: while (childIndex != -1) {
3039: if (fDeferredDocumentImpl
3040: .getNodeName(childIndex, false) == nameIndex) {
3041: break;
3042: }
3043: int prevIndex = getPrevSiblingElement(childIndex);
3044: childIndex = prevIndex;
3045: }
3046: }
3047: return childIndex;
3048: }
3049:
3050: /** Returns the last child element of the specified node. */
3051: private int getLastChildElement(int nodeIndex) {
3052: int childIndex = fDeferredDocumentImpl.getLastChild(nodeIndex,
3053: false);
3054: while (childIndex != -1) {
3055: if (fDeferredDocumentImpl.getNodeType(childIndex, false) == Node.ELEMENT_NODE) {
3056: return childIndex;
3057: }
3058: childIndex = fDeferredDocumentImpl.getPrevSibling(
3059: childIndex, false);
3060: }
3061: return -1;
3062: }
3063:
3064: /** Returns the previous sibling element of the specified node. */
3065: private int getPrevSiblingElement(int nodeIndex) {
3066: int siblingIndex = fDeferredDocumentImpl.getPrevSibling(
3067: nodeIndex, false);
3068: while (siblingIndex != -1) {
3069: if (fDeferredDocumentImpl.getNodeType(siblingIndex, false) == Node.ELEMENT_NODE) {
3070: return siblingIndex;
3071: }
3072: siblingIndex = fDeferredDocumentImpl.getPrevSibling(
3073: siblingIndex, false);
3074: }
3075: return -1;
3076: }
3077:
3078: /** Returns the first child element with the given name. */
3079: private int getLastChildElement(int nodeIndex, String elementName) {
3080: int childIndex = getLastChildElement(nodeIndex);
3081: if (childIndex != -1) {
3082: while (childIndex != -1) {
3083: String nodeName = fDeferredDocumentImpl
3084: .getNodeNameString(childIndex, false);
3085: if (nodeName.equals(elementName)) {
3086: return childIndex;
3087: }
3088: childIndex = getPrevSiblingElement(childIndex);
3089: }
3090: }
3091: return -1;
3092: }
3093:
3094: /** Returns the next sibling element with the given name. */
3095: private int getPrevSiblingElement(int nodeIndex, String elementName) {
3096: int siblingIndex = getPrevSiblingElement(nodeIndex);
3097: if (siblingIndex != -1) {
3098: while (siblingIndex != -1) {
3099: String nodeName = fDeferredDocumentImpl
3100: .getNodeNameString(siblingIndex, false);
3101: if (nodeName.equals(elementName)) {
3102: return siblingIndex;
3103: }
3104: siblingIndex = getPrevSiblingElement(siblingIndex);
3105: }
3106: }
3107: return -1;
3108: }
3109:
3110: /** Returns the first child element with the given name. */
3111: private int getLastChildElement(int nodeIndex, String elemName,
3112: String attrName, String attrValue) {
3113: int childIndex = getLastChildElement(nodeIndex, elemName);
3114: if (childIndex != -1) {
3115: while (childIndex != -1) {
3116: int attrIndex = fDeferredDocumentImpl.getNodeValue(
3117: childIndex, false);
3118: while (attrIndex != -1) {
3119: String nodeName = fDeferredDocumentImpl
3120: .getNodeNameString(attrIndex, false);
3121: if (nodeName.equals(attrName)) {
3122: // REVISIT: Do we need to normalize the text? -Ac
3123: int textIndex = fDeferredDocumentImpl
3124: .getLastChild(attrIndex, false);
3125: String nodeValue = fDeferredDocumentImpl
3126: .getNodeValueString(textIndex, false);
3127: if (nodeValue.equals(attrValue)) {
3128: return childIndex;
3129: }
3130: }
3131: attrIndex = fDeferredDocumentImpl.getPrevSibling(
3132: attrIndex, false);
3133: }
3134: childIndex = getPrevSiblingElement(childIndex, elemName);
3135: }
3136: }
3137: return -1;
3138: }
3139:
3140: /** Returns the next sibling element with the given name and attribute. */
3141: private int getPrevSiblingElement(int nodeIndex, String elemName,
3142: String attrName, String attrValue) {
3143: int siblingIndex = getPrevSiblingElement(nodeIndex, elemName);
3144: if (siblingIndex != -1) {
3145: int attributeNameIndex = fStringPool.addSymbol(attrName);
3146: while (siblingIndex != -1) {
3147: int attrIndex = fDeferredDocumentImpl.getNodeValue(
3148: siblingIndex, false);
3149: while (attrIndex != -1) {
3150: int attrValueIndex = fDeferredDocumentImpl
3151: .getNodeValue(attrIndex, false);
3152: if (attrValue.equals(fStringPool
3153: .toString(attrValueIndex))) {
3154: return siblingIndex;
3155: }
3156: attrIndex = fDeferredDocumentImpl.getPrevSibling(
3157: attrIndex, false);
3158: }
3159: siblingIndex = getPrevSiblingElement(siblingIndex,
3160: elemName);
3161: }
3162: }
3163: return -1;
3164: }
3165:
3166: /**
3167: * Copies the source tree into the specified place in a destination
3168: * tree. The source node and its children are appended as children
3169: * of the destination node.
3170: * <p>
3171: * <em>Note:</em> This is an iterative implementation.
3172: */
3173: private void copyInto(Node src, int destIndex) throws Exception {
3174:
3175: // for ignorable whitespace features
3176: boolean domimpl = src != null && src instanceof DocumentImpl;
3177:
3178: // placement variables
3179: Node start = src;
3180: Node parent = src;
3181: Node place = src;
3182:
3183: // traverse source tree
3184: while (place != null) {
3185:
3186: // copy this node
3187: int nodeIndex = -1;
3188: short type = place.getNodeType();
3189: switch (type) {
3190: case Node.CDATA_SECTION_NODE: {
3191: boolean ignorable = domimpl
3192: && ((TextImpl) place).isIgnorableWhitespace();
3193: nodeIndex = fDeferredDocumentImpl.createCDATASection(
3194: fStringPool.addString(place.getNodeValue()),
3195: ignorable);
3196: break;
3197: }
3198: case Node.COMMENT_NODE: {
3199: nodeIndex = fDeferredDocumentImpl
3200: .createComment(fStringPool.addString(place
3201: .getNodeValue()));
3202: break;
3203: }
3204: case Node.ELEMENT_NODE: {
3205: XMLAttrList attrList = null;
3206: int handle = -1;
3207: NamedNodeMap attrs = place.getAttributes();
3208: if (attrs != null) {
3209: int length = attrs.getLength();
3210: if (length > 0) {
3211: handle = fAttrList.startAttrList();
3212: for (int i = 0; i < length; i++) {
3213: Attr attr = (Attr) attrs.item(i);
3214: String attrName = attr.getNodeName();
3215: String attrValue = attr.getNodeValue();
3216: fAttrList.addAttr(fStringPool
3217: .addSymbol(attrName), fStringPool
3218: .addString(attrValue), fStringPool
3219: .addSymbol("CDATA"), // REVISIT
3220: attr.getSpecified(), false); // search
3221: }
3222: fAttrList.endAttrList();
3223: attrList = fAttrList;
3224: }
3225: }
3226: nodeIndex = fDeferredDocumentImpl.createElement(
3227: fStringPool.addSymbol(place.getNodeName()),
3228: attrList, handle);
3229: break;
3230: }
3231: case Node.ENTITY_REFERENCE_NODE: {
3232: nodeIndex = fDeferredDocumentImpl
3233: .createEntityReference(fStringPool
3234: .addSymbol(place.getNodeName()));
3235: break;
3236: }
3237: case Node.PROCESSING_INSTRUCTION_NODE: {
3238: nodeIndex = fDeferredDocumentImpl
3239: .createProcessingInstruction(fStringPool
3240: .addSymbol(place.getNodeName()),
3241: fStringPool.addString(place
3242: .getNodeValue()));
3243: break;
3244: }
3245: case Node.TEXT_NODE: {
3246: boolean ignorable = domimpl
3247: && ((TextImpl) place).isIgnorableWhitespace();
3248: nodeIndex = fDeferredDocumentImpl.createTextNode(
3249: fStringPool.addString(place.getNodeValue()),
3250: ignorable);
3251: break;
3252: }
3253: default: {
3254: throw new IllegalArgumentException(
3255: "PAR010 Can't copy node type, " + type + " ("
3256: + place.getNodeName() + ')' + "\n"
3257: + type + "\t" + place.getNodeName());
3258: }
3259: }
3260: fDeferredDocumentImpl.appendChild(destIndex, nodeIndex);
3261:
3262: // iterate over children
3263: if (place.hasChildNodes()) {
3264: parent = place;
3265: place = place.getFirstChild();
3266: destIndex = nodeIndex;
3267: }
3268:
3269: // advance
3270: else {
3271: place = place.getNextSibling();
3272: while (place == null && parent != start) {
3273: place = parent.getNextSibling();
3274: parent = parent.getParentNode();
3275: destIndex = fDeferredDocumentImpl.getParentNode(
3276: destIndex, false);
3277: }
3278: }
3279:
3280: }
3281:
3282: } // copyInto(Node,int)
3283:
3284: /**
3285: * Sets the appropriate occurrence count attributes on the specified
3286: * model element.
3287: */
3288: private void setOccurrenceCount(Element model, int minOccur,
3289: int maxOccur) {
3290:
3291: // min
3292: model.setAttribute("minOccurs", Integer.toString(minOccur));
3293: if (minOccur == 1) {
3294: ((AttrImpl) model.getAttributeNode("minOccurs"))
3295: .setSpecified(false);
3296: }
3297:
3298: // max
3299: if (maxOccur == -1) {
3300: model.setAttribute("maxOccurs", "*");
3301: } else if (maxOccur != 1) {
3302: model.setAttribute("maxOccurs", Integer.toString(maxOccur));
3303: }
3304:
3305: } // setOccurrenceCount(Element,int,int)
3306:
3307: /** Creates the children for the element decl. */
3308: private Element createChildren(XMLContentSpec.Provider provider,
3309: int index, XMLContentSpec node, DocumentImpl factory,
3310: Element parent) throws Exception {
3311:
3312: // get occurrence count
3313: provider.getContentSpec(index, node);
3314: int occurs = -1;
3315: switch (node.type) {
3316: case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: {
3317: occurs = '+';
3318: provider.getContentSpec(node.value, node);
3319: break;
3320: }
3321: case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: {
3322: occurs = '*';
3323: provider.getContentSpec(node.value, node);
3324: break;
3325: }
3326: case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: {
3327: occurs = '?';
3328: provider.getContentSpec(node.value, node);
3329: break;
3330: }
3331: }
3332:
3333: // flatten model
3334: int nodeType = node.type;
3335: switch (nodeType) {
3336:
3337: // CHOICE or SEQUENCE
3338: case XMLContentSpec.CONTENTSPECNODE_CHOICE:
3339: case XMLContentSpec.CONTENTSPECNODE_SEQ: {
3340:
3341: // go down left side
3342: int leftIndex = node.value;
3343: int rightIndex = node.otherValue;
3344: Element left = createChildren(provider, leftIndex, node,
3345: factory, parent);
3346:
3347: // go down right side
3348: Element right = createChildren(provider, rightIndex, node,
3349: factory, null);
3350:
3351: // append left children
3352: boolean choice = nodeType == XMLContentSpec.CONTENTSPECNODE_CHOICE;
3353: String type = choice ? "choice" : "sequence";
3354: Element model = left;
3355: if (!left.getNodeName().equals(type)) {
3356: String minOccurs = left.getAttribute("minOccurs");
3357: String maxOccurs = left.getAttribute("maxOccurs");
3358: boolean min1 = minOccurs.length() == 0
3359: || minOccurs.equals("1");
3360: boolean max1 = maxOccurs.length() == 0
3361: || maxOccurs.equals("1");
3362: if (parent == null || (min1 && max1)) {
3363: model = factory.createElement(type);
3364: model.appendChild(left);
3365: } else {
3366: model = parent;
3367: }
3368: }
3369:
3370: // set occurrence count
3371: switch (occurs) {
3372: case '+': {
3373: model.setAttribute("maxOccurs", "unbounded");
3374: break;
3375: }
3376: case '*': {
3377: model.setAttribute("minOccurs", "0");
3378: model.setAttribute("maxOccurs", "unbounded");
3379: break;
3380: }
3381: case '?': {
3382: model.setAttribute("minOccurs", "0");
3383: break;
3384: }
3385: }
3386:
3387: // append right children
3388: model.appendChild(right);
3389:
3390: // return model
3391: return model;
3392: }
3393:
3394: // LEAF
3395: case XMLContentSpec.CONTENTSPECNODE_LEAF: {
3396: Element leaf = factory.createElement("element");
3397: leaf.setAttribute("ref", fStringPool.toString(node.value));
3398: switch (occurs) {
3399: case '+': {
3400: leaf.setAttribute("maxOccurs", "unbounded");
3401: break;
3402: }
3403: case '*': {
3404: leaf.setAttribute("minOccurs", "0");
3405: leaf.setAttribute("maxOccurs", "unbounded");
3406: break;
3407: }
3408: case '?': {
3409: leaf.setAttribute("minOccurs", "0");
3410: break;
3411: }
3412: }
3413: return leaf;
3414: }
3415:
3416: } // switch node type
3417:
3418: // error
3419: return null;
3420:
3421: } // createChildren(XMLContentSpec.Provider,int,XMLContentSpec,DocumentImpl,Element):Element
3422:
3423: /** Creates the children for the deferred element decl. */
3424: private int createChildren(XMLContentSpec.Provider provider,
3425: int index, XMLContentSpec node,
3426: DeferredDocumentImpl factory, int parent) throws Exception {
3427:
3428: // get occurrence count
3429: provider.getContentSpec(index, node);
3430: int occurs = -1;
3431: switch (node.type) {
3432: case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: {
3433: occurs = '+';
3434: provider.getContentSpec(node.value, node);
3435: break;
3436: }
3437: case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: {
3438: occurs = '*';
3439: provider.getContentSpec(node.value, node);
3440: break;
3441: }
3442: case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: {
3443: occurs = '?';
3444: provider.getContentSpec(node.value, node);
3445: break;
3446: }
3447: }
3448:
3449: // flatten model
3450: int nodeType = node.type;
3451: switch (nodeType) {
3452:
3453: // CHOICE or SEQUENCE
3454: case XMLContentSpec.CONTENTSPECNODE_CHOICE:
3455: case XMLContentSpec.CONTENTSPECNODE_SEQ: {
3456:
3457: // go down left side
3458: int leftIndex = node.value;
3459: int rightIndex = node.otherValue;
3460: int left = createChildren(provider, leftIndex, node,
3461: factory, parent);
3462:
3463: // go down right side
3464: int right = createChildren(provider, rightIndex, node,
3465: factory, -1);
3466:
3467: // append left children
3468: boolean choice = nodeType == XMLContentSpec.CONTENTSPECNODE_CHOICE;
3469: int type = fStringPool.addSymbol(choice ? "choice"
3470: : "sequence");
3471: int model = left;
3472: if (factory.getNodeName(left, false) != type) {
3473: int minOccurs = factory.getAttribute(left, fStringPool
3474: .addSymbol("minOccurs"));
3475: int maxOccurs = factory.getAttribute(left, fStringPool
3476: .addSymbol("maxOccurs"));
3477: boolean min1 = minOccurs == -1
3478: || fStringPool.toString(minOccurs).equals("1");
3479: boolean max1 = maxOccurs == -1
3480: || fStringPool.toString(maxOccurs).equals("1");
3481: if (parent == -1 || (min1 && max1)) {
3482: model = factory.createElement(type, null, -1);
3483: factory.appendChild(model, left);
3484: } else {
3485: model = parent;
3486: }
3487: }
3488:
3489: // set occurrence count
3490: switch (occurs) {
3491: case '+': {
3492: int maxOccurs = factory.createAttribute(fStringPool
3493: .addSymbol("maxOccurs"), fStringPool
3494: .addString("unbounded"), true);
3495: factory.setAttributeNode(model, maxOccurs);
3496: break;
3497: }
3498: case '*': {
3499: int minOccurs = factory.createAttribute(fStringPool
3500: .addSymbol("minOccurs"), fStringPool
3501: .addString("0"), true);
3502: factory.setAttributeNode(model, minOccurs);
3503: int maxOccurs = factory.createAttribute(fStringPool
3504: .addSymbol("maxOccurs"), fStringPool
3505: .addString("unbounded"), true);
3506: factory.setAttributeNode(model, maxOccurs);
3507: break;
3508: }
3509: case '?': {
3510: int minOccurs = factory.createAttribute(fStringPool
3511: .addSymbol("minOccurs"), fStringPool
3512: .addString("0"), true);
3513: factory.setAttributeNode(model, minOccurs);
3514: break;
3515: }
3516: }
3517:
3518: // append right children
3519: factory.appendChild(model, right);
3520:
3521: // return model
3522: return model;
3523: }
3524:
3525: // LEAF
3526: case XMLContentSpec.CONTENTSPECNODE_LEAF: {
3527: int handle = fAttrList.startAttrList();
3528: fAttrList.addAttr(fStringPool.addSymbol("ref"), fStringPool
3529: .addString(fStringPool.toString(node.value)),
3530: fStringPool.addSymbol("NMTOKEN"), true, false); // search
3531: switch (occurs) {
3532: case '+': {
3533: fAttrList.addAttr(fStringPool.addSymbol("maxOccurs"),
3534: fStringPool.addString("unbounded"), fStringPool
3535: .addSymbol("CDATA"), true, false); // search
3536: break;
3537: }
3538: case '*': {
3539: fAttrList.addAttr(fStringPool.addSymbol("minOccurs"),
3540: fStringPool.addString("0"), fStringPool
3541: .addSymbol("NMTOKEN"), true, false); // search
3542: fAttrList.addAttr(fStringPool.addSymbol("maxOccurs"),
3543: fStringPool.addString("unbounded"), fStringPool
3544: .addSymbol("CDATA"), true, false); // search
3545: break;
3546: }
3547: case '?': {
3548: fAttrList.addAttr(fStringPool.addSymbol("minOccurs"),
3549: fStringPool.addString("0"), fStringPool
3550: .addSymbol("NMTOKEN"), true, false); // search
3551: break;
3552: }
3553: }
3554: fAttrList.endAttrList();
3555: int leaf = factory.createElement(fStringPool
3556: .addSymbol("element"), fAttrList, handle);
3557: return leaf;
3558: }
3559:
3560: } // switch node type
3561:
3562: // error
3563: return -1;
3564:
3565: } // createChildren(XMLContentSpec.Provider,int,XMLContentSpec,DeferredDocumentImpl,int):int
3566:
3567: } // class DOMParser
|