0001: /*
0002: * Copyright 1999-2004 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: /*
0017: * $Id: DTMDefaultBase.java,v 1.43 2005/07/25 19:23:05 johng Exp $
0018: */
0019: package org.apache.xml.dtm.ref;
0020:
0021: import org.apache.xml.dtm.*;
0022: import org.apache.xml.utils.SuballocatedIntVector;
0023: import org.apache.xml.utils.BoolStack;
0024:
0025: import java.util.Vector;
0026:
0027: import javax.xml.transform.Source;
0028:
0029: import org.apache.xml.utils.XMLString;
0030: import org.apache.xml.utils.XMLStringFactory;
0031:
0032: import org.apache.xml.res.XMLMessages;
0033: import org.apache.xml.res.XMLErrorResources;
0034:
0035: import java.io.*; // for dumpDTM
0036:
0037: /**
0038: * The <code>DTMDefaultBase</code> class serves as a helper base for DTMs.
0039: * It sets up structures for navigation and type, while leaving data
0040: * management and construction to the derived classes.
0041: */
0042: public abstract class DTMDefaultBase implements DTM {
0043: static final boolean JJK_DEBUG = false;
0044:
0045: // This constant is likely to be removed in the future. Use the
0046: // getDocument() method instead of ROOTNODE to get at the root
0047: // node of a DTM.
0048: /** The identity of the root node. */
0049: public static final int ROOTNODE = 0;
0050:
0051: /**
0052: * The number of nodes, which is also used to determine the next
0053: * node index.
0054: */
0055: protected int m_size = 0;
0056:
0057: /** The expanded names, one array element for each node. */
0058: protected SuballocatedIntVector m_exptype;
0059:
0060: /** First child values, one array element for each node. */
0061: protected SuballocatedIntVector m_firstch;
0062:
0063: /** Next sibling values, one array element for each node. */
0064: protected SuballocatedIntVector m_nextsib;
0065:
0066: /** Previous sibling values, one array element for each node. */
0067: protected SuballocatedIntVector m_prevsib;
0068:
0069: /** Previous sibling values, one array element for each node. */
0070: protected SuballocatedIntVector m_parent;
0071:
0072: /** Vector of SuballocatedIntVectors of NS decl sets */
0073: protected Vector m_namespaceDeclSets = null;
0074:
0075: /** SuballocatedIntVector of elements at which corresponding
0076: * namespaceDeclSets were defined */
0077: protected SuballocatedIntVector m_namespaceDeclSetElements = null;
0078:
0079: /**
0080: * These hold indexes to elements based on namespace and local name.
0081: * The base lookup is the the namespace. The second lookup is the local
0082: * name, and the last array contains the the first free element
0083: * at the start, and the list of element handles following.
0084: */
0085: protected int[][][] m_elemIndexes;
0086:
0087: /** The default block size of the node arrays */
0088: public static final int DEFAULT_BLOCKSIZE = 512; // favor small docs.
0089:
0090: /** The number of blocks for the node arrays */
0091: public static final int DEFAULT_NUMBLOCKS = 32;
0092:
0093: /** The number of blocks used for small documents & RTFs */
0094: public static final int DEFAULT_NUMBLOCKS_SMALL = 4;
0095:
0096: /** The block size of the node arrays */
0097: //protected final int m_blocksize;
0098: /**
0099: * The value to use when the information has not been built yet.
0100: */
0101: protected static final int NOTPROCESSED = DTM.NULL - 1;
0102:
0103: /**
0104: * The DTM manager who "owns" this DTM.
0105: */
0106:
0107: public DTMManager m_mgr;
0108:
0109: /**
0110: * m_mgr cast to DTMManagerDefault, or null if it isn't an instance
0111: * (Efficiency hook)
0112: */
0113: protected DTMManagerDefault m_mgrDefault = null;
0114:
0115: /** The document identity number(s). If we have overflowed the addressing
0116: * range of the first that was assigned to us, we may add others. */
0117: protected SuballocatedIntVector m_dtmIdent;
0118:
0119: /** The mask for the identity.
0120: %REVIEW% Should this really be set to the _DEFAULT? What if
0121: a particular DTM wanted to use another value? */
0122: //protected final static int m_mask = DTMManager.IDENT_NODE_DEFAULT;
0123: /** The base URI for this document. */
0124: protected String m_documentBaseURI;
0125:
0126: /**
0127: * The whitespace filter that enables elements to strip whitespace or not.
0128: */
0129: protected DTMWSFilter m_wsfilter;
0130:
0131: /** Flag indicating whether to strip whitespace nodes */
0132: protected boolean m_shouldStripWS = false;
0133:
0134: /** Stack of flags indicating whether to strip whitespace nodes */
0135: protected BoolStack m_shouldStripWhitespaceStack;
0136:
0137: /** The XMLString factory for creating XMLStrings. */
0138: protected XMLStringFactory m_xstrf;
0139:
0140: /**
0141: * The table for exandedNameID lookups. This may or may not be the same
0142: * table as is contained in the DTMManagerDefault.
0143: */
0144: protected ExpandedNameTable m_expandedNameTable;
0145:
0146: /** true if indexing is turned on. */
0147: protected boolean m_indexing;
0148:
0149: /**
0150: * Construct a DTMDefaultBase object using the default block size.
0151: *
0152: * @param mgr The DTMManager who owns this DTM.
0153: * @param source The object that is used to specify the construction source.
0154: * @param dtmIdentity The DTM identity ID for this DTM.
0155: * @param whiteSpaceFilter The white space filter for this DTM, which may
0156: * be null.
0157: * @param xstringfactory The factory to use for creating XMLStrings.
0158: * @param doIndexing true if the caller considers it worth it to use
0159: * indexing schemes.
0160: */
0161: public DTMDefaultBase(DTMManager mgr, Source source,
0162: int dtmIdentity, DTMWSFilter whiteSpaceFilter,
0163: XMLStringFactory xstringfactory, boolean doIndexing) {
0164: this (mgr, source, dtmIdentity, whiteSpaceFilter,
0165: xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true,
0166: false);
0167: }
0168:
0169: /**
0170: * Construct a DTMDefaultBase object from a DOM node.
0171: *
0172: * @param mgr The DTMManager who owns this DTM.
0173: * @param source The object that is used to specify the construction source.
0174: * @param dtmIdentity The DTM identity ID for this DTM.
0175: * @param whiteSpaceFilter The white space filter for this DTM, which may
0176: * be null.
0177: * @param xstringfactory The factory to use for creating XMLStrings.
0178: * @param doIndexing true if the caller considers it worth it to use
0179: * indexing schemes.
0180: * @param blocksize The block size of the DTM.
0181: * @param usePrevsib true if we want to build the previous sibling node array.
0182: * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM.
0183: */
0184: public DTMDefaultBase(DTMManager mgr, Source source,
0185: int dtmIdentity, DTMWSFilter whiteSpaceFilter,
0186: XMLStringFactory xstringfactory, boolean doIndexing,
0187: int blocksize, boolean usePrevsib, boolean newNameTable) {
0188: // Use smaller sizes for the internal node arrays if the block size
0189: // is small.
0190: int numblocks;
0191: if (blocksize <= 64) {
0192: numblocks = DEFAULT_NUMBLOCKS_SMALL;
0193: m_dtmIdent = new SuballocatedIntVector(4, 1);
0194: } else {
0195: numblocks = DEFAULT_NUMBLOCKS;
0196: m_dtmIdent = new SuballocatedIntVector(32);
0197: }
0198:
0199: m_exptype = new SuballocatedIntVector(blocksize, numblocks);
0200: m_firstch = new SuballocatedIntVector(blocksize, numblocks);
0201: m_nextsib = new SuballocatedIntVector(blocksize, numblocks);
0202: m_parent = new SuballocatedIntVector(blocksize, numblocks);
0203:
0204: // Only create the m_prevsib array if the usePrevsib flag is true.
0205: // Some DTM implementations (e.g. SAXImpl) do not need this array.
0206: // We can save the time to build it in those cases.
0207: if (usePrevsib)
0208: m_prevsib = new SuballocatedIntVector(blocksize, numblocks);
0209:
0210: m_mgr = mgr;
0211: if (mgr instanceof DTMManagerDefault)
0212: m_mgrDefault = (DTMManagerDefault) mgr;
0213:
0214: m_documentBaseURI = (null != source) ? source.getSystemId()
0215: : null;
0216: m_dtmIdent.setElementAt(dtmIdentity, 0);
0217: m_wsfilter = whiteSpaceFilter;
0218: m_xstrf = xstringfactory;
0219: m_indexing = doIndexing;
0220:
0221: if (doIndexing) {
0222: m_expandedNameTable = new ExpandedNameTable();
0223: } else {
0224: // Note that this fails if we aren't talking to an instance of
0225: // DTMManagerDefault
0226: m_expandedNameTable = m_mgrDefault
0227: .getExpandedNameTable(this );
0228: }
0229:
0230: if (null != whiteSpaceFilter) {
0231: m_shouldStripWhitespaceStack = new BoolStack();
0232:
0233: pushShouldStripWhitespace(false);
0234: }
0235: }
0236:
0237: /**
0238: * Ensure that the size of the element indexes can hold the information.
0239: *
0240: * @param namespaceID Namespace ID index.
0241: * @param LocalNameID Local name ID.
0242: */
0243: protected void ensureSizeOfIndex(int namespaceID, int LocalNameID) {
0244:
0245: if (null == m_elemIndexes) {
0246: m_elemIndexes = new int[namespaceID + 20][][];
0247: } else if (m_elemIndexes.length <= namespaceID) {
0248: int[][][] indexes = m_elemIndexes;
0249:
0250: m_elemIndexes = new int[namespaceID + 20][][];
0251:
0252: System.arraycopy(indexes, 0, m_elemIndexes, 0,
0253: indexes.length);
0254: }
0255:
0256: int[][] localNameIndex = m_elemIndexes[namespaceID];
0257:
0258: if (null == localNameIndex) {
0259: localNameIndex = new int[LocalNameID + 100][];
0260: m_elemIndexes[namespaceID] = localNameIndex;
0261: } else if (localNameIndex.length <= LocalNameID) {
0262: int[][] indexes = localNameIndex;
0263:
0264: localNameIndex = new int[LocalNameID + 100][];
0265:
0266: System.arraycopy(indexes, 0, localNameIndex, 0,
0267: indexes.length);
0268:
0269: m_elemIndexes[namespaceID] = localNameIndex;
0270: }
0271:
0272: int[] elemHandles = localNameIndex[LocalNameID];
0273:
0274: if (null == elemHandles) {
0275: elemHandles = new int[128];
0276: localNameIndex[LocalNameID] = elemHandles;
0277: elemHandles[0] = 1;
0278: } else if (elemHandles.length <= elemHandles[0] + 1) {
0279: int[] indexes = elemHandles;
0280:
0281: elemHandles = new int[elemHandles[0] + 1024];
0282:
0283: System
0284: .arraycopy(indexes, 0, elemHandles, 0,
0285: indexes.length);
0286:
0287: localNameIndex[LocalNameID] = elemHandles;
0288: }
0289: }
0290:
0291: /**
0292: * Add a node to the element indexes. The node will not be added unless
0293: * it's an element.
0294: *
0295: * @param expandedTypeID The expanded type ID of the node.
0296: * @param identity The node identity index.
0297: */
0298: protected void indexNode(int expandedTypeID, int identity) {
0299:
0300: ExpandedNameTable ent = m_expandedNameTable;
0301: short type = ent.getType(expandedTypeID);
0302:
0303: if (DTM.ELEMENT_NODE == type) {
0304: int namespaceID = ent.getNamespaceID(expandedTypeID);
0305: int localNameID = ent.getLocalNameID(expandedTypeID);
0306:
0307: ensureSizeOfIndex(namespaceID, localNameID);
0308:
0309: int[] index = m_elemIndexes[namespaceID][localNameID];
0310:
0311: index[index[0]] = identity;
0312:
0313: index[0]++;
0314: }
0315: }
0316:
0317: /**
0318: * Find the first index that occurs in the list that is greater than or
0319: * equal to the given value.
0320: *
0321: * @param list A list of integers.
0322: * @param start The start index to begin the search.
0323: * @param len The number of items to search.
0324: * @param value Find the slot that has a value that is greater than or
0325: * identical to this argument.
0326: *
0327: * @return The index in the list of the slot that is higher or identical
0328: * to the identity argument, or -1 if no node is higher or equal.
0329: */
0330: protected int findGTE(int[] list, int start, int len, int value) {
0331:
0332: int low = start;
0333: int high = start + (len - 1);
0334: int end = high;
0335:
0336: while (low <= high) {
0337: int mid = (low + high) / 2;
0338: int c = list[mid];
0339:
0340: if (c > value)
0341: high = mid - 1;
0342: else if (c < value)
0343: low = mid + 1;
0344: else
0345: return mid;
0346: }
0347:
0348: return (low <= end && list[low] > value) ? low : -1;
0349: }
0350:
0351: /**
0352: * Find the first matching element from the index at or after the
0353: * given node.
0354: *
0355: * @param nsIndex The namespace index lookup.
0356: * @param lnIndex The local name index lookup.
0357: * @param firstPotential The first potential match that is worth looking at.
0358: *
0359: * @return The first node that is greater than or equal to the
0360: * firstPotential argument, or DTM.NOTPROCESSED if not found.
0361: */
0362: int findElementFromIndex(int nsIndex, int lnIndex,
0363: int firstPotential) {
0364:
0365: int[][][] indexes = m_elemIndexes;
0366:
0367: if (null != indexes && nsIndex < indexes.length) {
0368: int[][] lnIndexs = indexes[nsIndex];
0369:
0370: if (null != lnIndexs && lnIndex < lnIndexs.length) {
0371: int[] elems = lnIndexs[lnIndex];
0372:
0373: if (null != elems) {
0374: int pos = findGTE(elems, 1, elems[0],
0375: firstPotential);
0376:
0377: if (pos > -1) {
0378: return elems[pos];
0379: }
0380: }
0381: }
0382: }
0383:
0384: return NOTPROCESSED;
0385: }
0386:
0387: /**
0388: * Get the next node identity value in the list, and call the iterator
0389: * if it hasn't been added yet.
0390: *
0391: * @param identity The node identity (index).
0392: * @return identity+1, or DTM.NULL.
0393: */
0394: protected abstract int getNextNodeIdentity(int identity);
0395:
0396: /**
0397: * This method should try and build one or more nodes in the table.
0398: *
0399: * @return The true if a next node is found or false if
0400: * there are no more nodes.
0401: */
0402: protected abstract boolean nextNode();
0403:
0404: /**
0405: * Get the number of nodes that have been added.
0406: *
0407: * @return the number of nodes that have been mapped.
0408: */
0409: protected abstract int getNumberOfNodes();
0410:
0411: /** Stateless axis traversers, lazely built. */
0412: protected DTMAxisTraverser[] m_traversers;
0413:
0414: // /**
0415: // * Ensure that the size of the information arrays can hold another entry
0416: // * at the given index.
0417: // *
0418: // * @param index On exit from this function, the information arrays sizes must be
0419: // * at least index+1.
0420: // */
0421: // protected void ensureSize(int index)
0422: // {
0423: // // We've cut over to Suballocated*Vector, which are self-sizing.
0424: // }
0425:
0426: /**
0427: * Get the simple type ID for the given node identity.
0428: *
0429: * @param identity The node identity.
0430: *
0431: * @return The simple type ID, or DTM.NULL.
0432: */
0433: protected short _type(int identity) {
0434:
0435: int info = _exptype(identity);
0436:
0437: if (NULL != info)
0438: return m_expandedNameTable.getType(info);
0439: else
0440: return NULL;
0441: }
0442:
0443: /**
0444: * Get the expanded type ID for the given node identity.
0445: *
0446: * @param identity The node identity.
0447: *
0448: * @return The expanded type ID, or DTM.NULL.
0449: */
0450: protected int _exptype(int identity) {
0451: if (identity == DTM.NULL)
0452: return NULL;
0453: // Reorganized test and loop into single flow
0454: // Tiny performance improvement, saves a few bytes of code, clearer.
0455: // %OPT% Other internal getters could be treated simliarly
0456: while (identity >= m_size) {
0457: if (!nextNode() && identity >= m_size)
0458: return NULL;
0459: }
0460: return m_exptype.elementAt(identity);
0461:
0462: }
0463:
0464: /**
0465: * Get the level in the tree for the given node identity.
0466: *
0467: * @param identity The node identity.
0468: *
0469: * @return The tree level, or DTM.NULL.
0470: */
0471: protected int _level(int identity) {
0472: while (identity >= m_size) {
0473: boolean isMore = nextNode();
0474: if (!isMore && identity >= m_size)
0475: return NULL;
0476: }
0477:
0478: int i = 0;
0479: while (NULL != (identity = _parent(identity)))
0480: ++i;
0481: return i;
0482: }
0483:
0484: /**
0485: * Get the first child for the given node identity.
0486: *
0487: * @param identity The node identity.
0488: *
0489: * @return The first child identity, or DTM.NULL.
0490: */
0491: protected int _firstch(int identity) {
0492:
0493: // Boiler-plate code for each of the _xxx functions, except for the array.
0494: int info = (identity >= m_size) ? NOTPROCESSED : m_firstch
0495: .elementAt(identity);
0496:
0497: // Check to see if the information requested has been processed, and,
0498: // if not, advance the iterator until we the information has been
0499: // processed.
0500: while (info == NOTPROCESSED) {
0501: boolean isMore = nextNode();
0502:
0503: if (identity >= m_size && !isMore)
0504: return NULL;
0505: else {
0506: info = m_firstch.elementAt(identity);
0507: if (info == NOTPROCESSED && !isMore)
0508: return NULL;
0509: }
0510: }
0511:
0512: return info;
0513: }
0514:
0515: /**
0516: * Get the next sibling for the given node identity.
0517: *
0518: * @param identity The node identity.
0519: *
0520: * @return The next sibling identity, or DTM.NULL.
0521: */
0522: protected int _nextsib(int identity) {
0523: // Boiler-plate code for each of the _xxx functions, except for the array.
0524: int info = (identity >= m_size) ? NOTPROCESSED : m_nextsib
0525: .elementAt(identity);
0526:
0527: // Check to see if the information requested has been processed, and,
0528: // if not, advance the iterator until we the information has been
0529: // processed.
0530: while (info == NOTPROCESSED) {
0531: boolean isMore = nextNode();
0532:
0533: if (identity >= m_size && !isMore)
0534: return NULL;
0535: else {
0536: info = m_nextsib.elementAt(identity);
0537: if (info == NOTPROCESSED && !isMore)
0538: return NULL;
0539: }
0540: }
0541:
0542: return info;
0543: }
0544:
0545: /**
0546: * Get the previous sibling for the given node identity.
0547: *
0548: * @param identity The node identity.
0549: *
0550: * @return The previous sibling identity, or DTM.NULL.
0551: */
0552: protected int _prevsib(int identity) {
0553:
0554: if (identity < m_size)
0555: return m_prevsib.elementAt(identity);
0556:
0557: // Check to see if the information requested has been processed, and,
0558: // if not, advance the iterator until we the information has been
0559: // processed.
0560: while (true) {
0561: boolean isMore = nextNode();
0562:
0563: if (identity >= m_size && !isMore)
0564: return NULL;
0565: else if (identity < m_size)
0566: return m_prevsib.elementAt(identity);
0567: }
0568: }
0569:
0570: /**
0571: * Get the parent for the given node identity.
0572: *
0573: * @param identity The node identity.
0574: *
0575: * @return The parent identity, or DTM.NULL.
0576: */
0577: protected int _parent(int identity) {
0578:
0579: if (identity < m_size)
0580: return m_parent.elementAt(identity);
0581:
0582: // Check to see if the information requested has been processed, and,
0583: // if not, advance the iterator until we the information has been
0584: // processed.
0585: while (true) {
0586: boolean isMore = nextNode();
0587:
0588: if (identity >= m_size && !isMore)
0589: return NULL;
0590: else if (identity < m_size)
0591: return m_parent.elementAt(identity);
0592: }
0593: }
0594:
0595: /**
0596: * Diagnostics function to dump the DTM.
0597: */
0598: public void dumpDTM(OutputStream os) {
0599: try {
0600: if (os == null) {
0601: File f = new File("DTMDump"
0602: + ((Object) this ).hashCode() + ".txt");
0603: System.err.println("Dumping... " + f.getAbsolutePath());
0604: os = new FileOutputStream(f);
0605: }
0606: PrintStream ps = new PrintStream(os);
0607:
0608: while (nextNode()) {
0609: }
0610:
0611: int nRecords = m_size;
0612:
0613: ps.println("Total nodes: " + nRecords);
0614:
0615: for (int index = 0; index < nRecords; ++index) {
0616: int i = makeNodeHandle(index);
0617: ps.println("=========== index=" + index + " handle="
0618: + i + " ===========");
0619: ps.println("NodeName: " + getNodeName(i));
0620: ps.println("NodeNameX: " + getNodeNameX(i));
0621: ps.println("LocalName: " + getLocalName(i));
0622: ps.println("NamespaceURI: " + getNamespaceURI(i));
0623: ps.println("Prefix: " + getPrefix(i));
0624:
0625: int exTypeID = _exptype(index);
0626:
0627: ps.println("Expanded Type ID: "
0628: + Integer.toHexString(exTypeID));
0629:
0630: int type = _type(index);
0631: String typestring;
0632:
0633: switch (type) {
0634: case DTM.ATTRIBUTE_NODE:
0635: typestring = "ATTRIBUTE_NODE";
0636: break;
0637: case DTM.CDATA_SECTION_NODE:
0638: typestring = "CDATA_SECTION_NODE";
0639: break;
0640: case DTM.COMMENT_NODE:
0641: typestring = "COMMENT_NODE";
0642: break;
0643: case DTM.DOCUMENT_FRAGMENT_NODE:
0644: typestring = "DOCUMENT_FRAGMENT_NODE";
0645: break;
0646: case DTM.DOCUMENT_NODE:
0647: typestring = "DOCUMENT_NODE";
0648: break;
0649: case DTM.DOCUMENT_TYPE_NODE:
0650: typestring = "DOCUMENT_NODE";
0651: break;
0652: case DTM.ELEMENT_NODE:
0653: typestring = "ELEMENT_NODE";
0654: break;
0655: case DTM.ENTITY_NODE:
0656: typestring = "ENTITY_NODE";
0657: break;
0658: case DTM.ENTITY_REFERENCE_NODE:
0659: typestring = "ENTITY_REFERENCE_NODE";
0660: break;
0661: case DTM.NAMESPACE_NODE:
0662: typestring = "NAMESPACE_NODE";
0663: break;
0664: case DTM.NOTATION_NODE:
0665: typestring = "NOTATION_NODE";
0666: break;
0667: case DTM.NULL:
0668: typestring = "NULL";
0669: break;
0670: case DTM.PROCESSING_INSTRUCTION_NODE:
0671: typestring = "PROCESSING_INSTRUCTION_NODE";
0672: break;
0673: case DTM.TEXT_NODE:
0674: typestring = "TEXT_NODE";
0675: break;
0676: default:
0677: typestring = "Unknown!";
0678: break;
0679: }
0680:
0681: ps.println("Type: " + typestring);
0682:
0683: int firstChild = _firstch(index);
0684:
0685: if (DTM.NULL == firstChild)
0686: ps.println("First child: DTM.NULL");
0687: else if (NOTPROCESSED == firstChild)
0688: ps.println("First child: NOTPROCESSED");
0689: else
0690: ps.println("First child: " + firstChild);
0691:
0692: if (m_prevsib != null) {
0693: int prevSibling = _prevsib(index);
0694:
0695: if (DTM.NULL == prevSibling)
0696: ps.println("Prev sibling: DTM.NULL");
0697: else if (NOTPROCESSED == prevSibling)
0698: ps.println("Prev sibling: NOTPROCESSED");
0699: else
0700: ps.println("Prev sibling: " + prevSibling);
0701: }
0702:
0703: int nextSibling = _nextsib(index);
0704:
0705: if (DTM.NULL == nextSibling)
0706: ps.println("Next sibling: DTM.NULL");
0707: else if (NOTPROCESSED == nextSibling)
0708: ps.println("Next sibling: NOTPROCESSED");
0709: else
0710: ps.println("Next sibling: " + nextSibling);
0711:
0712: int parent = _parent(index);
0713:
0714: if (DTM.NULL == parent)
0715: ps.println("Parent: DTM.NULL");
0716: else if (NOTPROCESSED == parent)
0717: ps.println("Parent: NOTPROCESSED");
0718: else
0719: ps.println("Parent: " + parent);
0720:
0721: int level = _level(index);
0722:
0723: ps.println("Level: " + level);
0724: ps.println("Node Value: " + getNodeValue(i));
0725: ps.println("String Value: " + getStringValue(i));
0726: }
0727: } catch (IOException ioe) {
0728: ioe.printStackTrace(System.err);
0729: throw new RuntimeException(ioe.getMessage());
0730: }
0731: }
0732:
0733: /**
0734: * Diagnostics function to dump a single node.
0735: *
0736: * %REVIEW% KNOWN GLITCH: If you pass it a node index rather than a
0737: * node handle, it works just fine... but the displayed identity
0738: * number before the colon is different, which complicates comparing
0739: * it with nodes printed the other way. We could always OR the DTM ID
0740: * into the value, to suppress that distinction...
0741: *
0742: * %REVIEW% This might want to be moved up to DTMDefaultBase, or possibly
0743: * DTM itself, since it's a useful diagnostic and uses only DTM's public
0744: * APIs.
0745: */
0746: public String dumpNode(int nodeHandle) {
0747: if (nodeHandle == DTM.NULL)
0748: return "[null]";
0749:
0750: String typestring;
0751: switch (getNodeType(nodeHandle)) {
0752: case DTM.ATTRIBUTE_NODE:
0753: typestring = "ATTR";
0754: break;
0755: case DTM.CDATA_SECTION_NODE:
0756: typestring = "CDATA";
0757: break;
0758: case DTM.COMMENT_NODE:
0759: typestring = "COMMENT";
0760: break;
0761: case DTM.DOCUMENT_FRAGMENT_NODE:
0762: typestring = "DOC_FRAG";
0763: break;
0764: case DTM.DOCUMENT_NODE:
0765: typestring = "DOC";
0766: break;
0767: case DTM.DOCUMENT_TYPE_NODE:
0768: typestring = "DOC_TYPE";
0769: break;
0770: case DTM.ELEMENT_NODE:
0771: typestring = "ELEMENT";
0772: break;
0773: case DTM.ENTITY_NODE:
0774: typestring = "ENTITY";
0775: break;
0776: case DTM.ENTITY_REFERENCE_NODE:
0777: typestring = "ENT_REF";
0778: break;
0779: case DTM.NAMESPACE_NODE:
0780: typestring = "NAMESPACE";
0781: break;
0782: case DTM.NOTATION_NODE:
0783: typestring = "NOTATION";
0784: break;
0785: case DTM.NULL:
0786: typestring = "null";
0787: break;
0788: case DTM.PROCESSING_INSTRUCTION_NODE:
0789: typestring = "PI";
0790: break;
0791: case DTM.TEXT_NODE:
0792: typestring = "TEXT";
0793: break;
0794: default:
0795: typestring = "Unknown!";
0796: break;
0797: }
0798:
0799: StringBuffer sb = new StringBuffer();
0800: sb.append("[" + nodeHandle + ": " + typestring + "(0x"
0801: + Integer.toHexString(getExpandedTypeID(nodeHandle))
0802: + ") " + getNodeNameX(nodeHandle) + " {"
0803: + getNamespaceURI(nodeHandle) + "}" + "=\""
0804: + getNodeValue(nodeHandle) + "\"]");
0805: return sb.toString();
0806: }
0807:
0808: // ========= DTM Implementation Control Functions. ==============
0809:
0810: /**
0811: * Set an implementation dependent feature.
0812: * <p>
0813: * %REVIEW% Do we really expect to set features on DTMs?
0814: *
0815: * @param featureId A feature URL.
0816: * @param state true if this feature should be on, false otherwise.
0817: */
0818: public void setFeature(String featureId, boolean state) {
0819: }
0820:
0821: // ========= Document Navigation Functions =========
0822:
0823: /**
0824: * Given a node handle, test if it has child nodes.
0825: * <p> %REVIEW% This is obviously useful at the DOM layer, where it
0826: * would permit testing this without having to create a proxy
0827: * node. It's less useful in the DTM API, where
0828: * (dtm.getFirstChild(nodeHandle)!=DTM.NULL) is just as fast and
0829: * almost as self-evident. But it's a convenience, and eases porting
0830: * of DOM code to DTM. </p>
0831: *
0832: * @param nodeHandle int Handle of the node.
0833: * @return int true if the given node has child nodes.
0834: */
0835: public boolean hasChildNodes(int nodeHandle) {
0836:
0837: int identity = makeNodeIdentity(nodeHandle);
0838: int firstChild = _firstch(identity);
0839:
0840: return firstChild != DTM.NULL;
0841: }
0842:
0843: /** Given a node identity, return a node handle. If extended addressing
0844: * has been used (multiple DTM IDs), we need to map the high bits of the
0845: * identity into the proper DTM ID.
0846: *
0847: * This has been made FINAL to facilitate inlining, since we do not expect
0848: * any subclass of DTMDefaultBase to ever change the algorithm. (I don't
0849: * really like doing so, and would love to have an excuse not to...)
0850: *
0851: * %REVIEW% Is it worth trying to specialcase small documents?
0852: * %REVIEW% Should this be exposed at the package/public layers?
0853: *
0854: * @param nodeIdentity Internal offset to this node's records.
0855: * @return NodeHandle (external representation of node)
0856: * */
0857: final public int makeNodeHandle(int nodeIdentity) {
0858: if (NULL == nodeIdentity)
0859: return NULL;
0860:
0861: if (JJK_DEBUG && nodeIdentity > DTMManager.IDENT_NODE_DEFAULT)
0862: System.err
0863: .println("GONK! (only useful in limited situations)");
0864:
0865: return m_dtmIdent
0866: .elementAt(nodeIdentity >>> DTMManager.IDENT_DTM_NODE_BITS)
0867: + (nodeIdentity & DTMManager.IDENT_NODE_DEFAULT);
0868: }
0869:
0870: /** Given a node handle, return a node identity. If extended addressing
0871: * has been used (multiple DTM IDs), we need to map the high bits of the
0872: * identity into the proper DTM ID and thence find the proper offset
0873: * to add to the low bits of the identity
0874: *
0875: * This has been made FINAL to facilitate inlining, since we do not expect
0876: * any subclass of DTMDefaultBase to ever change the algorithm. (I don't
0877: * really like doing so, and would love to have an excuse not to...)
0878: *
0879: * %OPT% Performance is critical for this operation.
0880: *
0881: * %REVIEW% Should this be exposed at the package/public layers?
0882: *
0883: * @param nodeHandle (external representation of node)
0884: * @return nodeIdentity Internal offset to this node's records.
0885: * */
0886: final public int makeNodeIdentity(int nodeHandle) {
0887: if (NULL == nodeHandle)
0888: return NULL;
0889:
0890: if (m_mgrDefault != null) {
0891: // Optimization: use the DTMManagerDefault's fast DTMID-to-offsets
0892: // table. I'm not wild about this solution but this operation
0893: // needs need extreme speed.
0894:
0895: int whichDTMindex = nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS;
0896:
0897: // %REVIEW% Wish I didn't have to perform the pre-test, but
0898: // someone is apparently asking DTMs whether they contain nodes
0899: // which really don't belong to them. That's probably a bug
0900: // which should be fixed, but until it is:
0901: if (m_mgrDefault.m_dtms[whichDTMindex] != this )
0902: return NULL;
0903: else
0904: return m_mgrDefault.m_dtm_offsets[whichDTMindex]
0905: | (nodeHandle & DTMManager.IDENT_NODE_DEFAULT);
0906: }
0907:
0908: int whichDTMid = m_dtmIdent.indexOf(nodeHandle
0909: & DTMManager.IDENT_DTM_DEFAULT);
0910: return (whichDTMid == NULL) ? NULL
0911: : (whichDTMid << DTMManager.IDENT_DTM_NODE_BITS)
0912: + (nodeHandle & DTMManager.IDENT_NODE_DEFAULT);
0913: }
0914:
0915: /**
0916: * Given a node handle, get the handle of the node's first child.
0917: * If not yet resolved, waits for more nodes to be added to the document and
0918: * tries again.
0919: *
0920: * @param nodeHandle int Handle of the node.
0921: * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
0922: */
0923: public int getFirstChild(int nodeHandle) {
0924:
0925: int identity = makeNodeIdentity(nodeHandle);
0926: int firstChild = _firstch(identity);
0927:
0928: return makeNodeHandle(firstChild);
0929: }
0930:
0931: /**
0932: * Given a node handle, get the handle of the node's first child.
0933: * If not yet resolved, waits for more nodes to be added to the document and
0934: * tries again.
0935: *
0936: * @param nodeHandle int Handle of the node.
0937: * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
0938: */
0939: public int getTypedFirstChild(int nodeHandle, int nodeType) {
0940:
0941: int firstChild, eType;
0942: if (nodeType < DTM.NTYPES) {
0943: for (firstChild = _firstch(makeNodeIdentity(nodeHandle)); firstChild != DTM.NULL; firstChild = _nextsib(firstChild)) {
0944: eType = _exptype(firstChild);
0945: if (eType == nodeType
0946: || (eType >= DTM.NTYPES && m_expandedNameTable
0947: .getType(eType) == nodeType)) {
0948: return makeNodeHandle(firstChild);
0949: }
0950: }
0951: } else {
0952: for (firstChild = _firstch(makeNodeIdentity(nodeHandle)); firstChild != DTM.NULL; firstChild = _nextsib(firstChild)) {
0953: if (_exptype(firstChild) == nodeType) {
0954: return makeNodeHandle(firstChild);
0955: }
0956: }
0957: }
0958: return DTM.NULL;
0959: }
0960:
0961: /**
0962: * Given a node handle, advance to its last child.
0963: * If not yet resolved, waits for more nodes to be added to the document and
0964: * tries again.
0965: *
0966: * @param nodeHandle int Handle of the node.
0967: * @return int Node-number of last child,
0968: * or DTM.NULL to indicate none exists.
0969: */
0970: public int getLastChild(int nodeHandle) {
0971:
0972: int identity = makeNodeIdentity(nodeHandle);
0973: int child = _firstch(identity);
0974: int lastChild = DTM.NULL;
0975:
0976: while (child != DTM.NULL) {
0977: lastChild = child;
0978: child = _nextsib(child);
0979: }
0980:
0981: return makeNodeHandle(lastChild);
0982: }
0983:
0984: /**
0985: * Retrieves an attribute node by by qualified name and namespace URI.
0986: *
0987: * @param nodeHandle int Handle of the node upon which to look up this attribute..
0988: * @param namespaceURI The namespace URI of the attribute to
0989: * retrieve, or null.
0990: * @param name The local name of the attribute to
0991: * retrieve.
0992: * @return The attribute node handle with the specified name (
0993: * <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
0994: * attribute.
0995: */
0996: public abstract int getAttributeNode(int nodeHandle,
0997: String namespaceURI, String name);
0998:
0999: /**
1000: * Given a node handle, get the index of the node's first attribute.
1001: *
1002: * @param nodeHandle int Handle of the node.
1003: * @return Handle of first attribute, or DTM.NULL to indicate none exists.
1004: */
1005: public int getFirstAttribute(int nodeHandle) {
1006: int nodeID = makeNodeIdentity(nodeHandle);
1007:
1008: return makeNodeHandle(getFirstAttributeIdentity(nodeID));
1009: }
1010:
1011: /**
1012: * Given a node identity, get the index of the node's first attribute.
1013: *
1014: * @param identity int identity of the node.
1015: * @return Identity of first attribute, or DTM.NULL to indicate none exists.
1016: */
1017: protected int getFirstAttributeIdentity(int identity) {
1018: int type = _type(identity);
1019:
1020: if (DTM.ELEMENT_NODE == type) {
1021: // Assume that attributes and namespaces immediately follow the element.
1022: while (DTM.NULL != (identity = getNextNodeIdentity(identity))) {
1023:
1024: // Assume this can not be null.
1025: type = _type(identity);
1026:
1027: if (type == DTM.ATTRIBUTE_NODE) {
1028: return identity;
1029: } else if (DTM.NAMESPACE_NODE != type) {
1030: break;
1031: }
1032: }
1033: }
1034:
1035: return DTM.NULL;
1036: }
1037:
1038: /**
1039: * Given a node handle and an expanded type ID, get the index of the node's
1040: * attribute of that type, if any.
1041: *
1042: * @param nodeHandle int Handle of the node.
1043: * @param attType int expanded type ID of the required attribute.
1044: * @return Handle of attribute of the required type, or DTM.NULL to indicate
1045: * none exists.
1046: */
1047: protected int getTypedAttribute(int nodeHandle, int attType) {
1048: int type = getNodeType(nodeHandle);
1049: if (DTM.ELEMENT_NODE == type) {
1050: int identity = makeNodeIdentity(nodeHandle);
1051:
1052: while (DTM.NULL != (identity = getNextNodeIdentity(identity))) {
1053: type = _type(identity);
1054:
1055: if (type == DTM.ATTRIBUTE_NODE) {
1056: if (_exptype(identity) == attType)
1057: return makeNodeHandle(identity);
1058: } else if (DTM.NAMESPACE_NODE != type) {
1059: break;
1060: }
1061: }
1062: }
1063:
1064: return DTM.NULL;
1065: }
1066:
1067: /**
1068: * Given a node handle, advance to its next sibling.
1069: * If not yet resolved, waits for more nodes to be added to the document and
1070: * tries again.
1071: * @param nodeHandle int Handle of the node.
1072: * @return int Node-number of next sibling,
1073: * or DTM.NULL to indicate none exists.
1074: */
1075: public int getNextSibling(int nodeHandle) {
1076: if (nodeHandle == DTM.NULL)
1077: return DTM.NULL;
1078: return makeNodeHandle(_nextsib(makeNodeIdentity(nodeHandle)));
1079: }
1080:
1081: /**
1082: * Given a node handle, advance to its next sibling.
1083: * If not yet resolved, waits for more nodes to be added to the document and
1084: * tries again.
1085: * @param nodeHandle int Handle of the node.
1086: * @return int Node-number of next sibling,
1087: * or DTM.NULL to indicate none exists.
1088: */
1089: public int getTypedNextSibling(int nodeHandle, int nodeType) {
1090: if (nodeHandle == DTM.NULL)
1091: return DTM.NULL;
1092: int node = makeNodeIdentity(nodeHandle);
1093: int eType;
1094: while ((node = _nextsib(node)) != DTM.NULL
1095: && ((eType = _exptype(node)) != nodeType && m_expandedNameTable
1096: .getType(eType) != nodeType))
1097: ;
1098: //_type(node) != nodeType));
1099:
1100: return (node == DTM.NULL ? DTM.NULL : makeNodeHandle(node));
1101: }
1102:
1103: /**
1104: * Given a node handle, find its preceeding sibling.
1105: * WARNING: DTM is asymmetric; this operation is resolved by search, and is
1106: * relatively expensive.
1107: *
1108: * @param nodeHandle the id of the node.
1109: * @return int Node-number of the previous sib,
1110: * or DTM.NULL to indicate none exists.
1111: */
1112: public int getPreviousSibling(int nodeHandle) {
1113: if (nodeHandle == DTM.NULL)
1114: return DTM.NULL;
1115:
1116: if (m_prevsib != null)
1117: return makeNodeHandle(_prevsib(makeNodeIdentity(nodeHandle)));
1118: else {
1119: // If the previous sibling array is not built, we get at
1120: // the previous sibling using the parent, firstch and
1121: // nextsib arrays.
1122: int nodeID = makeNodeIdentity(nodeHandle);
1123: int parent = _parent(nodeID);
1124: int node = _firstch(parent);
1125: int result = DTM.NULL;
1126: while (node != nodeID) {
1127: result = node;
1128: node = _nextsib(node);
1129: }
1130: return makeNodeHandle(result);
1131: }
1132: }
1133:
1134: /**
1135: * Given a node handle, advance to the next attribute.
1136: * If an attr, we advance to
1137: * the next attr on the same node. If not an attribute, we return NULL.
1138: *
1139: * @param nodeHandle int Handle of the node.
1140: * @return int DTM node-number of the resolved attr,
1141: * or DTM.NULL to indicate none exists.
1142: */
1143: public int getNextAttribute(int nodeHandle) {
1144: int nodeID = makeNodeIdentity(nodeHandle);
1145:
1146: if (_type(nodeID) == DTM.ATTRIBUTE_NODE) {
1147: return makeNodeHandle(getNextAttributeIdentity(nodeID));
1148: }
1149:
1150: return DTM.NULL;
1151: }
1152:
1153: /**
1154: * Given a node identity for an attribute, advance to the next attribute.
1155: *
1156: * @param identity int identity of the attribute node. This
1157: * <strong>must</strong> be an attribute node.
1158: *
1159: * @return int DTM node-identity of the resolved attr,
1160: * or DTM.NULL to indicate none exists.
1161: *
1162: */
1163: protected int getNextAttributeIdentity(int identity) {
1164: // Assume that attributes and namespace nodes immediately follow the element
1165: while (DTM.NULL != (identity = getNextNodeIdentity(identity))) {
1166: int type = _type(identity);
1167:
1168: if (type == DTM.ATTRIBUTE_NODE) {
1169: return identity;
1170: } else if (type != DTM.NAMESPACE_NODE) {
1171: break;
1172: }
1173: }
1174:
1175: return DTM.NULL;
1176: }
1177:
1178: /** Lazily created namespace lists. */
1179: private Vector m_namespaceLists = null; // on demand
1180:
1181: /** Build table of namespace declaration
1182: * locations during DTM construction. Table is a Vector of
1183: * SuballocatedIntVectors containing the namespace node HANDLES declared at
1184: * that ID, plus an SuballocatedIntVector of the element node INDEXES at which
1185: * these declarations appeared.
1186: *
1187: * NOTE: Since this occurs during model build, nodes will be encountered
1188: * in doucment order and thus the table will be ordered by element,
1189: * permitting binary-search as a possible retrieval optimization.
1190: *
1191: * %REVIEW% Directly managed arrays rather than vectors?
1192: * %REVIEW% Handles or IDs? Given usage, I think handles.
1193: * */
1194: protected void declareNamespaceInContext(int elementNodeIndex,
1195: int namespaceNodeIndex) {
1196: SuballocatedIntVector nsList = null;
1197: if (m_namespaceDeclSets == null) {
1198:
1199: // First
1200: m_namespaceDeclSetElements = new SuballocatedIntVector(32);
1201: m_namespaceDeclSetElements.addElement(elementNodeIndex);
1202: m_namespaceDeclSets = new Vector();
1203: nsList = new SuballocatedIntVector(32);
1204: m_namespaceDeclSets.addElement(nsList);
1205: } else {
1206: // Most recent. May be -1 (none) if DTM was pruned.
1207: // %OPT% Is there a lastElement() method? Should there be?
1208: int last = m_namespaceDeclSetElements.size() - 1;
1209:
1210: if (last >= 0
1211: && elementNodeIndex == m_namespaceDeclSetElements
1212: .elementAt(last)) {
1213: nsList = (SuballocatedIntVector) m_namespaceDeclSets
1214: .elementAt(last);
1215: }
1216: }
1217: if (nsList == null) {
1218: m_namespaceDeclSetElements.addElement(elementNodeIndex);
1219:
1220: SuballocatedIntVector inherited = findNamespaceContext(_parent(elementNodeIndex));
1221:
1222: if (inherited != null) {
1223: // %OPT% Count-down might be faster, but debuggability may
1224: // be better this way, and if we ever decide we want to
1225: // keep this ordered by expanded-type...
1226: int isize = inherited.size();
1227:
1228: // Base the size of a new namespace list on the
1229: // size of the inherited list - but within reason!
1230: nsList = new SuballocatedIntVector(Math.max(Math.min(
1231: isize + 16, 2048), 32));
1232:
1233: for (int i = 0; i < isize; ++i) {
1234: nsList.addElement(inherited.elementAt(i));
1235: }
1236: } else {
1237: nsList = new SuballocatedIntVector(32);
1238: }
1239:
1240: m_namespaceDeclSets.addElement(nsList);
1241: }
1242:
1243: // Handle overwriting inherited.
1244: // %OPT% Keep sorted? (By expanded-name rather than by doc order...)
1245: // Downside: Would require insertElementAt if not found,
1246: // which has recopying costs. But these are generally short lists...
1247: int newEType = _exptype(namespaceNodeIndex);
1248:
1249: for (int i = nsList.size() - 1; i >= 0; --i) {
1250: if (newEType == getExpandedTypeID(nsList.elementAt(i))) {
1251: nsList.setElementAt(makeNodeHandle(namespaceNodeIndex),
1252: i);
1253: return;
1254: }
1255: }
1256: nsList.addElement(makeNodeHandle(namespaceNodeIndex));
1257: }
1258:
1259: /** Retrieve list of namespace declaration locations
1260: * active at this node. List is an SuballocatedIntVector whose
1261: * entries are the namespace node HANDLES declared at that ID.
1262: *
1263: * %REVIEW% Directly managed arrays rather than vectors?
1264: * %REVIEW% Handles or IDs? Given usage, I think handles.
1265: * */
1266: protected SuballocatedIntVector findNamespaceContext(
1267: int elementNodeIndex) {
1268: if (null != m_namespaceDeclSetElements) {
1269: // %OPT% Is binary-search really saving us a lot versus linear?
1270: // (... It may be, in large docs with many NS decls.)
1271: int wouldBeAt = findInSortedSuballocatedIntVector(
1272: m_namespaceDeclSetElements, elementNodeIndex);
1273: if (wouldBeAt >= 0) // Found it
1274: return (SuballocatedIntVector) m_namespaceDeclSets
1275: .elementAt(wouldBeAt);
1276: if (wouldBeAt == -1) // -1-wouldbeat == 0
1277: return null; // Not after anything; definitely not found
1278:
1279: // Not found, but we know where it should have been.
1280: // Search back until we find an ancestor or run out.
1281: wouldBeAt = -1 - wouldBeAt;
1282:
1283: // Decrement wouldBeAt to find last possible ancestor
1284: int candidate = m_namespaceDeclSetElements
1285: .elementAt(--wouldBeAt);
1286: int ancestor = _parent(elementNodeIndex);
1287:
1288: // Special case: if the candidate is before the given node, and
1289: // is in the earliest possible position in the document, it
1290: // must have the namespace declarations we're interested in.
1291: if (wouldBeAt == 0 && candidate < ancestor) {
1292: int rootHandle = getDocumentRoot(makeNodeHandle(elementNodeIndex));
1293: int rootID = makeNodeIdentity(rootHandle);
1294: int uppermostNSCandidateID;
1295:
1296: if (getNodeType(rootHandle) == DTM.DOCUMENT_NODE) {
1297: int ch = _firstch(rootID);
1298: uppermostNSCandidateID = (ch != DTM.NULL) ? ch
1299: : rootID;
1300: } else {
1301: uppermostNSCandidateID = rootID;
1302: }
1303:
1304: if (candidate == uppermostNSCandidateID) {
1305: return (SuballocatedIntVector) m_namespaceDeclSets
1306: .elementAt(wouldBeAt);
1307: }
1308: }
1309:
1310: while (wouldBeAt >= 0 && ancestor > 0) {
1311: if (candidate == ancestor) {
1312: // Found ancestor in list
1313: return (SuballocatedIntVector) m_namespaceDeclSets
1314: .elementAt(wouldBeAt);
1315: } else if (candidate < ancestor) {
1316: // Too deep in tree
1317: do {
1318: ancestor = _parent(ancestor);
1319: } while (candidate < ancestor);
1320: } else if (wouldBeAt > 0) {
1321: // Too late in list
1322: candidate = m_namespaceDeclSetElements
1323: .elementAt(--wouldBeAt);
1324: } else
1325: break;
1326: }
1327: }
1328:
1329: return null; // No namespaces known at this node
1330: }
1331:
1332: /**
1333: * Subroutine: Locate the specified node within
1334: * m_namespaceDeclSetElements, or the last element which
1335: * preceeds it in document order
1336: *
1337: * %REVIEW% Inlne this into findNamespaceContext? Create SortedSuballocatedIntVector type?
1338: *
1339: * @return If positive or zero, the index of the found item.
1340: * If negative, index of the point at which it would have appeared,
1341: * encoded as -1-index and hence reconvertable by subtracting
1342: * it from -1. (Encoding because I don't want to recompare the strings
1343: * but don't want to burn bytes on a datatype to hold a flagged value.)
1344: */
1345: protected int findInSortedSuballocatedIntVector(
1346: SuballocatedIntVector vector, int lookfor) {
1347: // Binary search
1348: int i = 0;
1349: if (vector != null) {
1350: int first = 0;
1351: int last = vector.size() - 1;
1352:
1353: while (first <= last) {
1354: i = (first + last) / 2;
1355: int test = lookfor - vector.elementAt(i);
1356: if (test == 0) {
1357: return i; // Name found
1358: } else if (test < 0) {
1359: last = i - 1; // looked too late
1360: } else {
1361: first = i + 1; // looked ot early
1362: }
1363: }
1364:
1365: if (first > i) {
1366: i = first; // Clean up at loop end
1367: }
1368: }
1369:
1370: return -1 - i; // not-found has to be encoded.
1371: }
1372:
1373: /**
1374: * Given a node handle, get the index of the node's first child.
1375: * If not yet resolved, waits for more nodes to be added to the document and
1376: * tries again
1377: *
1378: * @param nodeHandle handle to node, which should probably be an element
1379: * node, but need not be.
1380: *
1381: * @param inScope true if all namespaces in scope should be returned,
1382: * false if only the namespace declarations should be
1383: * returned.
1384: * @return handle of first namespace, or DTM.NULL to indicate none exists.
1385: */
1386: public int getFirstNamespaceNode(int nodeHandle, boolean inScope) {
1387: if (inScope) {
1388: int identity = makeNodeIdentity(nodeHandle);
1389: if (_type(identity) == DTM.ELEMENT_NODE) {
1390: SuballocatedIntVector nsContext = findNamespaceContext(identity);
1391: if (nsContext == null || nsContext.size() < 1)
1392: return NULL;
1393:
1394: return nsContext.elementAt(0);
1395: } else
1396: return NULL;
1397: } else {
1398: // Assume that attributes and namespaces immediately
1399: // follow the element.
1400: //
1401: // %OPT% Would things be faster if all NS nodes were built
1402: // before all Attr nodes? Some costs at build time for 2nd
1403: // pass...
1404: int identity = makeNodeIdentity(nodeHandle);
1405: if (_type(identity) == DTM.ELEMENT_NODE) {
1406: while (DTM.NULL != (identity = getNextNodeIdentity(identity))) {
1407: int type = _type(identity);
1408: if (type == DTM.NAMESPACE_NODE)
1409: return makeNodeHandle(identity);
1410: else if (DTM.ATTRIBUTE_NODE != type)
1411: break;
1412: }
1413: return NULL;
1414: } else
1415: return NULL;
1416: }
1417: }
1418:
1419: /**
1420: * Given a namespace handle, advance to the next namespace.
1421: *
1422: * @param baseHandle handle to original node from where the first namespace
1423: * was relative to (needed to return nodes in document order).
1424: * @param nodeHandle A namespace handle for which we will find the next node.
1425: * @param inScope true if all namespaces that are in scope should be processed,
1426: * otherwise just process the nodes in the given element handle.
1427: * @return handle of next namespace, or DTM.NULL to indicate none exists.
1428: */
1429: public int getNextNamespaceNode(int baseHandle, int nodeHandle,
1430: boolean inScope) {
1431: if (inScope) {
1432: //Since we've been given the base, try direct lookup
1433: //(could look from nodeHandle but this is at least one
1434: //comparison/get-parent faster)
1435: //SuballocatedIntVector nsContext=findNamespaceContext(nodeHandle & m_mask);
1436:
1437: SuballocatedIntVector nsContext = findNamespaceContext(makeNodeIdentity(baseHandle));
1438:
1439: if (nsContext == null)
1440: return NULL;
1441: int i = 1 + nsContext.indexOf(nodeHandle);
1442: if (i <= 0 || i == nsContext.size())
1443: return NULL;
1444:
1445: return nsContext.elementAt(i);
1446: } else {
1447: // Assume that attributes and namespace nodes immediately follow the element.
1448: int identity = makeNodeIdentity(nodeHandle);
1449: while (DTM.NULL != (identity = getNextNodeIdentity(identity))) {
1450: int type = _type(identity);
1451: if (type == DTM.NAMESPACE_NODE) {
1452: return makeNodeHandle(identity);
1453: } else if (type != DTM.ATTRIBUTE_NODE) {
1454: break;
1455: }
1456: }
1457: }
1458: return DTM.NULL;
1459: }
1460:
1461: /**
1462: * Given a node handle, find its parent node.
1463: *
1464: * @param nodeHandle the id of the node.
1465: * @return int Node-number of parent,
1466: * or DTM.NULL to indicate none exists.
1467: */
1468: public int getParent(int nodeHandle) {
1469:
1470: int identity = makeNodeIdentity(nodeHandle);
1471:
1472: if (identity > 0)
1473: return makeNodeHandle(_parent(identity));
1474: else
1475: return DTM.NULL;
1476: }
1477:
1478: /**
1479: * Find the Document node handle for the document currently under construction.
1480: * PLEASE NOTE that most people should use getOwnerDocument(nodeHandle) instead;
1481: * this version of the operation is primarily intended for use during negotiation
1482: * with the DTM Manager.
1483: *
1484: * @return int Node handle of document, which should always be valid.
1485: */
1486: public int getDocument() {
1487: return m_dtmIdent.elementAt(0); // makeNodeHandle(0)
1488: }
1489:
1490: /**
1491: * Given a node handle, find the owning document node. This has the exact
1492: * same semantics as the DOM Document method of the same name, in that if
1493: * the nodeHandle is a document node, it will return NULL.
1494: *
1495: * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
1496: * binding layer. Included here as a convenience function and to
1497: * aid porting of DOM code to DTM.</p>
1498: *
1499: * @param nodeHandle the id of the node.
1500: * @return int Node handle of owning document, or -1 if the node was a Docment
1501: */
1502: public int getOwnerDocument(int nodeHandle) {
1503:
1504: if (DTM.DOCUMENT_NODE == getNodeType(nodeHandle))
1505: return DTM.NULL;
1506:
1507: return getDocumentRoot(nodeHandle);
1508: }
1509:
1510: /**
1511: * Given a node handle, find the owning document node. Unlike the DOM,
1512: * this considers the owningDocument of a Document to be itself.
1513: *
1514: * @param nodeHandle the id of the node.
1515: * @return int Node handle of owning document, or the nodeHandle if it is
1516: * a Document.
1517: */
1518: public int getDocumentRoot(int nodeHandle) {
1519: return getDocument();
1520: }
1521:
1522: /**
1523: * Get the string-value of a node as a String object
1524: * (see http://www.w3.org/TR/xpath#data-model
1525: * for the definition of a node's string-value).
1526: *
1527: * @param nodeHandle The node ID.
1528: *
1529: * @return A string object that represents the string-value of the given node.
1530: */
1531: public abstract XMLString getStringValue(int nodeHandle);
1532:
1533: /**
1534: * Get number of character array chunks in
1535: * the string-value of a node.
1536: * (see http://www.w3.org/TR/xpath#data-model
1537: * for the definition of a node's string-value).
1538: * Note that a single text node may have multiple text chunks.
1539: *
1540: * @param nodeHandle The node ID.
1541: *
1542: * @return number of character array chunks in
1543: * the string-value of a node.
1544: */
1545: public int getStringValueChunkCount(int nodeHandle) {
1546:
1547: // %TBD%
1548: error(XMLMessages.createXMLMessage(
1549: XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//("getStringValueChunkCount not yet supported!");
1550:
1551: return 0;
1552: }
1553:
1554: /**
1555: * Get a character array chunk in the string-value of a node.
1556: * (see http://www.w3.org/TR/xpath#data-model
1557: * for the definition of a node's string-value).
1558: * Note that a single text node may have multiple text chunks.
1559: *
1560: * @param nodeHandle The node ID.
1561: * @param chunkIndex Which chunk to get.
1562: * @param startAndLen An array of 2 where the start position and length of
1563: * the chunk will be returned.
1564: *
1565: * @return The character array reference where the chunk occurs.
1566: */
1567: public char[] getStringValueChunk(int nodeHandle, int chunkIndex,
1568: int[] startAndLen) {
1569:
1570: // %TBD%
1571: error(XMLMessages.createXMLMessage(
1572: XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"getStringValueChunk not yet supported!");
1573:
1574: return null;
1575: }
1576:
1577: /**
1578: * Given a node handle, return an ID that represents the node's expanded name.
1579: *
1580: * @param nodeHandle The handle to the node in question.
1581: *
1582: * @return the expanded-name id of the node.
1583: */
1584: public int getExpandedTypeID(int nodeHandle) {
1585: // %REVIEW% This _should_ only be null if someone asked the wrong DTM about the node...
1586: // which one would hope would never happen...
1587: int id = makeNodeIdentity(nodeHandle);
1588: if (id == NULL)
1589: return NULL;
1590: return _exptype(id);
1591: }
1592:
1593: /**
1594: * Given an expanded name, return an ID. If the expanded-name does not
1595: * exist in the internal tables, the entry will be created, and the ID will
1596: * be returned. Any additional nodes that are created that have this
1597: * expanded name will use this ID.
1598: *
1599: * @param type The simple type, i.e. one of ELEMENT, ATTRIBUTE, etc.
1600: *
1601: * @param namespace The namespace URI, which may be null, may be an empty
1602: * string (which will be the same as null), or may be a
1603: * namespace URI.
1604: * @param localName The local name string, which must be a valid
1605: * <a href="http://www.w3.org/TR/REC-xml-names/">NCName</a>.
1606: *
1607: * @return the expanded-name id of the node.
1608: */
1609: public int getExpandedTypeID(String namespace, String localName,
1610: int type) {
1611:
1612: ExpandedNameTable ent = m_expandedNameTable;
1613:
1614: return ent.getExpandedTypeID(namespace, localName, type);
1615: }
1616:
1617: /**
1618: * Given an expanded-name ID, return the local name part.
1619: *
1620: * @param expandedNameID an ID that represents an expanded-name.
1621: * @return String Local name of this node.
1622: */
1623: public String getLocalNameFromExpandedNameID(int expandedNameID) {
1624: return m_expandedNameTable.getLocalName(expandedNameID);
1625: }
1626:
1627: /**
1628: * Given an expanded-name ID, return the namespace URI part.
1629: *
1630: * @param expandedNameID an ID that represents an expanded-name.
1631: * @return String URI value of this node's namespace, or null if no
1632: * namespace was resolved.
1633: */
1634: public String getNamespaceFromExpandedNameID(int expandedNameID) {
1635: return m_expandedNameTable.getNamespace(expandedNameID);
1636: }
1637:
1638: /**
1639: * Returns the namespace type of a specific node
1640: * @param nodeHandle the id of the node.
1641: * @return the ID of the namespace.
1642: */
1643: public int getNamespaceType(final int nodeHandle) {
1644:
1645: int identity = makeNodeIdentity(nodeHandle);
1646: int expandedNameID = _exptype(identity);
1647:
1648: return m_expandedNameTable.getNamespaceID(expandedNameID);
1649: }
1650:
1651: /**
1652: * Given a node handle, return its DOM-style node name. This will
1653: * include names such as #text or #document.
1654: *
1655: * @param nodeHandle the id of the node.
1656: * @return String Name of this node, which may be an empty string.
1657: * %REVIEW% Document when empty string is possible...
1658: * %REVIEW-COMMENT% It should never be empty, should it?
1659: */
1660: public abstract String getNodeName(int nodeHandle);
1661:
1662: /**
1663: * Given a node handle, return the XPath node name. This should be
1664: * the name as described by the XPath data model, NOT the DOM-style
1665: * name.
1666: *
1667: * @param nodeHandle the id of the node.
1668: * @return String Name of this node, which may be an empty string.
1669: */
1670: public String getNodeNameX(int nodeHandle) {
1671:
1672: /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */
1673: error(XMLMessages.createXMLMessage(
1674: XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!");
1675:
1676: return null;
1677: }
1678:
1679: /**
1680: * Given a node handle, return its XPath-style localname.
1681: * (As defined in Namespaces, this is the portion of the name after any
1682: * colon character).
1683: *
1684: * @param nodeHandle the id of the node.
1685: * @return String Local name of this node.
1686: */
1687: public abstract String getLocalName(int nodeHandle);
1688:
1689: /**
1690: * Given a namespace handle, return the prefix that the namespace decl is
1691: * mapping.
1692: * Given a node handle, return the prefix used to map to the namespace.
1693: *
1694: * <p> %REVIEW% Are you sure you want "" for no prefix? </p>
1695: * <p> %REVIEW-COMMENT% I think so... not totally sure. -sb </p>
1696: *
1697: * @param nodeHandle the id of the node.
1698: * @return String prefix of this node's name, or "" if no explicit
1699: * namespace prefix was given.
1700: */
1701: public abstract String getPrefix(int nodeHandle);
1702:
1703: /**
1704: * Given a node handle, return its DOM-style namespace URI
1705: * (As defined in Namespaces, this is the declared URI which this node's
1706: * prefix -- or default in lieu thereof -- was mapped to.)
1707: *
1708: * <p>%REVIEW% Null or ""? -sb</p>
1709: *
1710: * @param nodeHandle the id of the node.
1711: * @return String URI value of this node's namespace, or null if no
1712: * namespace was resolved.
1713: */
1714: public abstract String getNamespaceURI(int nodeHandle);
1715:
1716: /**
1717: * Given a node handle, return its node value. This is mostly
1718: * as defined by the DOM, but may ignore some conveniences.
1719: * <p>
1720: *
1721: * @param nodeHandle The node id.
1722: * @return String Value of this node, or null if not
1723: * meaningful for this node type.
1724: */
1725: public abstract String getNodeValue(int nodeHandle);
1726:
1727: /**
1728: * Given a node handle, return its DOM-style node type.
1729: * <p>
1730: * %REVIEW% Generally, returning short is false economy. Return int?
1731: * %REVIEW% Make assumption that node has already arrived. Is OK?
1732: *
1733: * @param nodeHandle The node id.
1734: * @return int Node type, as per the DOM's Node._NODE constants.
1735: */
1736: public short getNodeType(int nodeHandle) {
1737: if (nodeHandle == DTM.NULL)
1738: return DTM.NULL;
1739: return m_expandedNameTable
1740: .getType(_exptype(makeNodeIdentity(nodeHandle)));
1741: }
1742:
1743: /**
1744: * Get the depth level of this node in the tree (equals 1 for
1745: * a parentless node).
1746: *
1747: * @param nodeHandle The node id.
1748: * @return the number of ancestors, plus one
1749: * @xsl.usage internal
1750: */
1751: public short getLevel(int nodeHandle) {
1752: // Apparently, the axis walker stuff requires levels to count from 1.
1753: int identity = makeNodeIdentity(nodeHandle);
1754: return (short) (_level(identity) + 1);
1755: }
1756:
1757: /**
1758: * Get the identity of this node in the tree
1759: *
1760: * @param nodeHandle The node handle.
1761: * @return the node identity
1762: * @xsl.usage internal
1763: */
1764: public int getNodeIdent(int nodeHandle) {
1765: /*if (nodeHandle != DTM.NULL)
1766: return nodeHandle & m_mask;
1767: else
1768: return DTM.NULL;*/
1769:
1770: return makeNodeIdentity(nodeHandle);
1771: }
1772:
1773: /**
1774: * Get the handle of this node in the tree
1775: *
1776: * @param nodeId The node identity.
1777: * @return the node handle
1778: * @xsl.usage internal
1779: */
1780: public int getNodeHandle(int nodeId) {
1781: /*if (nodeId != DTM.NULL)
1782: return nodeId | m_dtmIdent;
1783: else
1784: return DTM.NULL;*/
1785:
1786: return makeNodeHandle(nodeId);
1787: }
1788:
1789: // ============== Document query functions ==============
1790:
1791: /**
1792: * Tests whether DTM DOM implementation implements a specific feature and
1793: * that feature is supported by this node.
1794: *
1795: * @param feature The name of the feature to test.
1796: * @param version This is the version number of the feature to test.
1797: * If the version is not
1798: * specified, supporting any version of the feature will cause the
1799: * method to return <code>true</code>.
1800: * @return Returns <code>true</code> if the specified feature is
1801: * supported on this node, <code>false</code> otherwise.
1802: */
1803: public boolean isSupported(String feature, String version) {
1804:
1805: // %TBD%
1806: return false;
1807: }
1808:
1809: /**
1810: * Return the base URI of the document entity. If it is not known
1811: * (because the document was parsed from a socket connection or from
1812: * standard input, for example), the value of this property is unknown.
1813: *
1814: * @return the document base URI String object or null if unknown.
1815: */
1816: public String getDocumentBaseURI() {
1817: return m_documentBaseURI;
1818: }
1819:
1820: /**
1821: * Set the base URI of the document entity.
1822: *
1823: * @param baseURI the document base URI String object or null if unknown.
1824: */
1825: public void setDocumentBaseURI(String baseURI) {
1826: m_documentBaseURI = baseURI;
1827: }
1828:
1829: /**
1830: * Return the system identifier of the document entity. If
1831: * it is not known, the value of this property is unknown.
1832: *
1833: * @param nodeHandle The node id, which can be any valid node handle.
1834: * @return the system identifier String object or null if unknown.
1835: */
1836: public String getDocumentSystemIdentifier(int nodeHandle) {
1837:
1838: // %REVIEW% OK? -sb
1839: return m_documentBaseURI;
1840: }
1841:
1842: /**
1843: * Return the name of the character encoding scheme
1844: * in which the document entity is expressed.
1845: *
1846: * @param nodeHandle The node id, which can be any valid node handle.
1847: * @return the document encoding String object.
1848: * @xsl.usage internal
1849: */
1850: public String getDocumentEncoding(int nodeHandle) {
1851:
1852: // %REVIEW% OK?? -sb
1853: return "UTF-8";
1854: }
1855:
1856: /**
1857: * Return an indication of the standalone status of the document,
1858: * either "yes" or "no". This property is derived from the optional
1859: * standalone document declaration in the XML declaration at the
1860: * beginning of the document entity, and has no value if there is no
1861: * standalone document declaration.
1862: *
1863: * @param nodeHandle The node id, which can be any valid node handle.
1864: * @return the document standalone String object, either "yes", "no", or null.
1865: */
1866: public String getDocumentStandalone(int nodeHandle) {
1867: return null;
1868: }
1869:
1870: /**
1871: * Return a string representing the XML version of the document. This
1872: * property is derived from the XML declaration optionally present at the
1873: * beginning of the document entity, and has no value if there is no XML
1874: * declaration.
1875: *
1876: * @param documentHandle The document handle
1877: *
1878: * @return the document version String object.
1879: */
1880: public String getDocumentVersion(int documentHandle) {
1881: return null;
1882: }
1883:
1884: /**
1885: * Return an indication of
1886: * whether the processor has read the complete DTD. Its value is a
1887: * boolean. If it is false, then certain properties (indicated in their
1888: * descriptions below) may be unknown. If it is true, those properties
1889: * are never unknown.
1890: *
1891: * @return <code>true</code> if all declarations were processed;
1892: * <code>false</code> otherwise.
1893: */
1894: public boolean getDocumentAllDeclarationsProcessed() {
1895:
1896: // %REVIEW% OK?
1897: return true;
1898: }
1899:
1900: /**
1901: * A document type declaration information item has the following properties:
1902: *
1903: * 1. [system identifier] The system identifier of the external subset, if
1904: * it exists. Otherwise this property has no value.
1905: *
1906: * @return the system identifier String object, or null if there is none.
1907: */
1908: public abstract String getDocumentTypeDeclarationSystemIdentifier();
1909:
1910: /**
1911: * Return the public identifier of the external subset,
1912: * normalized as described in 4.2.2 External Entities [XML]. If there is
1913: * no external subset or if it has no public identifier, this property
1914: * has no value.
1915: *
1916: * @return the public identifier String object, or null if there is none.
1917: */
1918: public abstract String getDocumentTypeDeclarationPublicIdentifier();
1919:
1920: /**
1921: * Returns the <code>Element</code> whose <code>ID</code> is given by
1922: * <code>elementId</code>. If no such element exists, returns
1923: * <code>DTM.NULL</code>. Behavior is not defined if more than one element
1924: * has this <code>ID</code>. Attributes (including those
1925: * with the name "ID") are not of type ID unless so defined by DTD/Schema
1926: * information available to the DTM implementation.
1927: * Implementations that do not know whether attributes are of type ID or
1928: * not are expected to return <code>DTM.NULL</code>.
1929: *
1930: * <p>%REVIEW% Presumably IDs are still scoped to a single document,
1931: * and this operation searches only within a single document, right?
1932: * Wouldn't want collisions between DTMs in the same process.</p>
1933: *
1934: * @param elementId The unique <code>id</code> value for an element.
1935: * @return The handle of the matching element.
1936: */
1937: public abstract int getElementById(String elementId);
1938:
1939: /**
1940: * The getUnparsedEntityURI function returns the URI of the unparsed
1941: * entity with the specified name in the same document as the context
1942: * node (see [3.3 Unparsed Entities]). It returns the empty string if
1943: * there is no such entity.
1944: * <p>
1945: * XML processors may choose to use the System Identifier (if one
1946: * is provided) to resolve the entity, rather than the URI in the
1947: * Public Identifier. The details are dependent on the processor, and
1948: * we would have to support some form of plug-in resolver to handle
1949: * this properly. Currently, we simply return the System Identifier if
1950: * present, and hope that it a usable URI or that our caller can
1951: * map it to one.
1952: * TODO: Resolve Public Identifiers... or consider changing function name.
1953: * <p>
1954: * If we find a relative URI
1955: * reference, XML expects it to be resolved in terms of the base URI
1956: * of the document. The DOM doesn't do that for us, and it isn't
1957: * entirely clear whether that should be done here; currently that's
1958: * pushed up to a higher level of our application. (Note that DOM Level
1959: * 1 didn't store the document's base URI.)
1960: * TODO: Consider resolving Relative URIs.
1961: * <p>
1962: * (The DOM's statement that "An XML processor may choose to
1963: * completely expand entities before the structure model is passed
1964: * to the DOM" refers only to parsed entities, not unparsed, and hence
1965: * doesn't affect this function.)
1966: *
1967: * @param name A string containing the Entity Name of the unparsed
1968: * entity.
1969: *
1970: * @return String containing the URI of the Unparsed Entity, or an
1971: * empty string if no such entity exists.
1972: */
1973: public abstract String getUnparsedEntityURI(String name);
1974:
1975: // ============== Boolean methods ================
1976:
1977: /**
1978: * Return true if the xsl:strip-space or xsl:preserve-space was processed
1979: * during construction of the DTM document.
1980: *
1981: * @return true if this DTM supports prestripping.
1982: */
1983: public boolean supportsPreStripping() {
1984: return true;
1985: }
1986:
1987: /**
1988: * Figure out whether nodeHandle2 should be considered as being later
1989: * in the document than nodeHandle1, in Document Order as defined
1990: * by the XPath model. This may not agree with the ordering defined
1991: * by other XML applications.
1992: * <p>
1993: * There are some cases where ordering isn't defined, and neither are
1994: * the results of this function -- though we'll generally return false.
1995: *
1996: * @param nodeHandle1 Node handle to perform position comparison on.
1997: * @param nodeHandle2 Second Node handle to perform position comparison on .
1998: *
1999: * @return true if node1 comes before node2, otherwise return false.
2000: * You can think of this as
2001: * <code>(node1.documentOrderPosition <= node2.documentOrderPosition)</code>.
2002: */
2003: public boolean isNodeAfter(int nodeHandle1, int nodeHandle2) {
2004: // These return NULL if the node doesn't belong to this document.
2005: int index1 = makeNodeIdentity(nodeHandle1);
2006: int index2 = makeNodeIdentity(nodeHandle2);
2007:
2008: return index1 != NULL && index2 != NULL && index1 <= index2;
2009: }
2010:
2011: /**
2012: * 2. [element content whitespace] A boolean indicating whether the
2013: * character is white space appearing within element content (see [XML],
2014: * 2.10 "White Space Handling"). Note that validating XML processors are
2015: * required by XML 1.0 to provide this information. If there is no
2016: * declaration for the containing element, this property has no value for
2017: * white space characters. If no declaration has been read, but the [all
2018: * declarations processed] property of the document information item is
2019: * false (so there may be an unread declaration), then the value of this
2020: * property is unknown for white space characters. It is always false for
2021: * characters that are not white space.
2022: *
2023: * @param nodeHandle the node ID.
2024: * @return <code>true</code> if the character data is whitespace;
2025: * <code>false</code> otherwise.
2026: */
2027: public boolean isCharacterElementContentWhitespace(int nodeHandle) {
2028:
2029: // %TBD%
2030: return false;
2031: }
2032:
2033: /**
2034: * 10. [all declarations processed] This property is not strictly speaking
2035: * part of the infoset of the document. Rather it is an indication of
2036: * whether the processor has read the complete DTD. Its value is a
2037: * boolean. If it is false, then certain properties (indicated in their
2038: * descriptions below) may be unknown. If it is true, those properties
2039: * are never unknown.
2040: *
2041: * @param documentHandle A node handle that must identify a document.
2042: * @return <code>true</code> if all declarations were processed;
2043: * <code>false</code> otherwise.
2044: */
2045: public boolean isDocumentAllDeclarationsProcessed(int documentHandle) {
2046: return true;
2047: }
2048:
2049: /**
2050: * 5. [specified] A flag indicating whether this attribute was actually
2051: * specified in the start-tag of its element, or was defaulted from the
2052: * DTD.
2053: *
2054: * @param attributeHandle The attribute handle in question.
2055: *
2056: * @return <code>true</code> if the attribute was specified;
2057: * <code>false</code> if it was defaulted.
2058: */
2059: public abstract boolean isAttributeSpecified(int attributeHandle);
2060:
2061: // ========== Direct SAX Dispatch, for optimization purposes ========
2062:
2063: /**
2064: * Directly call the
2065: * characters method on the passed ContentHandler for the
2066: * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
2067: * for the definition of a node's string-value). Multiple calls to the
2068: * ContentHandler's characters methods may well occur for a single call to
2069: * this method.
2070: *
2071: * @param nodeHandle The node ID.
2072: * @param ch A non-null reference to a ContentHandler.
2073: * @param normalize true if the content should be normalized according to
2074: * the rules for the XPath
2075: * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
2076: * function.
2077: *
2078: * @throws org.xml.sax.SAXException
2079: */
2080: public abstract void dispatchCharactersEvents(int nodeHandle,
2081: org.xml.sax.ContentHandler ch, boolean normalize)
2082: throws org.xml.sax.SAXException;
2083:
2084: /**
2085: * Directly create SAX parser events from a subtree.
2086: *
2087: * @param nodeHandle The node ID.
2088: * @param ch A non-null reference to a ContentHandler.
2089: *
2090: * @throws org.xml.sax.SAXException
2091: */
2092: public abstract void dispatchToEvents(int nodeHandle,
2093: org.xml.sax.ContentHandler ch)
2094: throws org.xml.sax.SAXException;
2095:
2096: /**
2097: * Return an DOM node for the given node.
2098: *
2099: * @param nodeHandle The node ID.
2100: *
2101: * @return A node representation of the DTM node.
2102: */
2103: public org.w3c.dom.Node getNode(int nodeHandle) {
2104: return new DTMNodeProxy(this , nodeHandle);
2105: }
2106:
2107: // ==== Construction methods (may not be supported by some implementations!) =====
2108:
2109: /**
2110: * Append a child to the end of the document. Please note that the node
2111: * is always cloned if it is owned by another document.
2112: *
2113: * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2114: * Does it become the last child of the Document? Of the root element?</p>
2115: *
2116: * @param newChild Must be a valid new node handle.
2117: * @param clone true if the child should be cloned into the document.
2118: * @param cloneDepth if the clone argument is true, specifies that the
2119: * clone should include all it's children.
2120: */
2121: public void appendChild(int newChild, boolean clone,
2122: boolean cloneDepth) {
2123: error(XMLMessages.createXMLMessage(
2124: XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendChild not yet supported!");
2125: }
2126:
2127: /**
2128: * Append a text node child that will be constructed from a string,
2129: * to the end of the document.
2130: *
2131: * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2132: * Does it become the last child of the Document? Of the root element?</p>
2133: *
2134: * @param str Non-null reverence to a string.
2135: */
2136: public void appendTextChild(String str) {
2137: error(XMLMessages.createXMLMessage(
2138: XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendTextChild not yet supported!");
2139: }
2140:
2141: /**
2142: * Simple error for asserts and the like.
2143: *
2144: * @param msg Error message to report.
2145: */
2146: protected void error(String msg) {
2147: throw new DTMException(msg);
2148: }
2149:
2150: /**
2151: * Find out whether or not to strip whispace nodes.
2152: *
2153: *
2154: * @return whether or not to strip whispace nodes.
2155: */
2156: protected boolean getShouldStripWhitespace() {
2157: return m_shouldStripWS;
2158: }
2159:
2160: /**
2161: * Set whether to strip whitespaces and push in current value of
2162: * m_shouldStripWS in m_shouldStripWhitespaceStack.
2163: *
2164: * @param shouldStrip Flag indicating whether to strip whitespace nodes
2165: */
2166: protected void pushShouldStripWhitespace(boolean shouldStrip) {
2167:
2168: m_shouldStripWS = shouldStrip;
2169:
2170: if (null != m_shouldStripWhitespaceStack)
2171: m_shouldStripWhitespaceStack.push(shouldStrip);
2172: }
2173:
2174: /**
2175: * Set whether to strip whitespaces at this point by popping out
2176: * m_shouldStripWhitespaceStack.
2177: *
2178: */
2179: protected void popShouldStripWhitespace() {
2180: if (null != m_shouldStripWhitespaceStack)
2181: m_shouldStripWS = m_shouldStripWhitespaceStack.popAndTop();
2182: }
2183:
2184: /**
2185: * Set whether to strip whitespaces and set the top of the stack to
2186: * the current value of m_shouldStripWS.
2187: *
2188: *
2189: * @param shouldStrip Flag indicating whether to strip whitespace nodes
2190: */
2191: protected void setShouldStripWhitespace(boolean shouldStrip) {
2192:
2193: m_shouldStripWS = shouldStrip;
2194:
2195: if (null != m_shouldStripWhitespaceStack)
2196: m_shouldStripWhitespaceStack.setTop(shouldStrip);
2197: }
2198:
2199: /**
2200: * A dummy routine to satisify the abstract interface. If the DTM
2201: * implememtation that extends the default base requires notification
2202: * of registration, they can override this method.
2203: */
2204: public void documentRegistration() {
2205: }
2206:
2207: /**
2208: * A dummy routine to satisify the abstract interface. If the DTM
2209: * implememtation that extends the default base requires notification
2210: * when the document is being released, they can override this method
2211: */
2212: public void documentRelease() {
2213: }
2214:
2215: /**
2216: * Migrate a DTM built with an old DTMManager to a new DTMManager.
2217: * After the migration, the new DTMManager will treat the DTM as
2218: * one that is built by itself.
2219: * This is used to support DTM sharing between multiple transformations.
2220: * @param mgr the DTMManager
2221: */
2222: public void migrateTo(DTMManager mgr) {
2223: m_mgr = mgr;
2224: if (mgr instanceof DTMManagerDefault)
2225: m_mgrDefault = (DTMManagerDefault) mgr;
2226: }
2227:
2228: /** Query which DTMManager this DTM is currently being handled by.
2229: *
2230: * %REVEW% Should this become part of the base DTM API?
2231: *
2232: * @return a DTMManager, or null if this is a "stand-alone" DTM.
2233: */
2234: public DTMManager getManager() {
2235: return m_mgr;
2236: }
2237:
2238: /** Query which DTMIDs this DTM is currently using within the DTMManager.
2239: *
2240: * %REVEW% Should this become part of the base DTM API?
2241: *
2242: * @return an IntVector, or null if this is a "stand-alone" DTM.
2243: */
2244: public SuballocatedIntVector getDTMIDs() {
2245: if (m_mgr == null)
2246: return null;
2247: return m_dtmIdent;
2248: }
2249: }
|