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: DTMDocumentImpl.java,v 1.16 2005/01/24 04:04:40 mcnamara Exp $
0018: */
0019: package org.apache.xml.dtm.ref;
0020:
0021: import javax.xml.transform.SourceLocator;
0022:
0023: import org.apache.xml.dtm.DTM;
0024: import org.apache.xml.dtm.DTMAxisIterator;
0025: import org.apache.xml.dtm.DTMAxisTraverser;
0026: import org.apache.xml.dtm.DTMManager;
0027: import org.apache.xml.dtm.DTMWSFilter;
0028: import org.apache.xml.utils.FastStringBuffer;
0029: import org.apache.xml.utils.XMLString;
0030: import org.apache.xml.utils.XMLStringFactory;
0031:
0032: import org.xml.sax.Attributes;
0033: import org.xml.sax.ContentHandler;
0034: import org.xml.sax.Locator;
0035: import org.xml.sax.ext.LexicalHandler;
0036:
0037: /**
0038: * This is the implementation of the DTM document interface. It receives
0039: * requests from an XML content handler similar to that of an XML DOM or SAX parser
0040: * to store information from the xml document in an array based
0041: * dtm table structure. This informtion is used later for document navigation,
0042: * query, and SAX event dispatch functions. The DTM can also be used directly as a
0043: * document composition model for an application. The requests received are:
0044: * <ul>
0045: * <li>initiating DTM to set the doc handle</li>
0046: * <li>resetting DTM for data structure reuse</li>
0047: * <li>hinting the end of document to adjust the end of data structure pointers</li>
0048: * <li>createnodes (element, comment, text, attribute, ....)</li>
0049: * <li>hinting the end of an element to patch parent and siblings<li>
0050: * <li>setting application provided symbol name stringpool data structures</li>
0051: * </ul>
0052: * <p>State: In progress!!</p>
0053: *
0054: * %REVIEW% I _think_ the SAX convention is that "no namespace" is expressed
0055: * as "" rather than as null (which is the DOM's convention). What should
0056: * DTM expect? What should it do with the other?
0057: *
0058: * <p>Origin: the implemention is a composite logic based on the DTM of XalanJ1 and
0059: * DocImpl, DocumentImpl, ElementImpl, TextImpl, etc. of XalanJ2</p>
0060: */
0061: public class DTMDocumentImpl implements DTM,
0062: org.xml.sax.ContentHandler, org.xml.sax.ext.LexicalHandler {
0063:
0064: // Number of lower bits used to represent node index.
0065: protected static final byte DOCHANDLE_SHIFT = 22;
0066: // Masks the lower order of node handle.
0067: // Same as {@link DTMConstructor.IDENT_NODE_DEFAULT}
0068: protected static final int NODEHANDLE_MASK = (1 << (DOCHANDLE_SHIFT + 1)) - 1;
0069: // Masks the higher order Document handle
0070: // Same as {@link DTMConstructor.IDENT_DOC_DEFAULT}
0071: protected static final int DOCHANDLE_MASK = -1 - NODEHANDLE_MASK;
0072:
0073: int m_docHandle = NULL; // masked document handle for this dtm document
0074: int m_docElement = NULL; // nodeHandle to the root of the actual dtm doc content
0075:
0076: // Context for parse-and-append operations
0077: int currentParent = 0; // current parent - default is document root
0078: int previousSibling = 0; // previous sibling - no previous sibling
0079: protected int m_currentNode = -1; // current node
0080:
0081: // The tree under construction can itself be used as
0082: // the element stack, so m_elemStack isn't needed.
0083: //protected Stack m_elemStack = new Stack(); // element stack
0084:
0085: private boolean previousSiblingWasParent = false;
0086: // Local cache for record-at-a-time fetch
0087: int gotslot[] = new int[4];
0088:
0089: // endDocument recieved?
0090: private boolean done = false;
0091: boolean m_isError = false;
0092:
0093: private final boolean DEBUG = false;
0094:
0095: /** The document base URI. */
0096: protected String m_documentBaseURI;
0097:
0098: /** If we're building the model incrementally on demand, we need to
0099: * be able to tell the source when to send us more data.
0100: *
0101: * Note that if this has not been set, and you attempt to read ahead
0102: * of the current build point, we'll probably throw a null-pointer
0103: * exception. We could try to wait-and-retry instead, as a very poor
0104: * fallback, but that has all the known problems with multithreading
0105: * on multiprocessors and we Don't Want to Go There.
0106: *
0107: * @see setIncrementalSAXSource
0108: */
0109: private IncrementalSAXSource m_incrSAXSource = null;
0110:
0111: // ========= DTM data structure declarations. ==============
0112:
0113: // nodes array: integer array blocks to hold the first level reference of the nodes,
0114: // each reference slot is addressed by a nodeHandle index value.
0115: // Assumes indices are not larger than {@link NODEHANDLE_MASK}
0116: // ({@link DOCHANDLE_SHIFT} bits).
0117: ChunkedIntArray nodes = new ChunkedIntArray(4);
0118:
0119: // text/comment table: string buffer to hold the text string values of the document,
0120: // each of which is addressed by the absolute offset and length in the buffer
0121: private FastStringBuffer m_char = new FastStringBuffer();
0122: // Start of string currently being accumulated into m_char;
0123: // needed because the string may be appended in several chunks.
0124: private int m_char_current_start = 0;
0125:
0126: // %TBD% INITIALIZATION/STARTUP ISSUES
0127: // -- Should we really be creating these, or should they be
0128: // passed in from outside? Scott want to be able to share
0129: // pools across multiple documents, so setting them here is
0130: // probably not the right default.
0131: private DTMStringPool m_localNames = new DTMStringPool();
0132: private DTMStringPool m_nsNames = new DTMStringPool();
0133: private DTMStringPool m_prefixNames = new DTMStringPool();
0134:
0135: // %TBD% If we use the current ExpandedNameTable mapper, it
0136: // needs to be bound to the NS and local name pools. Which
0137: // means it needs to attach to them AFTER we've resolved their
0138: // startup. Or it needs to attach to this document and
0139: // retrieve them each time. Or this needs to be
0140: // an interface _implemented_ by this class... which might be simplest!
0141: private ExpandedNameTable m_expandedNames = new ExpandedNameTable();
0142:
0143: private XMLStringFactory m_xsf;
0144:
0145: /**
0146: * Construct a DTM.
0147: *
0148: * @param documentNumber the ID number assigned to this document.
0149: * It will be shifted up into the high bits and returned as part of
0150: * all node ID numbers, so those IDs indicate which document they
0151: * came from as well as a location within the document. It is the
0152: * DTMManager's responsibility to assign a unique number to each
0153: * document.
0154: */
0155: public DTMDocumentImpl(DTMManager mgr, int documentNumber,
0156: DTMWSFilter whiteSpaceFilter,
0157: XMLStringFactory xstringfactory) {
0158: initDocument(documentNumber); // clear nodes and document handle
0159: m_xsf = xstringfactory;
0160: }
0161:
0162: /** Bind a IncrementalSAXSource to this DTM. If we discover we need nodes
0163: * that have not yet been built, we will ask this object to send us more
0164: * events, and it will manage interactions with its data sources.
0165: *
0166: * Note that we do not actually build the IncrementalSAXSource, since we don't
0167: * know what source it's reading from, what thread that source will run in,
0168: * or when it will run.
0169: *
0170: * @param source The IncrementalSAXSource that we want to recieve events from
0171: * on demand.
0172: */
0173: public void setIncrementalSAXSource(IncrementalSAXSource source) {
0174: m_incrSAXSource = source;
0175:
0176: // Establish SAX-stream link so we can receive the requested data
0177: source.setContentHandler(this );
0178: source.setLexicalHandler(this );
0179:
0180: // Are the following really needed? IncrementalSAXSource doesn't yet
0181: // support them, and they're mostly no-ops here...
0182: //source.setErrorHandler(this);
0183: //source.setDTDHandler(this);
0184: //source.setDeclHandler(this);
0185: }
0186:
0187: /**
0188: * Wrapper for ChunkedIntArray.append, to automatically update the
0189: * previous sibling's "next" reference (if necessary) and periodically
0190: * wake a reader who may have encountered incomplete data and entered
0191: * a wait state.
0192: * @param w0 int As in ChunkedIntArray.append
0193: * @param w1 int As in ChunkedIntArray.append
0194: * @param w2 int As in ChunkedIntArray.append
0195: * @param w3 int As in ChunkedIntArray.append
0196: * @return int As in ChunkedIntArray.append
0197: * @see ChunkedIntArray.append
0198: */
0199: private final int appendNode(int w0, int w1, int w2, int w3) {
0200: // A decent compiler may inline this.
0201: int slotnumber = nodes.appendSlot(w0, w1, w2, w3);
0202:
0203: if (DEBUG)
0204: System.out.println(slotnumber + ": " + w0 + " " + w1 + " "
0205: + w2 + " " + w3);
0206:
0207: if (previousSiblingWasParent)
0208: nodes.writeEntry(previousSibling, 2, slotnumber);
0209:
0210: previousSiblingWasParent = false; // Set the default; endElement overrides
0211:
0212: return slotnumber;
0213: }
0214:
0215: // ========= DTM Implementation Control Functions. ==============
0216:
0217: /**
0218: * Set an implementation dependent feature.
0219: * <p>
0220: * %REVIEW% Do we really expect to set features on DTMs?
0221: *
0222: * @param featureId A feature URL.
0223: * @param state true if this feature should be on, false otherwise.
0224: */
0225: public void setFeature(String featureId, boolean state) {
0226: };
0227:
0228: /**
0229: * Set a reference pointer to the element name symbol table.
0230: * %REVIEW% Should this really be Public? Changing it while
0231: * DTM is in use would be a disaster.
0232: *
0233: * @param poolRef DTMStringPool reference to an instance of table.
0234: */
0235: public void setLocalNameTable(DTMStringPool poolRef) {
0236: m_localNames = poolRef;
0237: }
0238:
0239: /**
0240: * Get a reference pointer to the element name symbol table.
0241: *
0242: * @return DTMStringPool reference to an instance of table.
0243: */
0244: public DTMStringPool getLocalNameTable() {
0245: return m_localNames;
0246: }
0247:
0248: /**
0249: * Set a reference pointer to the namespace URI symbol table.
0250: * %REVIEW% Should this really be Public? Changing it while
0251: * DTM is in use would be a disaster.
0252: *
0253: * @param poolRef DTMStringPool reference to an instance of table.
0254: */
0255: public void setNsNameTable(DTMStringPool poolRef) {
0256: m_nsNames = poolRef;
0257: }
0258:
0259: /**
0260: * Get a reference pointer to the namespace URI symbol table.
0261: *
0262: * @return DTMStringPool reference to an instance of table.
0263: */
0264: public DTMStringPool getNsNameTable() {
0265: return m_nsNames;
0266: }
0267:
0268: /**
0269: * Set a reference pointer to the prefix name symbol table.
0270: * %REVIEW% Should this really be Public? Changing it while
0271: * DTM is in use would be a disaster.
0272: *
0273: * @param poolRef DTMStringPool reference to an instance of table.
0274: */
0275: public void setPrefixNameTable(DTMStringPool poolRef) {
0276: m_prefixNames = poolRef;
0277: }
0278:
0279: /**
0280: * Get a reference pointer to the prefix name symbol table.
0281: *
0282: * @return DTMStringPool reference to an instance of table.
0283: */
0284: public DTMStringPool getPrefixNameTable() {
0285: return m_prefixNames;
0286: }
0287:
0288: /**
0289: * Set a reference pointer to the content-text repository
0290: *
0291: * @param buffer FastStringBuffer reference to an instance of
0292: * buffer
0293: */
0294: void setContentBuffer(FastStringBuffer buffer) {
0295: m_char = buffer;
0296: }
0297:
0298: /**
0299: * Get a reference pointer to the content-text repository
0300: *
0301: * @return FastStringBuffer reference to an instance of buffer
0302: */
0303: FastStringBuffer getContentBuffer() {
0304: return m_char;
0305: }
0306:
0307: /** getContentHandler returns "our SAX builder" -- the thing that
0308: * someone else should send SAX events to in order to extend this
0309: * DTM model.
0310: *
0311: * @return null if this model doesn't respond to SAX events,
0312: * "this" if the DTM object has a built-in SAX ContentHandler,
0313: * the IncrementalSAXSource if we're bound to one and should receive
0314: * the SAX stream via it for incremental build purposes...
0315: * */
0316: public org.xml.sax.ContentHandler getContentHandler() {
0317: if (m_incrSAXSource instanceof IncrementalSAXSource_Filter)
0318: return (ContentHandler) m_incrSAXSource;
0319: else
0320: return this ;
0321: }
0322:
0323: /**
0324: * Return this DTM's lexical handler.
0325: *
0326: * %REVIEW% Should this return null if constrution already done/begun?
0327: *
0328: * @return null if this model doesn't respond to lexical SAX events,
0329: * "this" if the DTM object has a built-in SAX ContentHandler,
0330: * the IncrementalSAXSource if we're bound to one and should receive
0331: * the SAX stream via it for incremental build purposes...
0332: */
0333: public LexicalHandler getLexicalHandler() {
0334:
0335: if (m_incrSAXSource instanceof IncrementalSAXSource_Filter)
0336: return (LexicalHandler) m_incrSAXSource;
0337: else
0338: return this ;
0339: }
0340:
0341: /**
0342: * Return this DTM's EntityResolver.
0343: *
0344: * @return null if this model doesn't respond to SAX entity ref events.
0345: */
0346: public org.xml.sax.EntityResolver getEntityResolver() {
0347:
0348: return null;
0349: }
0350:
0351: /**
0352: * Return this DTM's DTDHandler.
0353: *
0354: * @return null if this model doesn't respond to SAX dtd events.
0355: */
0356: public org.xml.sax.DTDHandler getDTDHandler() {
0357:
0358: return null;
0359: }
0360:
0361: /**
0362: * Return this DTM's ErrorHandler.
0363: *
0364: * @return null if this model doesn't respond to SAX error events.
0365: */
0366: public org.xml.sax.ErrorHandler getErrorHandler() {
0367:
0368: return null;
0369: }
0370:
0371: /**
0372: * Return this DTM's DeclHandler.
0373: *
0374: * @return null if this model doesn't respond to SAX Decl events.
0375: */
0376: public org.xml.sax.ext.DeclHandler getDeclHandler() {
0377:
0378: return null;
0379: }
0380:
0381: /** @return true iff we're building this model incrementally (eg
0382: * we're partnered with a IncrementalSAXSource) and thus require that the
0383: * transformation and the parse run simultaneously. Guidance to the
0384: * DTMManager.
0385: * */
0386: public boolean needsTwoThreads() {
0387: return null != m_incrSAXSource;
0388: }
0389:
0390: //================================================================
0391: // ========= SAX2 ContentHandler methods =========
0392: // Accept SAX events, use them to build/extend the DTM tree.
0393: // Replaces the deprecated DocumentHandler interface.
0394:
0395: public void characters(char[] ch, int start, int length)
0396: throws org.xml.sax.SAXException {
0397: // Actually creating the text node is handled by
0398: // processAccumulatedText(); here we just accumulate the
0399: // characters into the buffer.
0400: m_char.append(ch, start, length);
0401: }
0402:
0403: // Flush string accumulation into a text node
0404: private void processAccumulatedText() {
0405: int len = m_char.length();
0406: if (len != m_char_current_start) {
0407: // The FastStringBuffer has been previously agreed upon
0408: appendTextChild(m_char_current_start, len
0409: - m_char_current_start);
0410: m_char_current_start = len;
0411: }
0412: }
0413:
0414: public void endDocument() throws org.xml.sax.SAXException {
0415: // May need to tell the low-level builder code to pop up a level.
0416: // There _should't_ be any significant pending text at this point.
0417: appendEndDocument();
0418: }
0419:
0420: public void endElement(java.lang.String namespaceURI,
0421: java.lang.String localName, java.lang.String qName)
0422: throws org.xml.sax.SAXException {
0423: processAccumulatedText();
0424: // No args but we do need to tell the low-level builder code to
0425: // pop up a level.
0426: appendEndElement();
0427: }
0428:
0429: public void endPrefixMapping(java.lang.String prefix)
0430: throws org.xml.sax.SAXException {
0431: // No-op
0432: }
0433:
0434: public void ignorableWhitespace(char[] ch, int start, int length)
0435: throws org.xml.sax.SAXException {
0436: // %TBD% I believe ignorable text isn't part of the DTM model...?
0437: }
0438:
0439: public void processingInstruction(java.lang.String target,
0440: java.lang.String data) throws org.xml.sax.SAXException {
0441: processAccumulatedText();
0442: // %TBD% Which pools do target and data go into?
0443: }
0444:
0445: public void setDocumentLocator(Locator locator) {
0446: // No-op for DTM
0447: }
0448:
0449: public void skippedEntity(java.lang.String name)
0450: throws org.xml.sax.SAXException {
0451: processAccumulatedText();
0452: //%TBD%
0453: }
0454:
0455: public void startDocument() throws org.xml.sax.SAXException {
0456: appendStartDocument();
0457: }
0458:
0459: public void startElement(java.lang.String namespaceURI,
0460: java.lang.String localName, java.lang.String qName,
0461: Attributes atts) throws org.xml.sax.SAXException {
0462: processAccumulatedText();
0463:
0464: // %TBD% Split prefix off qname
0465: String prefix = null;
0466: int colon = qName.indexOf(':');
0467: if (colon > 0)
0468: prefix = qName.substring(0, colon);
0469:
0470: // %TBD% Where do we pool expandedName, or is it just the union, or...
0471: /**/System.out.println("Prefix=" + prefix + " index="
0472: + m_prefixNames.stringToIndex(prefix));
0473: appendStartElement(m_nsNames.stringToIndex(namespaceURI),
0474: m_localNames.stringToIndex(localName), m_prefixNames
0475: .stringToIndex(prefix)); /////// %TBD%
0476:
0477: // %TBD% I'm assuming that DTM will require resequencing of
0478: // NS decls before other attrs, hence two passes are taken.
0479: // %TBD% Is there an easier way to test for NSDecl?
0480: int nAtts = (atts == null) ? 0 : atts.getLength();
0481: // %TBD% Countdown is more efficient if nobody cares about sequence.
0482: for (int i = nAtts - 1; i >= 0; --i) {
0483: qName = atts.getQName(i);
0484: if (qName.startsWith("xmlns:") || "xmlns".equals(qName)) {
0485: prefix = null;
0486: colon = qName.indexOf(':');
0487: if (colon > 0) {
0488: prefix = qName.substring(0, colon);
0489: } else {
0490: // %REVEIW% Null or ""?
0491: prefix = null; // Default prefix
0492: }
0493:
0494: appendNSDeclaration(
0495: m_prefixNames.stringToIndex(prefix), m_nsNames
0496: .stringToIndex(atts.getValue(i)), atts
0497: .getType(i).equalsIgnoreCase("ID"));
0498: }
0499: }
0500:
0501: for (int i = nAtts - 1; i >= 0; --i) {
0502: qName = atts.getQName(i);
0503: if (!(qName.startsWith("xmlns:") || "xmlns".equals(qName))) {
0504: // %TBD% I hate having to extract the prefix into a new
0505: // string when we may never use it. Consider pooling whole
0506: // qNames, which are already strings?
0507: prefix = null;
0508: colon = qName.indexOf(':');
0509: if (colon > 0) {
0510: prefix = qName.substring(0, colon);
0511: localName = qName.substring(colon + 1);
0512: } else {
0513: prefix = ""; // Default prefix
0514: localName = qName;
0515: }
0516:
0517: m_char.append(atts.getValue(i)); // Single-string value
0518: int contentEnd = m_char.length();
0519:
0520: if (!("xmlns".equals(prefix) || "xmlns".equals(qName)))
0521: appendAttribute(m_nsNames.stringToIndex(atts
0522: .getURI(i)), m_localNames
0523: .stringToIndex(localName), m_prefixNames
0524: .stringToIndex(prefix), atts.getType(i)
0525: .equalsIgnoreCase("ID"),
0526: m_char_current_start, contentEnd
0527: - m_char_current_start);
0528: m_char_current_start = contentEnd;
0529: }
0530: }
0531: }
0532:
0533: public void startPrefixMapping(java.lang.String prefix,
0534: java.lang.String uri) throws org.xml.sax.SAXException {
0535: // No-op in DTM, handled during element/attr processing?
0536: }
0537:
0538: //
0539: // LexicalHandler support. Not all SAX2 parsers support these events
0540: // but we may want to pass them through when they exist...
0541: //
0542: public void comment(char[] ch, int start, int length)
0543: throws org.xml.sax.SAXException {
0544: processAccumulatedText();
0545:
0546: m_char.append(ch, start, length); // Single-string value
0547: appendComment(m_char_current_start, length);
0548: m_char_current_start += length;
0549: }
0550:
0551: public void endCDATA() throws org.xml.sax.SAXException {
0552: // No-op in DTM
0553: }
0554:
0555: public void endDTD() throws org.xml.sax.SAXException {
0556: // No-op in DTM
0557: }
0558:
0559: public void endEntity(java.lang.String name)
0560: throws org.xml.sax.SAXException {
0561: // No-op in DTM
0562: }
0563:
0564: public void startCDATA() throws org.xml.sax.SAXException {
0565: // No-op in DTM
0566: }
0567:
0568: public void startDTD(java.lang.String name,
0569: java.lang.String publicId, java.lang.String systemId)
0570: throws org.xml.sax.SAXException {
0571: // No-op in DTM
0572: }
0573:
0574: public void startEntity(java.lang.String name)
0575: throws org.xml.sax.SAXException {
0576: // No-op in DTM
0577: }
0578:
0579: //================================================================
0580: // ========= Document Handler Functions =========
0581: // %REVIEW% jjk -- DocumentHandler is SAX Level 1, and deprecated....
0582: // and this wasn't a fully compliant or declared implementation of that API
0583: // in any case. Phase out in favor of SAX2 ContentHandler/LexicalHandler
0584:
0585: /**
0586: * Reset a dtm document to its initial (empty) state.
0587: *
0588: * The DTMManager will invoke this method when the dtm is created.
0589: *
0590: * @param documentNumber the handle for the DTM document.
0591: */
0592: final void initDocument(int documentNumber) {
0593: // save masked DTM document handle
0594: m_docHandle = documentNumber << DOCHANDLE_SHIFT;
0595:
0596: // Initialize the doc -- no parent, no next-sib
0597: nodes.writeSlot(0, DOCUMENT_NODE, -1, -1, 0);
0598: // wait for the first startElement to create the doc root node
0599: done = false;
0600: }
0601:
0602: // /**
0603: // * Receive hint of the end of a document.
0604: // *
0605: // * <p>The content handler will invoke this method only once, and it will
0606: // * be the last method invoked during the parse. The handler shall not
0607: // * not invoke this method until it has either abandoned parsing
0608: // * (because of an unrecoverable error) or reached the end of
0609: // * input.</p>
0610: // */
0611: // public void documentEnd()
0612: // {
0613: // done = true;
0614: // // %TBD% may need to notice the last slot number and slot count to avoid
0615: // // residual data from provious use of this DTM
0616: // }
0617:
0618: // /**
0619: // * Receive notification of the beginning of a document.
0620: // *
0621: // * <p>The SAX parser will invoke this method only once, before any
0622: // * other methods in this interface.</p>
0623: // */
0624: // public void reset()
0625: // {
0626:
0627: // // %TBD% reset slot 0 to indicate ChunkedIntArray reuse or wait for
0628: // // the next initDocument().
0629: // m_docElement = NULL; // reset nodeHandle to the root of the actual dtm doc content
0630: // initDocument(0);
0631: // }
0632:
0633: // /**
0634: // * Factory method; creates an Element node in this document.
0635: // *
0636: // * The node created will be chained according to its natural order of request
0637: // * received. %TBD% It can be rechained later via the optional DTM writable interface.
0638: // *
0639: // * <p>The XML content handler will invoke endElement() method after all
0640: // * of the element's content are processed in order to give DTM the indication
0641: // * to prepare and patch up parent and sibling node pointers.</p>
0642: // *
0643: // * <p>The following interface for createElement will use an index value corresponds
0644: // * to the symbol entry in the DTMDStringPool based symbol tables.</p>
0645: // *
0646: // * @param nsIndex The namespace of the node
0647: // * @param nameIndex The element name.
0648: // * @see #endElement
0649: // * @see org.xml.sax.Attributes
0650: // * @return nodeHandle int of the element created
0651: // */
0652: // public int createElement(int nsIndex, int nameIndex, Attributes atts)
0653: // {
0654: // // do document root node creation here on the first element, create nodes for
0655: // // this element and its attributes, store the element, namespace, and attritute
0656: // // name indexes to the nodes array, keep track of the current node and parent
0657: // // element used
0658:
0659: // // W0 High: Namespace Low: Node Type
0660: // int w0 = (nsIndex << 16) | ELEMENT_NODE;
0661: // // W1: Parent
0662: // int w1 = currentParent;
0663: // // W2: Next (initialized as 0)
0664: // int w2 = 0;
0665: // // W3: Tagname
0666: // int w3 = nameIndex;
0667: // //int ourslot = nodes.appendSlot(w0, w1, w2, w3);
0668: // int ourslot = appendNode(w0, w1, w2, w3);
0669: // currentParent = ourslot;
0670: // previousSibling = 0;
0671: // setAttributes(atts);
0672:
0673: // // set the root element pointer when creating the first element node
0674: // if (m_docElement == NULL)
0675: // m_docElement = ourslot;
0676: // return (m_docHandle | ourslot);
0677: // }
0678:
0679: // // Factory method to create an Element node not associated with a given name space
0680: // // using String value parameters passed in from a content handler or application
0681: // /**
0682: // * Factory method; creates an Element node not associated with a given name space in this document.
0683: // *
0684: // * The node created will be chained according to its natural order of request
0685: // * received. %TBD% It can be rechained later via the optional DTM writable interface.
0686: // *
0687: // * <p>The XML content handler or application will invoke endElement() method after all
0688: // * of the element's content are processed in order to give DTM the indication
0689: // * to prepare and patch up parent and sibling node pointers.</p>
0690: // *
0691: // * <p>The following parameters for createElement contains raw string values for name
0692: // * symbols used in an Element node.</p>
0693: // *
0694: // * @param name String the element name, including the prefix if any.
0695: // * @param atts The attributes attached to the element, if any.
0696: // * @see #endElement
0697: // * @see org.xml.sax.Attributes
0698: // */
0699: // public int createElement(String name, Attributes atts)
0700: // {
0701: // // This method wraps around the index valued interface of the createElement interface.
0702: // // The raw string values are stored into the current DTM name symbol tables. The method
0703: // // method will then use the index values returned to invoke the other createElement()
0704: // // onverted to index values modified to match a
0705: // // method.
0706: // int nsIndex = NULL;
0707: // int nameIndex = m_localNames.stringToIndex(name);
0708: // // note - there should be no prefix separator in the name because it is not associated
0709: // // with a name space
0710:
0711: // return createElement(nsIndex, nameIndex, atts);
0712: // }
0713:
0714: // // Factory method to create an Element node associated with a given name space
0715: // // using String value parameters passed in from a content handler or application
0716: // /**
0717: // * Factory method; creates an Element node associated with a given name space in this document.
0718: // *
0719: // * The node created will be chained according to its natural order of request
0720: // * received. %TBD% It can be rechained later via the optional DTM writable interface.
0721: // *
0722: // * <p>The XML content handler or application will invoke endElement() method after all
0723: // * of the element's content are processed in order to give DTM the indication
0724: // * to prepare and patch up parent and sibling node pointers.</p>
0725: // *
0726: // * <p>The following parameters for createElementNS contains raw string values for name
0727: // * symbols used in an Element node.</p>
0728: // *
0729: // * @param ns String the namespace of the node
0730: // * @param name String the element name, including the prefix if any.
0731: // * @param atts The attributes attached to the element, if any.
0732: // * @see #endElement
0733: // * @see org.xml.sax.Attributes
0734: // */
0735: // public int createElementNS(String ns, String name, Attributes atts)
0736: // {
0737: // // This method wraps around the index valued interface of the createElement interface.
0738: // // The raw string values are stored into the current DTM name symbol tables. The method
0739: // // method will then use the index values returned to invoke the other createElement()
0740: // // onverted to index values modified to match a
0741: // // method.
0742: // int nsIndex = m_nsNames.stringToIndex(ns);
0743: // int nameIndex = m_localNames.stringToIndex(name);
0744: // // The prefixIndex is not needed by the indexed interface of the createElement method
0745: // int prefixSep = name.indexOf(":");
0746: // int prefixIndex = m_prefixNames.stringToIndex(name.substring(0, prefixSep));
0747: // return createElement(nsIndex, nameIndex, atts);
0748: // }
0749:
0750: // /**
0751: // * Receive an indication for the end of an element.
0752: // *
0753: // * <p>The XML content handler will invoke this method at the end of every
0754: // * element in the XML document to give hint its time to pop up the current
0755: // * element and parent and patch up parent and sibling pointers if necessary
0756: // *
0757: // * <p>%tbd% The following interface may need to be modified to match a
0758: // * coordinated access to the DTMDStringPool based symbol tables.</p>
0759: // *
0760: // * @param ns the namespace of the element
0761: // * @param name The element name
0762: // */
0763: // public void endElement(String ns, String name)
0764: // {
0765: // // pop up the stacks
0766:
0767: // //
0768: // if (previousSiblingWasParent)
0769: // nodes.writeEntry(previousSibling, 2, NULL);
0770:
0771: // // Pop parentage
0772: // previousSibling = currentParent;
0773: // nodes.readSlot(currentParent, gotslot);
0774: // currentParent = gotslot[1] & 0xFFFF;
0775:
0776: // // The element just being finished will be
0777: // // the previous sibling for the next operation
0778: // previousSiblingWasParent = true;
0779:
0780: // // Pop a level of namespace table
0781: // // namespaceTable.removeLastElem();
0782: // }
0783:
0784: // /**
0785: // * Creates attributes for the current node.
0786: // *
0787: // * @param atts Attributes to be created.
0788: // */
0789: // void setAttributes(Attributes atts) {
0790: // int atLength = (null == atts) ? 0 : atts.getLength();
0791: // for (int i=0; i < atLength; i++) {
0792: // String qname = atts.getQName(i);
0793: // createAttribute(atts.getQName(i), atts.getValue(i));
0794: // }
0795: // }
0796:
0797: // /**
0798: // * Appends an attribute to the document.
0799: // * @param qname Qualified Name of the attribute
0800: // * @param value Value of the attribute
0801: // * @return Handle of node
0802: // */
0803: // public int createAttribute(String qname, String value) {
0804: // int colonpos = qname.indexOf(":");
0805: // String attName = qname.substring(colonpos+1);
0806: // int w0 = 0;
0807: // if (colonpos > 0) {
0808: // String prefix = qname.substring(0, colonpos);
0809: // if (prefix.equals("xml")) {
0810: // //w0 = ATTRIBUTE_NODE |
0811: // // (org.apache.xalan.templates.Constants.S_XMLNAMESPACEURI << 16);
0812: // } else {
0813: // //w0 = ATTRIBUTE_NODE |
0814: // }
0815: // } else {
0816: // w0 = ATTRIBUTE_NODE;
0817: // }
0818: // // W1: Parent
0819: // int w1 = currentParent;
0820: // // W2: Next (not yet resolved)
0821: // int w2 = 0;
0822: // // W3: Tag name
0823: // int w3 = m_localNames.stringToIndex(attName);
0824: // // Add node
0825: // int ourslot = appendNode(w0, w1, w2, w3);
0826: // previousSibling = ourslot; // Should attributes be previous siblings
0827:
0828: // // W0: Node Type
0829: // w0 = TEXT_NODE;
0830: // // W1: Parent
0831: // w1 = ourslot;
0832: // // W2: Start Position within buffer
0833: // w2 = m_char.length();
0834: // m_char.append(value);
0835: // // W3: Length
0836: // w3 = m_char.length() - w2;
0837: // appendNode(w0, w1, w2, w3);
0838: // charStringStart=m_char.length();
0839: // charStringLength = 0;
0840: // //previousSibling = ourslot;
0841: // // Attrs are Parents
0842: // previousSiblingWasParent = true;
0843: // return (m_docHandle | ourslot);
0844: // }
0845:
0846: // /**
0847: // * Factory method; creates a Text node in this document.
0848: // *
0849: // * The node created will be chained according to its natural order of request
0850: // * received. %TBD% It can be rechained later via the optional DTM writable interface.
0851: // *
0852: // * @param text String The characters text string from the XML document.
0853: // * @return int DTM node-number of the text node created
0854: // */
0855: // public int createTextNode(String text)
0856: // throws DTMException
0857: // {
0858: // // wraps around the index value based createTextNode method
0859: // return createTextNode(text.toCharArray(), 0, text.length());
0860: // }
0861:
0862: // /**
0863: // * Factory method; creates a Text node in this document.
0864: // *
0865: // * The node created will be chained according to its natural order of request
0866: // * received. %TBD% It can be rechained later via the optional DTM writable interface.
0867: // *
0868: // * %REVIEW% for text normalization issues, unless we are willing to
0869: // * insist that all adjacent text must be merged before this method
0870: // * is called.
0871: // *
0872: // * @param ch The characters from the XML document.
0873: // * @param start The start position in the array.
0874: // * @param length The number of characters to read from the array.
0875: // */
0876: // public int createTextNode(char ch[], int start, int length)
0877: // throws DTMException
0878: // {
0879: // m_char.append(ch, start, length); // store the chunk to the text/comment string table
0880:
0881: // // create a Text Node
0882: // // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
0883: // int w0 = TEXT_NODE;
0884: // // W1: Parent
0885: // int w1 = currentParent;
0886: // // W2: Start position within m_char
0887: // int w2 = charStringStart;
0888: // // W3: Length of the full string
0889: // int w3 = length;
0890: // int ourslot = appendNode(w0, w1, w2, w3);
0891: // previousSibling = ourslot;
0892:
0893: // charStringStart=m_char.length();
0894: // charStringLength = 0;
0895: // return (m_docHandle | ourslot);
0896: // }
0897:
0898: // /**
0899: // * Factory method; creates a Comment node in this document.
0900: // *
0901: // * The node created will be chained according to its natural order of request
0902: // * received. %TBD% It can be rechained later via the optional DTM writable interface.
0903: // *
0904: // * @param text String The characters text string from the XML document.
0905: // * @return int DTM node-number of the text node created
0906: // */
0907: // public int createComment(String text)
0908: // throws DTMException
0909: // {
0910: // // wraps around the index value based createTextNode method
0911: // return createComment(text.toCharArray(), 0, text.length());
0912: // }
0913:
0914: // /**
0915: // * Factory method; creates a Comment node in this document.
0916: // *
0917: // * The node created will be chained according to its natural order of request
0918: // * received. %TBD% It can be rechained later via the optional DTM writable interface.
0919: // *
0920: // * @param ch An array holding the characters in the comment.
0921: // * @param start The starting position in the array.
0922: // * @param length The number of characters to use from the array.
0923: // * @see DTMException
0924: // */
0925: // public int createComment(char ch[], int start, int length)
0926: // throws DTMException
0927: // {
0928: // m_char.append(ch, start, length); // store the comment string to the text/comment string table
0929:
0930: // // create a Comment Node
0931: // // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
0932: // int w0 = COMMENT_NODE;
0933: // // W1: Parent
0934: // int w1 = currentParent;
0935: // // W2: Start position within m_char
0936: // int w2 = charStringStart;
0937: // // W3: Length of the full string
0938: // int w3 = length;
0939: // int ourslot = appendNode(w0, w1, w2, w3);
0940: // previousSibling = ourslot;
0941:
0942: // charStringStart=m_char.length();
0943: // charStringLength = 0;
0944: // return (m_docHandle | ourslot);
0945: // }
0946:
0947: // // Counters to keep track of the current text string being accumulated with respect
0948: // // to the text/comment string table: charStringStart should point to the starting
0949: // // offset of the string in the table and charStringLength the acccumulated length when
0950: // // appendAccumulatedText starts, and reset to the end of the table and 0 at the end
0951: // // of appendAccumulatedText for the next set of characters receives
0952: // int charStringStart=0,charStringLength=0;
0953:
0954: // ========= Document Navigation Functions =========
0955:
0956: /** Given a node handle, test if it has child nodes.
0957: * <p> %REVIEW% This is obviously useful at the DOM layer, where it
0958: * would permit testing this without having to create a proxy
0959: * node. It's less useful in the DTM API, where
0960: * (dtm.getFirstChild(nodeHandle)!=DTM.NULL) is just as fast and
0961: * almost as self-evident. But it's a convenience, and eases porting
0962: * of DOM code to DTM. </p>
0963: *
0964: * @param nodeHandle int Handle of the node.
0965: * @return int true if the given node has child nodes.
0966: */
0967: public boolean hasChildNodes(int nodeHandle) {
0968: return (getFirstChild(nodeHandle) != NULL);
0969: }
0970:
0971: /**
0972: * Given a node handle, get the handle of the node's first child.
0973: * If not yet resolved, waits for more nodes to be added to the document and
0974: * tries again.
0975: *
0976: * @param nodeHandle int Handle of the node.
0977: * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
0978: */
0979: public int getFirstChild(int nodeHandle) {
0980:
0981: // ###shs worry about tracing/debug later
0982: nodeHandle &= NODEHANDLE_MASK;
0983: // Read node into variable
0984: nodes.readSlot(nodeHandle, gotslot);
0985:
0986: // type is the last half of first slot
0987: short type = (short) (gotslot[0] & 0xFFFF);
0988:
0989: // Check to see if Element or Document node
0990: if ((type == ELEMENT_NODE) || (type == DOCUMENT_NODE)
0991: || (type == ENTITY_REFERENCE_NODE)) {
0992:
0993: // In case when Document root is given
0994: // if (nodeHandle == 0) nodeHandle = 1;
0995: // %TBD% Probably was a mistake.
0996: // If someone explicitly asks for first child
0997: // of Document, I would expect them to want
0998: // that and only that.
0999:
1000: int kid = nodeHandle + 1;
1001: nodes.readSlot(kid, gotslot);
1002: while (ATTRIBUTE_NODE == (gotslot[0] & 0xFFFF)) {
1003: // points to next sibling
1004: kid = gotslot[2];
1005: // Return NULL if node has only attributes
1006: if (kid == NULL)
1007: return NULL;
1008: nodes.readSlot(kid, gotslot);
1009: }
1010: // If parent slot matches given parent, return kid
1011: if (gotslot[1] == nodeHandle) {
1012: int firstChild = kid | m_docHandle;
1013:
1014: return firstChild;
1015: }
1016: }
1017: // No child found
1018:
1019: return NULL;
1020: }
1021:
1022: /**
1023: * Given a node handle, advance to its last child.
1024: * If not yet resolved, waits for more nodes to be added to the document and
1025: * tries again.
1026: *
1027: * @param nodeHandle int Handle of the node.
1028: * @return int Node-number of last child,
1029: * or DTM.NULL to indicate none exists.
1030: */
1031: public int getLastChild(int nodeHandle) {
1032: // ###shs put trace/debug later
1033: nodeHandle &= NODEHANDLE_MASK;
1034: // do not need to test node type since getFirstChild does that
1035: int lastChild = NULL;
1036: for (int nextkid = getFirstChild(nodeHandle); nextkid != NULL; nextkid = getNextSibling(nextkid)) {
1037: lastChild = nextkid;
1038: }
1039: return lastChild | m_docHandle;
1040: }
1041:
1042: /**
1043: * Retrieves an attribute node by by qualified name and namespace URI.
1044: *
1045: * @param nodeHandle int Handle of the node upon which to look up this attribute.
1046: * @param namespaceURI The namespace URI of the attribute to
1047: * retrieve, or null.
1048: * @param name The local name of the attribute to
1049: * retrieve.
1050: * @return The attribute node handle with the specified name (
1051: * <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
1052: * attribute.
1053: */
1054: public int getAttributeNode(int nodeHandle, String namespaceURI,
1055: String name) {
1056: int nsIndex = m_nsNames.stringToIndex(namespaceURI), nameIndex = m_localNames
1057: .stringToIndex(name);
1058: nodeHandle &= NODEHANDLE_MASK;
1059: nodes.readSlot(nodeHandle, gotslot);
1060: short type = (short) (gotslot[0] & 0xFFFF);
1061: // If nodeHandle points to element next slot would be first attribute
1062: if (type == ELEMENT_NODE)
1063: nodeHandle++;
1064: // Iterate through Attribute Nodes
1065: while (type == ATTRIBUTE_NODE) {
1066: if ((nsIndex == (gotslot[0] << 16))
1067: && (gotslot[3] == nameIndex))
1068: return nodeHandle | m_docHandle;
1069: // Goto next sibling
1070: nodeHandle = gotslot[2];
1071: nodes.readSlot(nodeHandle, gotslot);
1072: }
1073: return NULL;
1074: }
1075:
1076: /**
1077: * Given a node handle, get the index of the node's first attribute.
1078: *
1079: * @param nodeHandle int Handle of the Element node.
1080: * @return Handle of first attribute, or DTM.NULL to indicate none exists.
1081: */
1082: public int getFirstAttribute(int nodeHandle) {
1083: nodeHandle &= NODEHANDLE_MASK;
1084:
1085: // %REVIEW% jjk: Just a quick observation: If you're going to
1086: // call readEntry repeatedly on the same node, it may be
1087: // more efficiently to do a readSlot to get the data locally,
1088: // reducing the addressing and call-and-return overhead.
1089:
1090: // Should we check if handle is element (do we want sanity checks?)
1091: if (ELEMENT_NODE != (nodes.readEntry(nodeHandle, 0) & 0xFFFF))
1092: return NULL;
1093: // First Attribute (if any) should be at next position in table
1094: nodeHandle++;
1095: return (ATTRIBUTE_NODE == (nodes.readEntry(nodeHandle, 0) & 0xFFFF)) ? nodeHandle
1096: | m_docHandle
1097: : NULL;
1098: }
1099:
1100: /**
1101: * Given a node handle, get the index of the node's first child.
1102: * If not yet resolved, waits for more nodes to be added to the document and
1103: * tries again
1104: *
1105: * @param nodeHandle handle to node, which should probably be an element
1106: * node, but need not be.
1107: *
1108: * @param inScope true if all namespaces in scope should be returned,
1109: * false if only the namespace declarations should be
1110: * returned.
1111: * @return handle of first namespace, or DTM.NULL to indicate none exists.
1112: */
1113: public int getFirstNamespaceNode(int nodeHandle, boolean inScope) {
1114:
1115: return NULL;
1116: }
1117:
1118: /**
1119: * Given a node handle, advance to its next sibling.
1120: *
1121: * %TBD% This currently uses the DTM-internal definition of
1122: * sibling; eg, the last attr's next sib is the first
1123: * child. In the old DTM, the DOM proxy layer provided the
1124: * additional logic for the public view. If we're rewriting
1125: * for XPath emulation, that test must be done here.
1126: *
1127: * %TBD% CODE INTERACTION WITH INCREMENTAL PARSE - If not yet
1128: * resolved, should wait for more nodes to be added to the document
1129: * and tries again.
1130: *
1131: * @param nodeHandle int Handle of the node.
1132: * @return int Node-number of next sibling,
1133: * or DTM.NULL to indicate none exists.
1134: * */
1135: public int getNextSibling(int nodeHandle) {
1136: nodeHandle &= NODEHANDLE_MASK;
1137: // Document root has no next sibling
1138: if (nodeHandle == 0)
1139: return NULL;
1140:
1141: short type = (short) (nodes.readEntry(nodeHandle, 0) & 0xFFFF);
1142: if ((type == ELEMENT_NODE) || (type == ATTRIBUTE_NODE)
1143: || (type == ENTITY_REFERENCE_NODE)) {
1144: int nextSib = nodes.readEntry(nodeHandle, 2);
1145: if (nextSib == NULL)
1146: return NULL;
1147: if (nextSib != 0)
1148: return (m_docHandle | nextSib);
1149: // ###shs should cycle/wait if nextSib is 0? Working on threading next
1150: }
1151: // Next Sibling is in the next position if it shares the same parent
1152: int this Parent = nodes.readEntry(nodeHandle, 1);
1153:
1154: if (nodes.readEntry(++nodeHandle, 1) == this Parent)
1155: return (m_docHandle | nodeHandle);
1156:
1157: return NULL;
1158: }
1159:
1160: /**
1161: * Given a node handle, find its preceeding sibling.
1162: * WARNING: DTM is asymmetric; this operation is resolved by search, and is
1163: * relatively expensive.
1164: *
1165: * @param nodeHandle the id of the node.
1166: * @return int Node-number of the previous sib,
1167: * or DTM.NULL to indicate none exists.
1168: */
1169: public int getPreviousSibling(int nodeHandle) {
1170: nodeHandle &= NODEHANDLE_MASK;
1171: // Document root has no previous sibling
1172: if (nodeHandle == 0)
1173: return NULL;
1174:
1175: int parent = nodes.readEntry(nodeHandle, 1);
1176: int kid = NULL;
1177: for (int nextkid = getFirstChild(parent); nextkid != nodeHandle; nextkid = getNextSibling(nextkid)) {
1178: kid = nextkid;
1179: }
1180: return kid | m_docHandle;
1181: }
1182:
1183: /**
1184: * Given a node handle, advance to the next attribute. If an
1185: * element, we advance to its first attribute; if an attr, we advance to
1186: * the next attr on the same node.
1187: *
1188: * @param nodeHandle int Handle of the node.
1189: * @return int DTM node-number of the resolved attr,
1190: * or DTM.NULL to indicate none exists.
1191: */
1192: public int getNextAttribute(int nodeHandle) {
1193: nodeHandle &= NODEHANDLE_MASK;
1194: nodes.readSlot(nodeHandle, gotslot);
1195:
1196: //%REVIEW% Why are we using short here? There's no storage
1197: //reduction for an automatic variable, especially one used
1198: //so briefly, and it typically costs more cycles to process
1199: //than an int would.
1200: short type = (short) (gotslot[0] & 0xFFFF);
1201:
1202: if (type == ELEMENT_NODE) {
1203: return getFirstAttribute(nodeHandle);
1204: } else if (type == ATTRIBUTE_NODE) {
1205: if (gotslot[2] != NULL)
1206: return (m_docHandle | gotslot[2]);
1207: }
1208: return NULL;
1209: }
1210:
1211: /**
1212: * Given a namespace handle, advance to the next namespace.
1213: *
1214: * %TBD% THIS METHOD DOES NOT MATCH THE CURRENT SIGNATURE IN
1215: * THE DTM INTERFACE. FIX IT, OR JUSTIFY CHANGING THE DTM
1216: * API.
1217: *
1218: * @param namespaceHandle handle to node which must be of type NAMESPACE_NODE.
1219: * @return handle of next namespace, or DTM.NULL to indicate none exists.
1220: */
1221: public int getNextNamespaceNode(int baseHandle,
1222: int namespaceHandle, boolean inScope) {
1223: // ###shs need to work on namespace
1224: return NULL;
1225: }
1226:
1227: /**
1228: * Given a node handle, advance to its next descendant.
1229: * If not yet resolved, waits for more nodes to be added to the document and
1230: * tries again.
1231: *
1232: * @param subtreeRootHandle
1233: * @param nodeHandle int Handle of the node.
1234: * @return handle of next descendant,
1235: * or DTM.NULL to indicate none exists.
1236: */
1237: public int getNextDescendant(int subtreeRootHandle, int nodeHandle) {
1238: subtreeRootHandle &= NODEHANDLE_MASK;
1239: nodeHandle &= NODEHANDLE_MASK;
1240: // Document root [Document Node? -- jjk] - no next-sib
1241: if (nodeHandle == 0)
1242: return NULL;
1243: while (!m_isError) {
1244: // Document done and node out of bounds
1245: if (done && (nodeHandle > nodes.slotsUsed()))
1246: break;
1247: if (nodeHandle > subtreeRootHandle) {
1248: nodes.readSlot(nodeHandle + 1, gotslot);
1249: if (gotslot[2] != 0) {
1250: short type = (short) (gotslot[0] & 0xFFFF);
1251: if (type == ATTRIBUTE_NODE) {
1252: nodeHandle += 2;
1253: } else {
1254: int nextParentPos = gotslot[1];
1255: if (nextParentPos >= subtreeRootHandle)
1256: return (m_docHandle | (nodeHandle + 1));
1257: else
1258: break;
1259: }
1260: } else if (!done) {
1261: // Add wait logic here
1262: } else
1263: break;
1264: } else {
1265: nodeHandle++;
1266: }
1267: }
1268: // Probably should throw error here like original instead of returning
1269: return NULL;
1270: }
1271:
1272: /**
1273: * Given a node handle, advance to the next node on the following axis.
1274: *
1275: * @param axisContextHandle the start of the axis that is being traversed.
1276: * @param nodeHandle
1277: * @return handle of next sibling,
1278: * or DTM.NULL to indicate none exists.
1279: */
1280: public int getNextFollowing(int axisContextHandle, int nodeHandle) {
1281: //###shs still working on
1282: return NULL;
1283: }
1284:
1285: /**
1286: * Given a node handle, advance to the next node on the preceding axis.
1287: *
1288: * @param axisContextHandle the start of the axis that is being traversed.
1289: * @param nodeHandle the id of the node.
1290: * @return int Node-number of preceding sibling,
1291: * or DTM.NULL to indicate none exists.
1292: */
1293: public int getNextPreceding(int axisContextHandle, int nodeHandle) {
1294: // ###shs copied from Xalan 1, what is this suppose to do?
1295: nodeHandle &= NODEHANDLE_MASK;
1296: while (nodeHandle > 1) {
1297: nodeHandle--;
1298: if (ATTRIBUTE_NODE == (nodes.readEntry(nodeHandle, 0) & 0xFFFF))
1299: continue;
1300:
1301: // if nodeHandle is _not_ an ancestor of
1302: // axisContextHandle, specialFind will return it.
1303: // If it _is_ an ancestor, specialFind will return -1
1304:
1305: // %REVIEW% unconditional return defeats the
1306: // purpose of the while loop -- does this
1307: // logic make any sense?
1308:
1309: return (m_docHandle | nodes.specialFind(axisContextHandle,
1310: nodeHandle));
1311: }
1312: return NULL;
1313: }
1314:
1315: /**
1316: * Given a node handle, find its parent node.
1317: *
1318: * @param nodeHandle the id of the node.
1319: * @return int Node-number of parent,
1320: * or DTM.NULL to indicate none exists.
1321: */
1322: public int getParent(int nodeHandle) {
1323: // Should check to see within range?
1324:
1325: // Document Root should not have to be handled differently
1326: return (m_docHandle | nodes.readEntry(nodeHandle, 1));
1327: }
1328:
1329: /**
1330: * Returns the root element of the document.
1331: * @return nodeHandle to the Document Root.
1332: */
1333: public int getDocumentRoot() {
1334: return (m_docHandle | m_docElement);
1335: }
1336:
1337: /**
1338: * Given a node handle, find the owning document node.
1339: *
1340: * @return int Node handle of document, which should always be valid.
1341: */
1342: public int getDocument() {
1343: return m_docHandle;
1344: }
1345:
1346: /**
1347: * Given a node handle, find the owning document node. This has the exact
1348: * same semantics as the DOM Document method of the same name, in that if
1349: * the nodeHandle is a document node, it will return NULL.
1350: *
1351: * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
1352: * binding layer. Included here as a convenience function and to
1353: * aid porting of DOM code to DTM.</p>
1354: *
1355: * @param nodeHandle the id of the node.
1356: * @return int Node handle of owning document, or NULL if the nodeHandle is
1357: * a document.
1358: */
1359: public int getOwnerDocument(int nodeHandle) {
1360: // Assumption that Document Node is always in 0 slot
1361: if ((nodeHandle & NODEHANDLE_MASK) == 0)
1362: return NULL;
1363: return (nodeHandle & DOCHANDLE_MASK);
1364: }
1365:
1366: /**
1367: * Given a node handle, find the owning document node. This has the DTM
1368: * semantics; a Document node is its own owner.
1369: *
1370: * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
1371: * binding layer. Included here as a convenience function and to
1372: * aid porting of DOM code to DTM.</p>
1373: *
1374: * @param nodeHandle the id of the node.
1375: * @return int Node handle of owning document, or NULL if the nodeHandle is
1376: * a document.
1377: */
1378: public int getDocumentRoot(int nodeHandle) {
1379: // Assumption that Document Node is always in 0 slot
1380: if ((nodeHandle & NODEHANDLE_MASK) == 0)
1381: return NULL;
1382: return (nodeHandle & DOCHANDLE_MASK);
1383: }
1384:
1385: /**
1386: * Get the string-value of a node as a String object
1387: * (see http://www.w3.org/TR/xpath#data-model
1388: * for the definition of a node's string-value).
1389: *
1390: * @param nodeHandle The node ID.
1391: *
1392: * @return A string object that represents the string-value of the given node.
1393: */
1394: public XMLString getStringValue(int nodeHandle) {
1395: // ###zaj - researching
1396: nodes.readSlot(nodeHandle, gotslot);
1397: int nodetype = gotslot[0] & 0xFF;
1398: String value = null;
1399:
1400: switch (nodetype) {
1401: case TEXT_NODE:
1402: case COMMENT_NODE:
1403: case CDATA_SECTION_NODE:
1404: value = m_char.getString(gotslot[2], gotslot[3]);
1405: break;
1406: case PROCESSING_INSTRUCTION_NODE:
1407: case ATTRIBUTE_NODE:
1408: case ELEMENT_NODE:
1409: case ENTITY_REFERENCE_NODE:
1410: default:
1411: break;
1412: }
1413: return m_xsf.newstr(value);
1414:
1415: }
1416:
1417: /**
1418: * Get number of character array chunks in
1419: * the string-value of a node.
1420: * (see http://www.w3.org/TR/xpath#data-model
1421: * for the definition of a node's string-value).
1422: * Note that a single text node may have multiple text chunks.
1423: *
1424: * EXPLANATION: This method is an artifact of the fact that the
1425: * underlying m_chars object may not store characters in a
1426: * single contiguous array -- for example,the current
1427: * FastStringBuffer may split a single node's text across
1428: * multiple allocation units. This call tells us how many
1429: * separate accesses will be required to retrieve the entire
1430: * content. PLEASE NOTE that this may not be the same as the
1431: * number of SAX characters() events that caused the text node
1432: * to be built in the first place, since m_chars buffering may
1433: * be on different boundaries than the parser's buffers.
1434: *
1435: * @param nodeHandle The node ID.
1436: *
1437: * @return number of character array chunks in
1438: * the string-value of a node.
1439: * */
1440: //###zaj - tbd
1441: public int getStringValueChunkCount(int nodeHandle) {
1442: //###zaj return value
1443: return 0;
1444: }
1445:
1446: /**
1447: * Get a character array chunk in the string-value of a node.
1448: * (see http://www.w3.org/TR/xpath#data-model
1449: * for the definition of a node's string-value).
1450: * Note that a single text node may have multiple text chunks.
1451: *
1452: * EXPLANATION: This method is an artifact of the fact that
1453: * the underlying m_chars object may not store characters in a
1454: * single contiguous array -- for example,the current
1455: * FastStringBuffer may split a single node's text across
1456: * multiple allocation units. This call retrieves a single
1457: * contiguous portion of the text -- as much as m-chars was
1458: * able to store in a single allocation unit. PLEASE NOTE
1459: * that this may not be the same granularityas the SAX
1460: * characters() events that caused the text node to be built
1461: * in the first place, since m_chars buffering may be on
1462: * different boundaries than the parser's buffers.
1463: *
1464: * @param nodeHandle The node ID.
1465: * @param chunkIndex Which chunk to get.
1466: * @param startAndLen An array of 2 where the start position and length of
1467: * the chunk will be returned.
1468: *
1469: * @return The character array reference where the chunk occurs. */
1470: //###zaj - tbd
1471: public char[] getStringValueChunk(int nodeHandle, int chunkIndex,
1472: int[] startAndLen) {
1473: return new char[0];
1474: }
1475:
1476: /**
1477: * Given a node handle, return an ID that represents the node's expanded name.
1478: *
1479: * @param nodeHandle The handle to the node in question.
1480: *
1481: * @return the expanded-name id of the node.
1482: */
1483: public int getExpandedTypeID(int nodeHandle) {
1484: nodes.readSlot(nodeHandle, gotslot);
1485: String qName = m_localNames.indexToString(gotslot[3]);
1486: // Remove prefix from qName
1487: // %TBD% jjk This is assuming the elementName is the qName.
1488: int colonpos = qName.indexOf(":");
1489: String localName = qName.substring(colonpos + 1);
1490: // Get NS
1491: String namespace = m_nsNames.indexToString(gotslot[0] << 16);
1492: // Create expanded name
1493: String expandedName = namespace + ":" + localName;
1494: int expandedNameID = m_nsNames.stringToIndex(expandedName);
1495:
1496: return expandedNameID;
1497: }
1498:
1499: /**
1500: * Given an expanded name, return an ID. If the expanded-name does not
1501: * exist in the internal tables, the entry will be created, and the ID will
1502: * be returned. Any additional nodes that are created that have this
1503: * expanded name will use this ID.
1504: *
1505: * @return the expanded-name id of the node.
1506: */
1507: public int getExpandedTypeID(String namespace, String localName,
1508: int type) {
1509: // Create expanded name
1510: // %TBD% jjk Expanded name is bitfield-encoded as
1511: // typeID[6]nsuriID[10]localID[16]. Switch to that form, and to
1512: // accessing the ns/local via their tables rather than confusing
1513: // nsnames and expandednames.
1514: String expandedName = namespace + ":" + localName;
1515: int expandedNameID = m_nsNames.stringToIndex(expandedName);
1516:
1517: return expandedNameID;
1518: }
1519:
1520: /**
1521: * Given an expanded-name ID, return the local name part.
1522: *
1523: * @param ExpandedNameID an ID that represents an expanded-name.
1524: * @return String Local name of this node.
1525: */
1526: public String getLocalNameFromExpandedNameID(int ExpandedNameID) {
1527:
1528: // Get expanded name
1529: String expandedName = m_localNames
1530: .indexToString(ExpandedNameID);
1531: // Remove prefix from expanded name
1532: int colonpos = expandedName.indexOf(":");
1533: String localName = expandedName.substring(colonpos + 1);
1534: return localName;
1535: }
1536:
1537: /**
1538: * Given an expanded-name ID, return the namespace URI part.
1539: *
1540: * @param ExpandedNameID an ID that represents an expanded-name.
1541: * @return String URI value of this node's namespace, or null if no
1542: * namespace was resolved.
1543: */
1544: public String getNamespaceFromExpandedNameID(int ExpandedNameID) {
1545:
1546: String expandedName = m_localNames
1547: .indexToString(ExpandedNameID);
1548: // Remove local name from expanded name
1549: int colonpos = expandedName.indexOf(":");
1550: String nsName = expandedName.substring(0, colonpos);
1551:
1552: return nsName;
1553: }
1554:
1555: /**
1556: * fixednames
1557: */
1558: private static final String[] fixednames = { null, null, // nothing, Element
1559: null, "#text", // Attr, Text
1560: "#cdata_section", null, // CDATA, EntityReference
1561: null, null, // Entity, PI
1562: "#comment", "#document", // Comment, Document
1563: null, "#document-fragment", // Doctype, DocumentFragment
1564: null }; // Notation
1565:
1566: /**
1567: * Given a node handle, return its DOM-style node name. This will
1568: * include names such as #text or #document.
1569: *
1570: * @param nodeHandle the id of the node.
1571: * @return String Name of this node, which may be an empty string.
1572: * %REVIEW% Document when empty string is possible...
1573: */
1574: public String getNodeName(int nodeHandle) {
1575: nodes.readSlot(nodeHandle, gotslot);
1576: short type = (short) (gotslot[0] & 0xFFFF);
1577: String name = fixednames[type];
1578: if (null == name) {
1579: int i = gotslot[3];
1580: /**/System.out.println("got i=" + i + " " + (i >> 16)
1581: + "/" + (i & 0xffff));
1582:
1583: name = m_localNames.indexToString(i & 0xFFFF);
1584: String prefix = m_prefixNames.indexToString(i >> 16);
1585: if (prefix != null && prefix.length() > 0)
1586: name = prefix + ":" + name;
1587: }
1588: return name;
1589: }
1590:
1591: /**
1592: * Given a node handle, return the XPath node name. This should be
1593: * the name as described by the XPath data model, NOT the DOM-style
1594: * name.
1595: *
1596: * @param nodeHandle the id of the node.
1597: * @return String Name of this node.
1598: */
1599: public String getNodeNameX(int nodeHandle) {
1600: return null;
1601: }
1602:
1603: /**
1604: * Given a node handle, return its DOM-style localname.
1605: * (As defined in Namespaces, this is the portion of the name after any
1606: * colon character)
1607: *
1608: * %REVIEW% What's the local name of something other than Element/Attr?
1609: * Should this be DOM-style (undefined unless namespaced), or other?
1610: *
1611: * @param nodeHandle the id of the node.
1612: * @return String Local name of this node.
1613: */
1614: public String getLocalName(int nodeHandle) {
1615: nodes.readSlot(nodeHandle, gotslot);
1616: short type = (short) (gotslot[0] & 0xFFFF);
1617: String name = "";
1618: if ((type == ELEMENT_NODE) || (type == ATTRIBUTE_NODE)) {
1619: int i = gotslot[3];
1620: name = m_localNames.indexToString(i & 0xFFFF);
1621: if (name == null)
1622: name = "";
1623: }
1624: return name;
1625: }
1626:
1627: /**
1628: * Given a namespace handle, return the prefix that the namespace decl is
1629: * mapping.
1630: * Given a node handle, return the prefix used to map to the namespace.
1631: *
1632: * <p> %REVIEW% Are you sure you want "" for no prefix? </p>
1633: *
1634: * %REVIEW% Should this be DOM-style (undefined unless namespaced),
1635: * or other?
1636: *
1637: * @param nodeHandle the id of the node.
1638: * @return String prefix of this node's name, or "" if no explicit
1639: * namespace prefix was given.
1640: */
1641: public String getPrefix(int nodeHandle) {
1642: nodes.readSlot(nodeHandle, gotslot);
1643: short type = (short) (gotslot[0] & 0xFFFF);
1644: String name = "";
1645: if ((type == ELEMENT_NODE) || (type == ATTRIBUTE_NODE)) {
1646: int i = gotslot[3];
1647: name = m_prefixNames.indexToString(i >> 16);
1648: if (name == null)
1649: name = "";
1650: }
1651: return name;
1652: }
1653:
1654: /**
1655: * Given a node handle, return its DOM-style namespace URI
1656: * (As defined in Namespaces, this is the declared URI which this node's
1657: * prefix -- or default in lieu thereof -- was mapped to.)
1658: *
1659: * @param nodeHandle the id of the node.
1660: * @return String URI value of this node's namespace, or null if no
1661: * namespace was resolved.
1662: */
1663: public String getNamespaceURI(int nodeHandle) {
1664: return null;
1665: }
1666:
1667: /**
1668: * Given a node handle, return its node value. This is mostly
1669: * as defined by the DOM, but may ignore some conveniences.
1670: * <p>
1671: *
1672: * @param nodeHandle The node id.
1673: * @return String Value of this node, or null if not
1674: * meaningful for this node type.
1675: */
1676: public String getNodeValue(int nodeHandle) {
1677: nodes.readSlot(nodeHandle, gotslot);
1678: int nodetype = gotslot[0] & 0xFF; // ###zaj use mask to get node type
1679: String value = null;
1680:
1681: switch (nodetype) { // ###zaj todo - document nodetypes
1682: case ATTRIBUTE_NODE:
1683: nodes.readSlot(nodeHandle + 1, gotslot);
1684: case TEXT_NODE:
1685: case COMMENT_NODE:
1686: case CDATA_SECTION_NODE:
1687: value = m_char.getString(gotslot[2], gotslot[3]); //###zaj
1688: break;
1689: case PROCESSING_INSTRUCTION_NODE:
1690: case ELEMENT_NODE:
1691: case ENTITY_REFERENCE_NODE:
1692: default:
1693: break;
1694: }
1695: return value;
1696: }
1697:
1698: /**
1699: * Given a node handle, return its DOM-style node type.
1700: * <p>
1701: * %REVIEW% Generally, returning short is false economy. Return int?
1702: *
1703: * @param nodeHandle The node id.
1704: * @return int Node type, as per the DOM's Node._NODE constants.
1705: */
1706: public short getNodeType(int nodeHandle) {
1707: return (short) (nodes.readEntry(nodeHandle, 0) & 0xFFFF);
1708: }
1709:
1710: /**
1711: * Get the depth level of this node in the tree (equals 1 for
1712: * a parentless node).
1713: *
1714: * @param nodeHandle The node id.
1715: * @return the number of ancestors, plus one
1716: * @xsl.usage internal
1717: */
1718: public short getLevel(int nodeHandle) {
1719: short count = 0;
1720: while (nodeHandle != 0) {
1721: count++;
1722: nodeHandle = nodes.readEntry(nodeHandle, 1);
1723: }
1724: return count;
1725: }
1726:
1727: // ============== Document query functions ==============
1728:
1729: /**
1730: * Tests whether DTM DOM implementation implements a specific feature and
1731: * that feature is supported by this node.
1732: *
1733: * @param feature The name of the feature to test.
1734: * @param version This is the version number of the feature to test.
1735: * If the version is not
1736: * specified, supporting any version of the feature will cause the
1737: * method to return <code>true</code>.
1738: * @return Returns <code>true</code> if the specified feature is
1739: * supported on this node, <code>false</code> otherwise.
1740: */
1741: public boolean isSupported(String feature, String version) {
1742: return false;
1743: }
1744:
1745: /**
1746: * Return the base URI of the document entity. If it is not known
1747: * (because the document was parsed from a socket connection or from
1748: * standard input, for example), the value of this property is unknown.
1749: *
1750: * @return the document base URI String object or null if unknown.
1751: */
1752: public String getDocumentBaseURI() {
1753:
1754: return m_documentBaseURI;
1755: }
1756:
1757: /**
1758: * Set the base URI of the document entity.
1759: *
1760: * @param baseURI the document base URI String object or null if unknown.
1761: */
1762: public void setDocumentBaseURI(String baseURI) {
1763:
1764: m_documentBaseURI = baseURI;
1765: }
1766:
1767: /**
1768: * Return the system identifier of the document entity. If
1769: * it is not known, the value of this property is unknown.
1770: *
1771: * @param nodeHandle The node id, which can be any valid node handle.
1772: * @return the system identifier String object or null if unknown.
1773: */
1774: public String getDocumentSystemIdentifier(int nodeHandle) {
1775: return null;
1776: }
1777:
1778: /**
1779: * Return the name of the character encoding scheme
1780: * in which the document entity is expressed.
1781: *
1782: * @param nodeHandle The node id, which can be any valid node handle.
1783: * @return the document encoding String object.
1784: */
1785: public String getDocumentEncoding(int nodeHandle) {
1786: return null;
1787: }
1788:
1789: /**
1790: * Return an indication of the standalone status of the document,
1791: * either "yes" or "no". This property is derived from the optional
1792: * standalone document declaration in the XML declaration at the
1793: * beginning of the document entity, and has no value if there is no
1794: * standalone document declaration.
1795: *
1796: * @param nodeHandle The node id, which can be any valid node handle.
1797: * @return the document standalone String object, either "yes", "no", or null.
1798: */
1799: public String getDocumentStandalone(int nodeHandle) {
1800: return null;
1801: }
1802:
1803: /**
1804: * Return a string representing the XML version of the document. This
1805: * property is derived from the XML declaration optionally present at the
1806: * beginning of the document entity, and has no value if there is no XML
1807: * declaration.
1808: *
1809: * @param documentHandle the document handle
1810: *
1811: * @return the document version String object
1812: */
1813: public String getDocumentVersion(int documentHandle) {
1814: return null;
1815: }
1816:
1817: /**
1818: * Return an indication of
1819: * whether the processor has read the complete DTD. Its value is a
1820: * boolean. If it is false, then certain properties (indicated in their
1821: * descriptions below) may be unknown. If it is true, those properties
1822: * are never unknown.
1823: *
1824: * @return <code>true</code> if all declarations were processed {};
1825: * <code>false</code> otherwise.
1826: */
1827: public boolean getDocumentAllDeclarationsProcessed() {
1828: return false;
1829: }
1830:
1831: /**
1832: * A document type declaration information item has the following properties:
1833: *
1834: * 1. [system identifier] The system identifier of the external subset, if
1835: * it exists. Otherwise this property has no value.
1836: *
1837: * @return the system identifier String object, or null if there is none.
1838: */
1839: public String getDocumentTypeDeclarationSystemIdentifier() {
1840: return null;
1841: }
1842:
1843: /**
1844: * Return the public identifier of the external subset,
1845: * normalized as described in 4.2.2 External Entities [XML]. If there is
1846: * no external subset or if it has no public identifier, this property
1847: * has no value.
1848: *
1849: * @return the public identifier String object, or null if there is none.
1850: */
1851: public String getDocumentTypeDeclarationPublicIdentifier() {
1852: return null;
1853: }
1854:
1855: /**
1856: * Returns the <code>Element</code> whose <code>ID</code> is given by
1857: * <code>elementId</code>. If no such element exists, returns
1858: * <code>DTM.NULL</code>. Behavior is not defined if more than one element
1859: * has this <code>ID</code>. Attributes (including those
1860: * with the name "ID") are not of type ID unless so defined by DTD/Schema
1861: * information available to the DTM implementation.
1862: * Implementations that do not know whether attributes are of type ID or
1863: * not are expected to return <code>DTM.NULL</code>.
1864: *
1865: * <p>%REVIEW% Presumably IDs are still scoped to a single document,
1866: * and this operation searches only within a single document, right?
1867: * Wouldn't want collisions between DTMs in the same process.</p>
1868: *
1869: * @param elementId The unique <code>id</code> value for an element.
1870: * @return The handle of the matching element.
1871: */
1872: public int getElementById(String elementId) {
1873: return 0;
1874: }
1875:
1876: /**
1877: * The getUnparsedEntityURI function returns the URI of the unparsed
1878: * entity with the specified name in the same document as the context
1879: * node (see [3.3 Unparsed Entities]). It returns the empty string if
1880: * there is no such entity.
1881: * <p>
1882: * XML processors may choose to use the System Identifier (if one
1883: * is provided) to resolve the entity, rather than the URI in the
1884: * Public Identifier. The details are dependent on the processor, and
1885: * we would have to support some form of plug-in resolver to handle
1886: * this properly. Currently, we simply return the System Identifier if
1887: * present, and hope that it a usable URI or that our caller can
1888: * map it to one.
1889: * TODO: Resolve Public Identifiers... or consider changing function name.
1890: * <p>
1891: * If we find a relative URI
1892: * reference, XML expects it to be resolved in terms of the base URI
1893: * of the document. The DOM doesn't do that for us, and it isn't
1894: * entirely clear whether that should be done here; currently that's
1895: * pushed up to a higher level of our application. (Note that DOM Level
1896: * 1 didn't store the document's base URI.)
1897: * TODO: Consider resolving Relative URIs.
1898: * <p>
1899: * (The DOM's statement that "An XML processor may choose to
1900: * completely expand entities before the structure model is passed
1901: * to the DOM" refers only to parsed entities, not unparsed, and hence
1902: * doesn't affect this function.)
1903: *
1904: * @param name A string containing the Entity Name of the unparsed
1905: * entity.
1906: *
1907: * @return String containing the URI of the Unparsed Entity, or an
1908: * empty string if no such entity exists.
1909: */
1910: public String getUnparsedEntityURI(String name) {
1911: return null;
1912: }
1913:
1914: // ============== Boolean methods ================
1915:
1916: /**
1917: * Return true if the xsl:strip-space or xsl:preserve-space was processed
1918: * during construction of the DTM document.
1919: *
1920: * <p>%REVEIW% Presumes a 1:1 mapping from DTM to Document, since
1921: * we aren't saying which Document to query...?</p>
1922: */
1923: public boolean supportsPreStripping() {
1924: return false;
1925: }
1926:
1927: /**
1928: * Figure out whether nodeHandle2 should be considered as being later
1929: * in the document than nodeHandle1, in Document Order as defined
1930: * by the XPath model. This may not agree with the ordering defined
1931: * by other XML applications.
1932: * <p>
1933: * There are some cases where ordering isn't defined, and neither are
1934: * the results of this function -- though we'll generally return true.
1935: *
1936: * TODO: Make sure this does the right thing with attribute nodes!!!
1937: *
1938: * @param nodeHandle1 DOM Node to perform position comparison on.
1939: * @param nodeHandle2 DOM Node to perform position comparison on .
1940: *
1941: * @return false if node2 comes before node1, otherwise return true.
1942: * You can think of this as
1943: * <code>(node1.documentOrderPosition <= node2.documentOrderPosition)</code>.
1944: */
1945: public boolean isNodeAfter(int nodeHandle1, int nodeHandle2) {
1946: return false;
1947: }
1948:
1949: /**
1950: * 2. [element content whitespace] A boolean indicating whether the
1951: * character is white space appearing within element content (see [XML],
1952: * 2.10 "White Space Handling"). Note that validating XML processors are
1953: * required by XML 1.0 to provide this information. If there is no
1954: * declaration for the containing element, this property has no value for
1955: * white space characters. If no declaration has been read, but the [all
1956: * declarations processed] property of the document information item is
1957: * false (so there may be an unread declaration), then the value of this
1958: * property is unknown for white space characters. It is always false for
1959: * characters that are not white space.
1960: *
1961: * @param nodeHandle the node ID.
1962: * @return <code>true</code> if the character data is whitespace;
1963: * <code>false</code> otherwise.
1964: */
1965: public boolean isCharacterElementContentWhitespace(int nodeHandle) {
1966: return false;
1967: }
1968:
1969: /**
1970: * 10. [all declarations processed] This property is not strictly speaking
1971: * part of the infoset of the document. Rather it is an indication of
1972: * whether the processor has read the complete DTD. Its value is a
1973: * boolean. If it is false, then certain properties (indicated in their
1974: * descriptions below) may be unknown. If it is true, those properties
1975: * are never unknown.
1976: *
1977: * @param documentHandle A node handle that must identify a document.
1978: * @return <code>true</code> if all declarations were processed;
1979: * <code>false</code> otherwise.
1980: */
1981: public boolean isDocumentAllDeclarationsProcessed(int documentHandle) {
1982: return false;
1983: }
1984:
1985: /**
1986: * 5. [specified] A flag indicating whether this attribute was actually
1987: * specified in the start-tag of its element, or was defaulted from the
1988: * DTD.
1989: *
1990: * @param attributeHandle the attribute handle
1991: * @return <code>true</code> if the attribute was specified;
1992: * <code>false</code> if it was defaulted.
1993: */
1994: public boolean isAttributeSpecified(int attributeHandle) {
1995: return false;
1996: }
1997:
1998: // ========== Direct SAX Dispatch, for optimization purposes ========
1999:
2000: /**
2001: * Directly call the
2002: * characters method on the passed ContentHandler for the
2003: * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
2004: * for the definition of a node's string-value). Multiple calls to the
2005: * ContentHandler's characters methods may well occur for a single call to
2006: * this method.
2007: *
2008: * @param nodeHandle The node ID.
2009: * @param ch A non-null reference to a ContentHandler.
2010: *
2011: * @throws org.xml.sax.SAXException
2012: */
2013: public void dispatchCharactersEvents(int nodeHandle,
2014: org.xml.sax.ContentHandler ch, boolean normalize)
2015: throws org.xml.sax.SAXException {
2016: }
2017:
2018: /**
2019: * Directly create SAX parser events from a subtree.
2020: *
2021: * @param nodeHandle The node ID.
2022: * @param ch A non-null reference to a ContentHandler.
2023: *
2024: * @throws org.xml.sax.SAXException
2025: */
2026:
2027: public void dispatchToEvents(int nodeHandle,
2028: org.xml.sax.ContentHandler ch)
2029: throws org.xml.sax.SAXException {
2030: }
2031:
2032: /**
2033: * Return an DOM node for the given node.
2034: *
2035: * @param nodeHandle The node ID.
2036: *
2037: * @return A node representation of the DTM node.
2038: */
2039: public org.w3c.dom.Node getNode(int nodeHandle) {
2040: return null;
2041: }
2042:
2043: // ==== Construction methods (may not be supported by some implementations!) =====
2044: // %REVIEW% jjk: These probably aren't the right API. At the very least
2045: // they need to deal with current-insertion-location and end-element
2046: // issues.
2047:
2048: /**
2049: * Append a child to the end of the child list of the current node. Please note that the node
2050: * is always cloned if it is owned by another document.
2051: *
2052: * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2053: * Does it become the last child of the Document? Of the root element?</p>
2054: *
2055: * @param newChild Must be a valid new node handle.
2056: * @param clone true if the child should be cloned into the document.
2057: * @param cloneDepth if the clone argument is true, specifies that the
2058: * clone should include all it's children.
2059: */
2060: public void appendChild(int newChild, boolean clone,
2061: boolean cloneDepth) {
2062: boolean sameDoc = ((newChild & DOCHANDLE_MASK) == m_docHandle);
2063: if (clone || !sameDoc) {
2064:
2065: } else {
2066:
2067: }
2068: }
2069:
2070: /**
2071: * Append a text node child that will be constructed from a string,
2072: * to the end of the document.
2073: *
2074: * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2075: * Does it become the last child of the Document? Of the root element?</p>
2076: *
2077: * @param str Non-null reference to a string.
2078: */
2079: public void appendTextChild(String str) {
2080: // ###shs Think more about how this differs from createTextNode
2081: //%TBD%
2082: }
2083:
2084: //================================================================
2085: // ==== BUILDER methods ====
2086: // %TBD% jjk: SHOULD PROBABLY BE INLINED, unless we want to support
2087: // both SAX1 and SAX2 and share this logic between them.
2088:
2089: /** Append a text child at the current insertion point. Assumes that the
2090: * actual content of the text has previously been appended to the m_char
2091: * buffer (shared with the builder).
2092: *
2093: * @param m_char_current_start int Starting offset of node's content in m_char.
2094: * @param contentLength int Length of node's content in m_char.
2095: * */
2096: void appendTextChild(int m_char_current_start, int contentLength) {
2097: // create a Text Node
2098: // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
2099: int w0 = TEXT_NODE;
2100: // W1: Parent
2101: int w1 = currentParent;
2102: // W2: Start position within m_char
2103: int w2 = m_char_current_start;
2104: // W3: Length of the full string
2105: int w3 = contentLength;
2106:
2107: int ourslot = appendNode(w0, w1, w2, w3);
2108: previousSibling = ourslot;
2109: }
2110:
2111: /** Append a comment child at the current insertion point. Assumes that the
2112: * actual content of the comment has previously been appended to the m_char
2113: * buffer (shared with the builder).
2114: *
2115: * @param m_char_current_start int Starting offset of node's content in m_char.
2116: * @param contentLength int Length of node's content in m_char.
2117: * */
2118: void appendComment(int m_char_current_start, int contentLength) {
2119: // create a Comment Node
2120: // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
2121: int w0 = COMMENT_NODE;
2122: // W1: Parent
2123: int w1 = currentParent;
2124: // W2: Start position within m_char
2125: int w2 = m_char_current_start;
2126: // W3: Length of the full string
2127: int w3 = contentLength;
2128:
2129: int ourslot = appendNode(w0, w1, w2, w3);
2130: previousSibling = ourslot;
2131: }
2132:
2133: /** Append an Element child at the current insertion point. This
2134: * Element then _becomes_ the insertion point; subsequent appends
2135: * become its lastChild until an appendEndElement() call is made.
2136: *
2137: * Assumes that the symbols (local name, namespace URI and prefix)
2138: * have already been added to the pools
2139: *
2140: * Note that this _only_ handles the Element node itself. Attrs and
2141: * namespace nodes are unbundled in the ContentHandler layer
2142: * and appended separately.
2143: *
2144: * @param namespaceIndex: Index within the namespaceURI string pool
2145: * @param localNameIndex Index within the local name string pool
2146: * @param prefixIndex: Index within the prefix string pool
2147: * */
2148: void appendStartElement(int namespaceIndex, int localNameIndex,
2149: int prefixIndex) {
2150: // do document root node creation here on the first element, create nodes for
2151: // this element and its attributes, store the element, namespace, and attritute
2152: // name indexes to the nodes array, keep track of the current node and parent
2153: // element used
2154:
2155: // W0 High: Namespace Low: Node Type
2156: int w0 = (namespaceIndex << 16) | ELEMENT_NODE;
2157: // W1: Parent
2158: int w1 = currentParent;
2159: // W2: Next (initialized as 0)
2160: int w2 = 0;
2161: // W3: Tagname high: prefix Low: local name
2162: int w3 = localNameIndex | prefixIndex << 16;
2163: /**/System.out.println("set w3=" + w3 + " " + (w3 >> 16) + "/"
2164: + (w3 & 0xffff));
2165:
2166: //int ourslot = nodes.appendSlot(w0, w1, w2, w3);
2167: int ourslot = appendNode(w0, w1, w2, w3);
2168: currentParent = ourslot;
2169: previousSibling = 0;
2170:
2171: // set the root element pointer when creating the first element node
2172: if (m_docElement == NULL)
2173: m_docElement = ourslot;
2174: }
2175:
2176: /** Append a Namespace Declaration child at the current insertion point.
2177: * Assumes that the symbols (namespace URI and prefix) have already been
2178: * added to the pools
2179: *
2180: * @param prefixIndex: Index within the prefix string pool
2181: * @param namespaceIndex: Index within the namespaceURI string pool
2182: * @param isID: If someone really insists on writing a bad DTD, it is
2183: * theoretically possible for a namespace declaration to also be declared
2184: * as being a node ID. I don't really want to support that stupidity,
2185: * but I'm not sure we can refuse to accept it.
2186: * */
2187: void appendNSDeclaration(int prefixIndex, int namespaceIndex,
2188: boolean isID) {
2189: // %REVIEW% I'm assigning this node the "namespace for namespaces"
2190: // which the DOM defined. It is expected that the Namespace spec will
2191: // adopt this as official. It isn't strictly needed since it's implied
2192: // by the nodetype, but for now...
2193:
2194: // %REVIEW% Prefix need not be recorded; it's implied too. But
2195: // recording it might simplify the design.
2196:
2197: // %TBD% isID is not currently honored.
2198:
2199: final int namespaceForNamespaces = m_nsNames
2200: .stringToIndex("http://www.w3.org/2000/xmlns/");
2201:
2202: // W0 High: Namespace Low: Node Type
2203: int w0 = NAMESPACE_NODE
2204: | (m_nsNames
2205: .stringToIndex("http://www.w3.org/2000/xmlns/") << 16);
2206:
2207: // W1: Parent
2208: int w1 = currentParent;
2209: // W2: CURRENTLY UNUSED -- It's next-sib in attrs, but we have no kids.
2210: int w2 = 0;
2211: // W3: namespace name
2212: int w3 = namespaceIndex;
2213: // Add node
2214: int ourslot = appendNode(w0, w1, w2, w3);
2215: previousSibling = ourslot; // Should attributes be previous siblings
2216: previousSiblingWasParent = false;
2217: return;//(m_docHandle | ourslot);
2218: }
2219:
2220: /** Append an Attribute child at the current insertion
2221: * point. Assumes that the symbols (namespace URI, local name, and
2222: * prefix) have already been added to the pools, and that the content has
2223: * already been appended to m_char. Note that the attribute's content has
2224: * been flattened into a single string; DTM does _NOT_ attempt to model
2225: * the details of entity references within attribute values.
2226: *
2227: * @param namespaceIndex int Index within the namespaceURI string pool
2228: * @param localNameIndex int Index within the local name string pool
2229: * @param prefixIndex int Index within the prefix string pool
2230: * @param isID boolean True if this attribute was declared as an ID
2231: * (for use in supporting getElementByID).
2232: * @param m_char_current_start int Starting offset of node's content in m_char.
2233: * @param contentLength int Length of node's content in m_char.
2234: * */
2235: void appendAttribute(int namespaceIndex, int localNameIndex,
2236: int prefixIndex, boolean isID, int m_char_current_start,
2237: int contentLength) {
2238: // %TBD% isID is not currently honored.
2239:
2240: // W0 High: Namespace Low: Node Type
2241: int w0 = ATTRIBUTE_NODE | namespaceIndex << 16;
2242:
2243: // W1: Parent
2244: int w1 = currentParent;
2245: // W2: Next (not yet resolved)
2246: int w2 = 0;
2247: // W3: Tagname high: prefix Low: local name
2248: int w3 = localNameIndex | prefixIndex << 16;
2249: /**/System.out.println("set w3=" + w3 + " " + (w3 >> 16) + "/"
2250: + (w3 & 0xffff));
2251: // Add node
2252: int ourslot = appendNode(w0, w1, w2, w3);
2253: previousSibling = ourslot; // Should attributes be previous siblings
2254:
2255: // Attribute's content is currently appended as a Text Node
2256:
2257: // W0: Node Type
2258: w0 = TEXT_NODE;
2259: // W1: Parent
2260: w1 = ourslot;
2261: // W2: Start Position within buffer
2262: w2 = m_char_current_start;
2263: // W3: Length
2264: w3 = contentLength;
2265: appendNode(w0, w1, w2, w3);
2266:
2267: // Attrs are Parents
2268: previousSiblingWasParent = true;
2269: return;//(m_docHandle | ourslot);
2270: }
2271:
2272: /**
2273: * This returns a stateless "traverser", that can navigate over an
2274: * XPath axis, though not in document order.
2275: *
2276: * @param axis One of Axes.ANCESTORORSELF, etc.
2277: *
2278: * @return A DTMAxisIterator, or null if the given axis isn't supported.
2279: */
2280: public DTMAxisTraverser getAxisTraverser(final int axis) {
2281: return null;
2282: }
2283:
2284: /**
2285: * This is a shortcut to the iterators that implement the
2286: * supported XPath axes (only namespace::) is not supported.
2287: * Returns a bare-bones iterator that must be initialized
2288: * with a start node (using iterator.setStartNode()).
2289: *
2290: * @param axis One of Axes.ANCESTORORSELF, etc.
2291: *
2292: * @return A DTMAxisIterator, or null if the given axis isn't supported.
2293: */
2294: public DTMAxisIterator getAxisIterator(final int axis) {
2295: // %TBD%
2296: return null;
2297: }
2298:
2299: /**
2300: * Get an iterator that can navigate over an XPath Axis, predicated by
2301: * the extended type ID.
2302: *
2303: *
2304: * @param axis
2305: * @param type An extended type ID.
2306: *
2307: * @return A DTMAxisIterator, or null if the given axis isn't supported.
2308: */
2309: public DTMAxisIterator getTypedAxisIterator(final int axis,
2310: final int type) {
2311: // %TBD%
2312: return null;
2313: }
2314:
2315: /** Terminate the element currently acting as an insertion point. Subsequent
2316: * insertions will occur as the last child of this element's parent.
2317: * */
2318: void appendEndElement() {
2319: // pop up the stacks
2320:
2321: if (previousSiblingWasParent)
2322: nodes.writeEntry(previousSibling, 2, NULL);
2323:
2324: // Pop parentage
2325: previousSibling = currentParent;
2326: nodes.readSlot(currentParent, gotslot);
2327: currentParent = gotslot[1] & 0xFFFF;
2328:
2329: // The element just being finished will be
2330: // the previous sibling for the next operation
2331: previousSiblingWasParent = true;
2332:
2333: // Pop a level of namespace table
2334: // namespaceTable.removeLastElem();
2335: }
2336:
2337: /** Starting a new document. Perform any resets/initialization
2338: * not already handled.
2339: * */
2340: void appendStartDocument() {
2341:
2342: // %TBD% reset slot 0 to indicate ChunkedIntArray reuse or wait for
2343: // the next initDocument().
2344: m_docElement = NULL; // reset nodeHandle to the root of the actual dtm doc content
2345: initDocument(0);
2346: }
2347:
2348: /** All appends to this document have finished; do whatever final
2349: * cleanup is needed.
2350: * */
2351: void appendEndDocument() {
2352: done = true;
2353: // %TBD% may need to notice the last slot number and slot count to avoid
2354: // residual data from provious use of this DTM
2355: }
2356:
2357: /**
2358: * For the moment all the run time properties are ignored by this
2359: * class.
2360: *
2361: * @param property a <code>String</code> value
2362: * @param value an <code>Object</code> value
2363: */
2364: public void setProperty(String property, Object value) {
2365: }
2366:
2367: /**
2368: * Source information is not handled yet, so return
2369: * <code>null</code> here.
2370: *
2371: * @param node an <code>int</code> value
2372: * @return null
2373: */
2374: public SourceLocator getSourceLocatorFor(int node) {
2375: return null;
2376: }
2377:
2378: /**
2379: * A dummy routine to satisify the abstract interface. If the DTM
2380: * implememtation that extends the default base requires notification
2381: * of registration, they can override this method.
2382: */
2383: public void documentRegistration() {
2384: }
2385:
2386: /**
2387: * A dummy routine to satisify the abstract interface. If the DTM
2388: * implememtation that extends the default base requires notification
2389: * when the document is being released, they can override this method
2390: */
2391: public void documentRelease() {
2392: }
2393:
2394: /**
2395: * Migrate a DTM built with an old DTMManager to a new DTMManager.
2396: * After the migration, the new DTMManager will treat the DTM as
2397: * one that is built by itself.
2398: * This is used to support DTM sharing between multiple transformations.
2399: * @param manager the DTMManager
2400: */
2401: public void migrateTo(DTMManager manager) {
2402: }
2403:
2404: }
|