001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: DTMDocumentImpl.java 1225427 2011-12-29 04:33:32Z mrglavas $
020     */
021    package org.apache.xml.dtm.ref;
022    
023    import javax.xml.transform.SourceLocator;
024    
025    import org.apache.xml.dtm.DTM;
026    import org.apache.xml.dtm.DTMAxisIterator;
027    import org.apache.xml.dtm.DTMAxisTraverser;
028    import org.apache.xml.dtm.DTMManager;
029    import org.apache.xml.dtm.DTMWSFilter;
030    import org.apache.xml.utils.FastStringBuffer;
031    import org.apache.xml.utils.XMLString;
032    import org.apache.xml.utils.XMLStringFactory;
033    
034    import org.xml.sax.Attributes;
035    import org.xml.sax.ContentHandler;
036    import org.xml.sax.Locator;
037    import org.xml.sax.ext.LexicalHandler;
038    
039    /**
040     * This is the implementation of the DTM document interface.  It receives
041     * requests from an XML content handler similar to that of an XML DOM or SAX parser
042     * to store information from the xml document in an array based
043     * dtm table structure.  This informtion is used later for document navigation,
044     * query, and SAX event dispatch functions. The DTM can also be used directly as a
045     * document composition model for an application.  The requests received are:
046     * <ul>
047     * <li>initiating DTM to set the doc handle</li>
048     * <li>resetting DTM for data structure reuse</li>
049     * <li>hinting the end of document to adjust the end of data structure pointers</li>
050     * <li>createnodes (element, comment, text, attribute, ....)</li>
051     * <li>hinting the end of an element to patch parent and siblings<li>
052     * <li>setting application provided symbol name stringpool data structures</li>
053     * </ul>
054     * <p>State: In progress!!</p>
055     *
056     * %REVIEW% I _think_ the SAX convention is that "no namespace" is expressed
057     * as "" rather than as null (which is the DOM's convention). What should
058     * DTM expect? What should it do with the other?
059     *
060     * <p>Origin: the implemention is a composite logic based on the DTM of XalanJ1 and
061     *     DocImpl, DocumentImpl, ElementImpl, TextImpl, etc. of XalanJ2</p>
062     */
063    public class DTMDocumentImpl
064    implements DTM, org.xml.sax.ContentHandler, org.xml.sax.ext.LexicalHandler
065    {
066    
067            // Number of lower bits used to represent node index.
068            protected static final byte DOCHANDLE_SHIFT = 22;
069            // Masks the lower order of node handle.
070            // Same as {@link DTMConstructor.IDENT_NODE_DEFAULT}
071            protected static final int NODEHANDLE_MASK = (1 << (DOCHANDLE_SHIFT + 1)) - 1;
072            // Masks the higher order Document handle
073            // Same as {@link DTMConstructor.IDENT_DOC_DEFAULT}
074            protected static final int DOCHANDLE_MASK = -1 - NODEHANDLE_MASK;
075    
076            int m_docHandle = NULL;          // masked document handle for this dtm document
077            int m_docElement = NULL;         // nodeHandle to the root of the actual dtm doc content
078    
079            // Context for parse-and-append operations
080            int currentParent = 0;                  // current parent - default is document root
081            int previousSibling = 0;                // previous sibling - no previous sibling
082            protected int m_currentNode = -1;               // current node
083    
084            // The tree under construction can itself be used as
085            // the element stack, so m_elemStack isn't needed.
086            //protected Stack m_elemStack = new Stack();     // element stack
087    
088            private boolean previousSiblingWasParent = false;
089            // Local cache for record-at-a-time fetch
090            int gotslot[] = new int[4];
091    
092            // endDocument recieved?
093            private boolean done = false;
094            boolean m_isError = false;
095    
096            static private final boolean DEBUG = false;
097    
098            /** The document base URI. */
099            protected String m_documentBaseURI;
100    
101      /** If we're building the model incrementally on demand, we need to
102       * be able to tell the source when to send us more data.
103       *
104       * Note that if this has not been set, and you attempt to read ahead
105       * of the current build point, we'll probably throw a null-pointer
106       * exception. We could try to wait-and-retry instead, as a very poor
107       * fallback, but that has all the known problems with multithreading
108       * on multiprocessors and we Don't Want to Go There.
109       *
110       * @see setIncrementalSAXSource
111       */
112      private IncrementalSAXSource m_incrSAXSource=null;
113    
114    
115            // ========= DTM data structure declarations. ==============
116    
117            // nodes array: integer array blocks to hold the first level reference of the nodes,
118            // each reference slot is addressed by a nodeHandle index value.
119            // Assumes indices are not larger than {@link NODEHANDLE_MASK}
120            // ({@link DOCHANDLE_SHIFT} bits).
121            ChunkedIntArray nodes = new ChunkedIntArray(4);
122    
123            // text/comment table: string buffer to hold the text string values of the document,
124            // each of which is addressed by the absolute offset and length in the buffer
125            private FastStringBuffer m_char = new FastStringBuffer();
126            // Start of string currently being accumulated into m_char;
127            // needed because the string may be appended in several chunks.
128            private int m_char_current_start=0;
129    
130            // %TBD% INITIALIZATION/STARTUP ISSUES
131            // -- Should we really be creating these, or should they be
132            // passed in from outside? Scott want to be able to share
133            // pools across multiple documents, so setting them here is
134            // probably not the right default.
135            private DTMStringPool m_localNames = new DTMStringPool();
136            private DTMStringPool m_nsNames = new DTMStringPool();
137            private DTMStringPool m_prefixNames = new DTMStringPool();
138    
139            // %TBD% If we use the current ExpandedNameTable mapper, it
140            // needs to be bound to the NS and local name pools. Which
141            // means it needs to attach to them AFTER we've resolved their
142            // startup. Or it needs to attach to this document and
143            // retrieve them each time. Or this needs to be
144            // an interface _implemented_ by this class... which might be simplest!
145            private ExpandedNameTable m_expandedNames=
146                    new ExpandedNameTable();
147    
148            private XMLStringFactory m_xsf;
149    
150    
151            /**
152             * Construct a DTM.
153             *
154             * @param documentNumber the ID number assigned to this document.
155             * It will be shifted up into the high bits and returned as part of
156             * all node ID numbers, so those IDs indicate which document they
157             * came from as well as a location within the document. It is the
158             * DTMManager's responsibility to assign a unique number to each
159             * document.
160             */
161            public DTMDocumentImpl(DTMManager mgr, int documentNumber,
162                                   DTMWSFilter whiteSpaceFilter,
163                                   XMLStringFactory xstringfactory){
164                    initDocument(documentNumber);    // clear nodes and document handle
165                    m_xsf = xstringfactory;
166            }
167    
168      /** Bind a IncrementalSAXSource to this DTM. If we discover we need nodes
169       * that have not yet been built, we will ask this object to send us more
170       * events, and it will manage interactions with its data sources.
171       *
172       * Note that we do not actually build the IncrementalSAXSource, since we don't
173       * know what source it's reading from, what thread that source will run in,
174       * or when it will run.
175       *
176       * @param source The IncrementalSAXSource that we want to recieve events from
177       * on demand.
178       */
179      public void setIncrementalSAXSource(IncrementalSAXSource source)
180      {
181        m_incrSAXSource=source;
182    
183        // Establish SAX-stream link so we can receive the requested data
184        source.setContentHandler(this);
185        source.setLexicalHandler(this);
186    
187        // Are the following really needed? IncrementalSAXSource doesn't yet
188        // support them, and they're mostly no-ops here...
189        //source.setErrorHandler(this);
190        //source.setDTDHandler(this);
191        //source.setDeclHandler(this);
192      }
193    
194            /**
195             * Wrapper for ChunkedIntArray.append, to automatically update the
196             * previous sibling's "next" reference (if necessary) and periodically
197             * wake a reader who may have encountered incomplete data and entered
198             * a wait state.
199             * @param w0 int As in ChunkedIntArray.append
200             * @param w1 int As in ChunkedIntArray.append
201             * @param w2 int As in ChunkedIntArray.append
202             * @param w3 int As in ChunkedIntArray.append
203             * @return int As in ChunkedIntArray.append
204             * @see ChunkedIntArray.append
205             */
206            private final int appendNode(int w0, int w1, int w2, int w3)
207            {
208                    // A decent compiler may inline this.
209                    int slotnumber = nodes.appendSlot(w0, w1, w2, w3);
210    
211                    if (DEBUG) System.out.println(slotnumber+": "+w0+" "+w1+" "+w2+" "+w3);
212    
213                    if (previousSiblingWasParent)
214                            nodes.writeEntry(previousSibling,2,slotnumber);
215    
216                    previousSiblingWasParent = false;       // Set the default; endElement overrides
217    
218                    return slotnumber;
219            }
220    
221            // ========= DTM Implementation Control Functions. ==============
222    
223            /**
224             * Set an implementation dependent feature.
225             * <p>
226             * %REVIEW% Do we really expect to set features on DTMs?
227             *
228             * @param featureId A feature URL.
229             * @param state true if this feature should be on, false otherwise.
230             */
231            public void setFeature(String featureId, boolean state) {};
232    
233            /**
234             * Set a reference pointer to the element name symbol table.
235             * %REVIEW% Should this really be Public? Changing it while
236             * DTM is in use would be a disaster.
237             *
238             * @param poolRef DTMStringPool reference to an instance of table.
239             */
240            public void setLocalNameTable(DTMStringPool poolRef) {
241                    m_localNames = poolRef;
242            }
243    
244            /**
245             * Get a reference pointer to the element name symbol table.
246             *
247             * @return DTMStringPool reference to an instance of table.
248             */
249            public DTMStringPool getLocalNameTable() {
250                     return m_localNames;
251             }
252    
253            /**
254             * Set a reference pointer to the namespace URI symbol table.
255             * %REVIEW% Should this really be Public? Changing it while
256             * DTM is in use would be a disaster.
257             *
258             * @param poolRef DTMStringPool reference to an instance of table.
259             */
260            public void setNsNameTable(DTMStringPool poolRef) {
261                    m_nsNames = poolRef;
262            }
263    
264            /**
265             * Get a reference pointer to the namespace URI symbol table.
266             *
267             * @return DTMStringPool reference to an instance of table.
268             */
269            public DTMStringPool getNsNameTable() {
270                     return m_nsNames;
271             }
272    
273            /**
274             * Set a reference pointer to the prefix name symbol table.
275             * %REVIEW% Should this really be Public? Changing it while
276             * DTM is in use would be a disaster.
277             *
278             * @param poolRef DTMStringPool reference to an instance of table.
279             */
280            public void setPrefixNameTable(DTMStringPool poolRef) {
281                    m_prefixNames = poolRef;
282            }
283    
284            /**
285             * Get a reference pointer to the prefix name symbol table.
286             *
287             * @return DTMStringPool reference to an instance of table.
288             */
289            public DTMStringPool getPrefixNameTable() {
290                    return m_prefixNames;
291            }
292    
293             /**
294              * Set a reference pointer to the content-text repository
295              *
296              * @param buffer FastStringBuffer reference to an instance of
297              * buffer
298              */
299             void setContentBuffer(FastStringBuffer buffer) {
300                     m_char = buffer;
301             }
302    
303             /**
304              * Get a reference pointer to the content-text repository
305              *
306              * @return FastStringBuffer reference to an instance of buffer
307              */
308             FastStringBuffer getContentBuffer() {
309                     return m_char;
310             }
311    
312      /** getContentHandler returns "our SAX builder" -- the thing that
313       * someone else should send SAX events to in order to extend this
314       * DTM model.
315       *
316       * @return null if this model doesn't respond to SAX events,
317       * "this" if the DTM object has a built-in SAX ContentHandler,
318       * the IncrementalSAXSource if we're bound to one and should receive
319       * the SAX stream via it for incremental build purposes...
320       * */
321      public org.xml.sax.ContentHandler getContentHandler()
322      {
323        if (m_incrSAXSource instanceof IncrementalSAXSource_Filter)
324          return (ContentHandler) m_incrSAXSource;
325        else
326          return this;
327      }
328    
329      /**
330       * Return this DTM's lexical handler.
331       *
332       * %REVIEW% Should this return null if constrution already done/begun?
333       *
334       * @return null if this model doesn't respond to lexical SAX events,
335       * "this" if the DTM object has a built-in SAX ContentHandler,
336       * the IncrementalSAXSource if we're bound to one and should receive
337       * the SAX stream via it for incremental build purposes...
338       */
339      public LexicalHandler getLexicalHandler()
340      {
341    
342        if (m_incrSAXSource instanceof IncrementalSAXSource_Filter)
343          return (LexicalHandler) m_incrSAXSource;
344        else
345          return this;
346      }
347    
348      /**
349       * Return this DTM's EntityResolver.
350       *
351       * @return null if this model doesn't respond to SAX entity ref events.
352       */
353      public org.xml.sax.EntityResolver getEntityResolver()
354      {
355    
356        return null;
357      }
358    
359      /**
360       * Return this DTM's DTDHandler.
361       *
362       * @return null if this model doesn't respond to SAX dtd events.
363       */
364      public org.xml.sax.DTDHandler getDTDHandler()
365      {
366    
367        return null;
368      }
369    
370      /**
371       * Return this DTM's ErrorHandler.
372       *
373       * @return null if this model doesn't respond to SAX error events.
374       */
375      public org.xml.sax.ErrorHandler getErrorHandler()
376      {
377    
378        return null;
379      }
380    
381      /**
382       * Return this DTM's DeclHandler.
383       *
384       * @return null if this model doesn't respond to SAX Decl events.
385       */
386      public org.xml.sax.ext.DeclHandler getDeclHandler()
387      {
388    
389        return null;
390      }
391    
392      /** @return true iff we're building this model incrementally (eg
393       * we're partnered with a IncrementalSAXSource) and thus require that the
394       * transformation and the parse run simultaneously. Guidance to the
395       * DTMManager.
396       * */
397      public boolean needsTwoThreads()
398      {
399        return null!=m_incrSAXSource;
400      }
401    
402      //================================================================
403      // ========= SAX2 ContentHandler methods =========
404      // Accept SAX events, use them to build/extend the DTM tree.
405      // Replaces the deprecated DocumentHandler interface.
406    
407      public void characters(char[] ch, int start, int length)
408           throws org.xml.sax.SAXException
409      {
410        // Actually creating the text node is handled by
411        // processAccumulatedText(); here we just accumulate the
412        // characters into the buffer.
413        m_char.append(ch,start,length);
414      }
415    
416      // Flush string accumulation into a text node
417      private void processAccumulatedText()
418      {
419        int len=m_char.length();
420        if(len!=m_char_current_start)
421          {
422            // The FastStringBuffer has been previously agreed upon
423            appendTextChild(m_char_current_start,len-m_char_current_start);
424            m_char_current_start=len;
425          }
426      }
427      public void endDocument()
428           throws org.xml.sax.SAXException
429      {
430        // May need to tell the low-level builder code to pop up a level.
431        // There _should't_ be any significant pending text at this point.
432        appendEndDocument();
433      }
434      public void endElement(java.lang.String namespaceURI, java.lang.String localName,
435          java.lang.String qName)
436           throws org.xml.sax.SAXException
437      {
438        processAccumulatedText();
439        // No args but we do need to tell the low-level builder code to
440        // pop up a level.
441        appendEndElement();
442      }
443      public void endPrefixMapping(java.lang.String prefix)
444           throws org.xml.sax.SAXException
445      {
446        // No-op
447      }
448      public void ignorableWhitespace(char[] ch, int start, int length)
449           throws org.xml.sax.SAXException
450      {
451        // %TBD% I believe ignorable text isn't part of the DTM model...?
452      }
453      public void processingInstruction(java.lang.String target, java.lang.String data)
454           throws org.xml.sax.SAXException
455      {
456        processAccumulatedText();
457        // %TBD% Which pools do target and data go into?
458      }
459      public void setDocumentLocator(Locator locator)
460      {
461        // No-op for DTM
462      }
463      public void skippedEntity(java.lang.String name)
464           throws org.xml.sax.SAXException
465      {
466        processAccumulatedText();
467        //%TBD%
468      }
469      public void startDocument()
470           throws org.xml.sax.SAXException
471      {
472        appendStartDocument();
473      }
474      public void startElement(java.lang.String namespaceURI, java.lang.String localName,
475          java.lang.String qName, Attributes atts)
476           throws org.xml.sax.SAXException
477      {
478        processAccumulatedText();
479    
480        // %TBD% Split prefix off qname
481        String prefix=null;
482        int colon=qName.indexOf(':');
483        if(colon>0)
484          prefix=qName.substring(0,colon);
485    
486        // %TBD% Where do we pool expandedName, or is it just the union, or...
487        /**/System.out.println("Prefix="+prefix+" index="+m_prefixNames.stringToIndex(prefix));
488        appendStartElement(m_nsNames.stringToIndex(namespaceURI),
489                         m_localNames.stringToIndex(localName),
490                         m_prefixNames.stringToIndex(prefix)); /////// %TBD%
491    
492        // %TBD% I'm assuming that DTM will require resequencing of
493        // NS decls before other attrs, hence two passes are taken.
494        // %TBD% Is there an easier way to test for NSDecl?
495        int nAtts=(atts==null) ? 0 : atts.getLength();
496        // %TBD% Countdown is more efficient if nobody cares about sequence.
497        for(int i=nAtts-1;i>=0;--i)
498          {
499            qName=atts.getQName(i);
500            if(qName.startsWith("xmlns:") || "xmlns".equals(qName))
501              {
502                prefix=null;
503                colon=qName.indexOf(':');
504                if(colon>0)
505                  {
506                    prefix=qName.substring(0,colon);
507                  }
508                else
509                  {
510                    // %REVEIW% Null or ""?
511                    prefix=null; // Default prefix
512                  }
513    
514    
515                appendNSDeclaration(
516                                        m_prefixNames.stringToIndex(prefix),
517                                        m_nsNames.stringToIndex(atts.getValue(i)),
518                                        atts.getType(i).equalsIgnoreCase("ID"));
519              }
520          }
521    
522        for(int i=nAtts-1;i>=0;--i)
523          {
524            qName=atts.getQName(i);
525            if(!(qName.startsWith("xmlns:") || "xmlns".equals(qName)))
526              {
527                // %TBD% I hate having to extract the prefix into a new
528                // string when we may never use it. Consider pooling whole
529                // qNames, which are already strings?
530                prefix=null;
531                colon=qName.indexOf(':');
532                if(colon>0)
533                  {
534                    prefix=qName.substring(0,colon);
535                    localName=qName.substring(colon+1);
536                  }
537                else
538                  {
539                    prefix=""; // Default prefix
540                    localName=qName;
541                  }
542    
543    
544                m_char.append(atts.getValue(i)); // Single-string value
545                int contentEnd=m_char.length();
546    
547                if(!("xmlns".equals(prefix) || "xmlns".equals(qName)))
548                  appendAttribute(m_nsNames.stringToIndex(atts.getURI(i)),
549                                      m_localNames.stringToIndex(localName),
550                                      m_prefixNames.stringToIndex(prefix),
551                                      atts.getType(i).equalsIgnoreCase("ID"),
552                                      m_char_current_start, contentEnd-m_char_current_start);
553                m_char_current_start=contentEnd;
554              }
555          }
556      }
557      public void startPrefixMapping(java.lang.String prefix, java.lang.String uri)
558           throws org.xml.sax.SAXException
559      {
560        // No-op in DTM, handled during element/attr processing?
561      }
562    
563      //
564      // LexicalHandler support. Not all SAX2 parsers support these events
565      // but we may want to pass them through when they exist...
566      //
567      public void comment(char[] ch, int start, int length)
568           throws org.xml.sax.SAXException
569      {
570        processAccumulatedText();
571    
572        m_char.append(ch,start,length); // Single-string value
573        appendComment(m_char_current_start,length);
574        m_char_current_start+=length;
575      }
576      public void endCDATA()
577           throws org.xml.sax.SAXException
578      {
579        // No-op in DTM
580      }
581      public void endDTD()
582           throws org.xml.sax.SAXException
583      {
584        // No-op in DTM
585      }
586      public void endEntity(java.lang.String name)
587           throws org.xml.sax.SAXException
588      {
589        // No-op in DTM
590      }
591      public void startCDATA()
592           throws org.xml.sax.SAXException
593      {
594        // No-op in DTM
595      }
596      public void startDTD(java.lang.String name, java.lang.String publicId,
597          java.lang.String systemId)
598           throws org.xml.sax.SAXException
599      {
600        // No-op in DTM
601      }
602      public void startEntity(java.lang.String name)
603           throws org.xml.sax.SAXException
604      {
605        // No-op in DTM
606      }
607    
608    
609      //================================================================
610      // ========= Document Handler Functions =========
611      // %REVIEW% jjk -- DocumentHandler is  SAX Level 1, and deprecated....
612      // and this wasn't a fully compliant or declared implementation of that API
613      // in any case. Phase out in favor of SAX2 ContentHandler/LexicalHandler
614    
615            /**
616             * Reset a dtm document to its initial (empty) state.
617             *
618             * The DTMManager will invoke this method when the dtm is created.
619             *
620             * @param documentNumber the handle for the DTM document.
621             */
622            final void initDocument(int documentNumber)
623            {
624                    // save masked DTM document handle
625                    m_docHandle = documentNumber<<DOCHANDLE_SHIFT;
626    
627                    // Initialize the doc -- no parent, no next-sib
628                    nodes.writeSlot(0,DOCUMENT_NODE,-1,-1,0);
629                    // wait for the first startElement to create the doc root node
630                    done = false;
631            }
632    
633    //      /**
634    //       * Receive hint of the end of a document.
635    //       *
636    //       * <p>The content handler will invoke this method only once, and it will
637    //       * be the last method invoked during the parse.  The handler shall not
638    //       * not invoke this method until it has either abandoned parsing
639    //       * (because of an unrecoverable error) or reached the end of
640    //       * input.</p>
641    //       */
642    //      public void documentEnd()
643    //      {
644    //              done = true;
645    //              // %TBD% may need to notice the last slot number and slot count to avoid
646    //              // residual data from provious use of this DTM
647    //      }
648    
649    //      /**
650    //       * Receive notification of the beginning of a document.
651    //       *
652    //       * <p>The SAX parser will invoke this method only once, before any
653    //       * other methods in this interface.</p>
654    //       */
655    //      public void reset()
656    //      {
657    
658    //              // %TBD% reset slot 0 to indicate ChunkedIntArray reuse or wait for
659    //              //       the next initDocument().
660    //              m_docElement = NULL;     // reset nodeHandle to the root of the actual dtm doc content
661    //              initDocument(0);
662    //      }
663    
664    //      /**
665    //       * Factory method; creates an Element node in this document.
666    //       *
667    //       * The node created will be chained according to its natural order of request
668    //       * received.  %TBD% It can be rechained later via the optional DTM writable interface.
669    //       *
670    //       * <p>The XML content handler will invoke endElement() method after all
671    //       * of the element's content are processed in order to give DTM the indication
672    //       * to prepare and patch up parent and sibling node pointers.</p>
673    //       *
674    //       * <p>The following interface for createElement will use an index value corresponds
675    //       * to the symbol entry in the DTMDStringPool based symbol tables.</p>
676    //       *
677    //       * @param nsIndex The namespace of the node
678    //       * @param nameIndex The element name.
679    //       * @see #endElement
680    //       * @see org.xml.sax.Attributes
681    //       * @return nodeHandle int of the element created
682    //       */
683    //      public int createElement(int nsIndex, int nameIndex, Attributes atts)
684    //      {
685    //              // do document root node creation here on the first element, create nodes for
686    //              // this element and its attributes, store the element, namespace, and attritute
687    //              // name indexes to the nodes array, keep track of the current node and parent
688    //              // element used
689    
690    //              // W0  High:  Namespace  Low:  Node Type
691    //              int w0 = (nsIndex << 16) | ELEMENT_NODE;
692    //              // W1: Parent
693    //              int w1 = currentParent;
694    //              // W2: Next  (initialized as 0)
695    //              int w2 = 0;
696    //              // W3: Tagname
697    //              int w3 = nameIndex;
698    //              //int ourslot = nodes.appendSlot(w0, w1, w2, w3);
699    //              int ourslot = appendNode(w0, w1, w2, w3);
700    //              currentParent = ourslot;
701    //              previousSibling = 0;
702    //              setAttributes(atts);
703    
704    //              // set the root element pointer when creating the first element node
705    //              if (m_docElement == NULL)
706    //                      m_docElement = ourslot;
707    //              return (m_docHandle | ourslot);
708    //      }
709    
710    //      // Factory method to create an Element node not associated with a given name space
711    //      // using String value parameters passed in from a content handler or application
712    //      /**
713    //       * Factory method; creates an Element node not associated with a given name space in this document.
714    //       *
715    //       * The node created will be chained according to its natural order of request
716    //       * received.  %TBD% It can be rechained later via the optional DTM writable interface.
717    //       *
718    //       * <p>The XML content handler or application will invoke endElement() method after all
719    //       * of the element's content are processed in order to give DTM the indication
720    //       * to prepare and patch up parent and sibling node pointers.</p>
721    //       *
722    //       * <p>The following parameters for createElement contains raw string values for name
723    //       * symbols used in an Element node.</p>
724    //       *
725    //       * @param name String the element name, including the prefix if any.
726    //       * @param atts The attributes attached to the element, if any.
727    //       * @see #endElement
728    //       * @see org.xml.sax.Attributes
729    //       */
730    //      public int createElement(String name, Attributes atts)
731    //      {
732    //              // This method wraps around the index valued interface of the createElement interface.
733    //              // The raw string values are stored into the current DTM name symbol tables.  The method
734    //              // method will then use the index values returned to invoke the other createElement()
735    //              // onverted to index values modified to match a
736    //              // method.
737    //              int nsIndex = NULL;
738    //              int nameIndex = m_localNames.stringToIndex(name);
739    //              // note - there should be no prefix separator in the name because it is not associated
740    //              // with a name space
741    
742    //              return createElement(nsIndex, nameIndex, atts);
743    //      }
744    
745    //      // Factory method to create an Element node associated with a given name space
746    //      // using String value parameters passed in from a content handler or application
747    //      /**
748    //       * Factory method; creates an Element node associated with a given name space in this document.
749    //       *
750    //       * The node created will be chained according to its natural order of request
751    //       * received.  %TBD% It can be rechained later via the optional DTM writable interface.
752    //       *
753    //       * <p>The XML content handler or application will invoke endElement() method after all
754    //       * of the element's content are processed in order to give DTM the indication
755    //       * to prepare and patch up parent and sibling node pointers.</p>
756    //       *
757    //       * <p>The following parameters for createElementNS contains raw string values for name
758    //       * symbols used in an Element node.</p>
759    //       *
760    //       * @param ns String the namespace of the node
761    //       * @param name String the element name, including the prefix if any.
762    //       * @param atts The attributes attached to the element, if any.
763    //       * @see #endElement
764    //       * @see org.xml.sax.Attributes
765    //       */
766    //      public int createElementNS(String ns, String name, Attributes atts)
767    //      {
768    //              // This method wraps around the index valued interface of the createElement interface.
769    //              // The raw string values are stored into the current DTM name symbol tables.  The method
770    //              // method will then use the index values returned to invoke the other createElement()
771    //              // onverted to index values modified to match a
772    //              // method.
773    //              int nsIndex = m_nsNames.stringToIndex(ns);
774    //              int nameIndex = m_localNames.stringToIndex(name);
775    //              // The prefixIndex is not needed by the indexed interface of the createElement method
776    //              int prefixSep = name.indexOf(":");
777    //              int prefixIndex = m_prefixNames.stringToIndex(name.substring(0, prefixSep));
778    //              return createElement(nsIndex, nameIndex, atts);
779    //      }
780    
781    //      /**
782    //       * Receive an indication for the end of an element.
783    //       *
784    //       * <p>The XML content handler will invoke this method at the end of every
785    //       * element in the XML document to give hint its time to pop up the current
786    //       * element and parent and patch up parent and sibling pointers if necessary
787    //       *
788    //       * <p>%tbd% The following interface may need to be modified to match a
789    //       * coordinated access to the DTMDStringPool based symbol tables.</p>
790    //               *
791    //       * @param ns the namespace of the element
792    //       * @param name The element name
793    //       */
794    //      public void endElement(String ns, String name)
795    //      {
796    //              // pop up the stacks
797    
798    //              //
799    //              if (previousSiblingWasParent)
800    //                      nodes.writeEntry(previousSibling, 2, NULL);
801    
802    //              // Pop parentage
803    //              previousSibling = currentParent;
804    //              nodes.readSlot(currentParent, gotslot);
805    //              currentParent = gotslot[1] & 0xFFFF;
806    
807    //              // The element just being finished will be
808    //              // the previous sibling for the next operation
809    //              previousSiblingWasParent = true;
810    
811    //              // Pop a level of namespace table
812    //              // namespaceTable.removeLastElem();
813    //      }
814    
815    //      /**
816    //       * Creates attributes for the current node.
817    //       *
818    //       * @param atts Attributes to be created.
819    //       */
820    //      void setAttributes(Attributes atts) {
821    //              int atLength = (null == atts) ? 0 : atts.getLength();
822    //              for (int i=0; i < atLength; i++) {
823    //                      String qname = atts.getQName(i);
824    //                      createAttribute(atts.getQName(i), atts.getValue(i));
825    //              }
826    //      }
827    
828    //      /**
829    //       * Appends an attribute to the document.
830    //       * @param qname Qualified Name of the attribute
831    //       * @param value Value of the attribute
832    //       * @return Handle of node
833    //       */
834    //      public int createAttribute(String qname, String value) {
835    //              int colonpos = qname.indexOf(":");
836    //              String attName = qname.substring(colonpos+1);
837    //              int w0 = 0;
838    //              if (colonpos > 0) {
839    //                      String prefix = qname.substring(0, colonpos);
840    //                      if (prefix.equals("xml")) {
841    //                              //w0 = ATTRIBUTE_NODE |
842    //                              //      (org.apache.xalan.templates.Constants.S_XMLNAMESPACEURI << 16);
843    //                      } else {
844    //                              //w0 = ATTRIBUTE_NODE |
845    //                      }
846    //              } else {
847    //                      w0 = ATTRIBUTE_NODE;
848    //              }
849    //              // W1:  Parent
850    //              int w1 = currentParent;
851    //              // W2:  Next (not yet resolved)
852    //              int w2 = 0;
853    //              // W3:  Tag name
854    //              int w3 = m_localNames.stringToIndex(attName);
855    //              // Add node
856    //              int ourslot = appendNode(w0, w1, w2, w3);
857    //              previousSibling = ourslot;      // Should attributes be previous siblings
858    
859    //              // W0: Node Type
860    //              w0 = TEXT_NODE;
861    //              // W1: Parent
862    //              w1 = ourslot;
863    //              // W2: Start Position within buffer
864    //              w2 = m_char.length();
865    //              m_char.append(value);
866    //              // W3: Length
867    //              w3 = m_char.length() - w2;
868    //              appendNode(w0, w1, w2, w3);
869    //              charStringStart=m_char.length();
870    //              charStringLength = 0;
871    //              //previousSibling = ourslot;
872    //              // Attrs are Parents
873    //              previousSiblingWasParent = true;
874    //              return (m_docHandle | ourslot);
875    //      }
876    
877    //      /**
878    //       * Factory method; creates a Text node in this document.
879    //       *
880    //       * The node created will be chained according to its natural order of request
881    //       * received.  %TBD% It can be rechained later via the optional DTM writable interface.
882    //       *
883    //       * @param text String The characters text string from the XML document.
884    //       * @return int DTM node-number of the text node created
885    //       */
886    //      public int createTextNode(String text)
887    //      throws DTMException
888    //      {
889    //              // wraps around the index value based createTextNode method
890    //              return createTextNode(text.toCharArray(), 0, text.length());
891    //      }
892    
893    //      /**
894    //       * Factory method; creates a Text node in this document.
895    //       *
896    //       * The node created will be chained according to its natural order of request
897    //       * received.  %TBD% It can be rechained later via the optional DTM writable interface.
898    //       *
899    //       * %REVIEW% for text normalization issues, unless we are willing to
900    //       * insist that all adjacent text must be merged before this method
901    //       * is called.
902    //       *
903    //       * @param ch The characters from the XML document.
904    //       * @param start The start position in the array.
905    //       * @param length The number of characters to read from the array.
906    //       */
907    //      public int createTextNode(char ch[], int start, int length)
908    //      throws DTMException
909    //      {
910    //              m_char.append(ch, start, length);               // store the chunk to the text/comment string table
911    
912    //              // create a Text Node
913    //              // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
914    //              int w0 = TEXT_NODE;
915    //              // W1: Parent
916    //              int w1 = currentParent;
917    //              // W2: Start position within m_char
918    //              int w2 = charStringStart;
919    //              // W3: Length of the full string
920    //              int w3 = length;
921    //              int ourslot = appendNode(w0, w1, w2, w3);
922    //              previousSibling = ourslot;
923    
924    //              charStringStart=m_char.length();
925    //              charStringLength = 0;
926    //              return (m_docHandle | ourslot);
927    //      }
928    
929    //      /**
930    //       * Factory method; creates a Comment node in this document.
931    //       *
932    //       * The node created will be chained according to its natural order of request
933    //       * received.  %TBD% It can be rechained later via the optional DTM writable interface.
934    //       *
935    //       * @param text String The characters text string from the XML document.
936    //       * @return int DTM node-number of the text node created
937    //       */
938    //      public int createComment(String text)
939    //      throws DTMException
940    //      {
941    //              // wraps around the index value based createTextNode method
942    //              return createComment(text.toCharArray(), 0, text.length());
943    //      }
944    
945    //      /**
946    //       * Factory method; creates a Comment node in this document.
947    //       *
948    //       * The node created will be chained according to its natural order of request
949    //       * received.  %TBD% It can be rechained later via the optional DTM writable interface.
950    //       *
951    //       * @param ch An array holding the characters in the comment.
952    //       * @param start The starting position in the array.
953    //       * @param length The number of characters to use from the array.
954    //       * @see DTMException
955    //       */
956    //      public int createComment(char ch[], int start, int length)
957    //      throws DTMException
958    //      {
959    //              m_char.append(ch, start, length);               // store the comment string to the text/comment string table
960    
961    //              // create a Comment Node
962    //              // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
963    //              int w0 = COMMENT_NODE;
964    //              // W1: Parent
965    //              int w1 = currentParent;
966    //              // W2: Start position within m_char
967    //              int w2 = charStringStart;
968    //              // W3: Length of the full string
969    //              int w3 = length;
970    //              int ourslot = appendNode(w0, w1, w2, w3);
971    //              previousSibling = ourslot;
972    
973    //              charStringStart=m_char.length();
974    //              charStringLength = 0;
975    //              return (m_docHandle | ourslot);
976    //      }
977    
978    //      // Counters to keep track of the current text string being accumulated with respect
979    //      // to the text/comment string table: charStringStart should point to the starting
980    //      // offset of the string in the table and charStringLength the acccumulated length when
981    //      // appendAccumulatedText starts, and reset to the end of the table and 0 at the end
982    //      // of appendAccumulatedText for the next set of characters receives
983    //      int charStringStart=0,charStringLength=0;
984    
985            // ========= Document Navigation Functions =========
986    
987            /** Given a node handle, test if it has child nodes.
988             * <p> %REVIEW% This is obviously useful at the DOM layer, where it
989             * would permit testing this without having to create a proxy
990             * node. It's less useful in the DTM API, where
991             * (dtm.getFirstChild(nodeHandle)!=DTM.NULL) is just as fast and
992             * almost as self-evident. But it's a convenience, and eases porting
993             * of DOM code to DTM.  </p>
994             *
995             * @param nodeHandle int Handle of the node.
996             * @return int true if the given node has child nodes.
997             */
998            public boolean hasChildNodes(int nodeHandle) {
999                    return(getFirstChild(nodeHandle) != NULL);
1000            }
1001    
1002            /**
1003             * Given a node handle, get the handle of the node's first child.
1004             * If not yet resolved, waits for more nodes to be added to the document and
1005             * tries again.
1006             *
1007             * @param nodeHandle int Handle of the node.
1008             * @return int DTM node-number of first child, or DTM.NULL to indicate none exists.
1009             */
1010            public int getFirstChild(int nodeHandle) {
1011    
1012                    // ###shs worry about tracing/debug later
1013                    nodeHandle &= NODEHANDLE_MASK;
1014                    // Read node into variable
1015                    nodes.readSlot(nodeHandle, gotslot);
1016    
1017                    // type is the last half of first slot
1018                    short type = (short) (gotslot[0] & 0xFFFF);
1019    
1020                    // Check to see if Element or Document node
1021                    if ((type == ELEMENT_NODE) || (type == DOCUMENT_NODE) ||
1022                                    (type == ENTITY_REFERENCE_NODE)) {
1023    
1024                            // In case when Document root is given
1025                            //      if (nodeHandle == 0) nodeHandle = 1;
1026                            // %TBD% Probably was a mistake.
1027                            // If someone explicitly asks for first child
1028                            // of Document, I would expect them to want
1029                            // that and only that.
1030    
1031                            int kid = nodeHandle + 1;
1032                            nodes.readSlot(kid, gotslot);
1033                            while (ATTRIBUTE_NODE == (gotslot[0] & 0xFFFF)) {
1034                                    // points to next sibling
1035                                    kid = gotslot[2];
1036                                    // Return NULL if node has only attributes
1037                                    if (kid == NULL) return NULL;
1038                                    nodes.readSlot(kid, gotslot);
1039                            }
1040                            // If parent slot matches given parent, return kid
1041                            if (gotslot[1] == nodeHandle)
1042                            {
1043                              int firstChild = kid | m_docHandle;
1044    
1045                              return firstChild;
1046                            }
1047                    }
1048                    // No child found
1049    
1050                    return NULL;
1051            }
1052    
1053            /**
1054            * Given a node handle, advance to its last child.
1055            * If not yet resolved, waits for more nodes to be added to the document and
1056            * tries again.
1057            *
1058            * @param nodeHandle int Handle of the node.
1059            * @return int Node-number of last child,
1060            * or DTM.NULL to indicate none exists.
1061            */
1062            public int getLastChild(int nodeHandle) {
1063                    // ###shs put trace/debug later
1064                    nodeHandle &= NODEHANDLE_MASK;
1065                    // do not need to test node type since getFirstChild does that
1066                    int lastChild = NULL;
1067                    for (int nextkid = getFirstChild(nodeHandle); nextkid != NULL;
1068                                    nextkid = getNextSibling(nextkid)) {
1069                            lastChild = nextkid;
1070                    }
1071                    return lastChild | m_docHandle;
1072            }
1073    
1074            /**
1075             * Retrieves an attribute node by by qualified name and namespace URI.
1076             *
1077             * @param nodeHandle int Handle of the node upon which to look up this attribute.
1078             * @param namespaceURI The namespace URI of the attribute to
1079             *   retrieve, or null.
1080             * @param name The local name of the attribute to
1081             *   retrieve.
1082             * @return The attribute node handle with the specified name (
1083             *   <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
1084             *   attribute.
1085             */
1086            public int getAttributeNode(int nodeHandle, String namespaceURI, String name) {
1087                    int nsIndex = m_nsNames.stringToIndex(namespaceURI),
1088                                                                            nameIndex = m_localNames.stringToIndex(name);
1089                    nodeHandle &= NODEHANDLE_MASK;
1090                    nodes.readSlot(nodeHandle, gotslot);
1091                    short type = (short) (gotslot[0] & 0xFFFF);
1092                    // If nodeHandle points to element next slot would be first attribute
1093                    if (type == ELEMENT_NODE)
1094                            nodeHandle++;
1095                    // Iterate through Attribute Nodes
1096                    while (type == ATTRIBUTE_NODE) {
1097                            if ((nsIndex == (gotslot[0] << 16)) && (gotslot[3] == nameIndex))
1098                                    return nodeHandle | m_docHandle;
1099                            // Goto next sibling
1100                            nodeHandle = gotslot[2];
1101                            nodes.readSlot(nodeHandle, gotslot);
1102                    }
1103                    return NULL;
1104            }
1105    
1106            /**
1107             * Given a node handle, get the index of the node's first attribute.
1108             *
1109             * @param nodeHandle int Handle of the Element node.
1110             * @return Handle of first attribute, or DTM.NULL to indicate none exists.
1111             */
1112            public int getFirstAttribute(int nodeHandle) {
1113                    nodeHandle &= NODEHANDLE_MASK;
1114    
1115                    // %REVIEW% jjk: Just a quick observation: If you're going to
1116                    // call readEntry repeatedly on the same node, it may be
1117                    // more efficiently to do a readSlot to get the data locally,
1118                    // reducing the addressing and call-and-return overhead.
1119    
1120                    // Should we check if handle is element (do we want sanity checks?)
1121                    if (ELEMENT_NODE != (nodes.readEntry(nodeHandle, 0) & 0xFFFF))
1122                            return NULL;
1123                    // First Attribute (if any) should be at next position in table
1124                    nodeHandle++;
1125                    return(ATTRIBUTE_NODE == (nodes.readEntry(nodeHandle, 0) & 0xFFFF)) ?
1126                    nodeHandle | m_docHandle : NULL;
1127            }
1128    
1129            /**
1130             * Given a node handle, get the index of the node's first child.
1131             * If not yet resolved, waits for more nodes to be added to the document and
1132             * tries again
1133             *
1134             * @param nodeHandle handle to node, which should probably be an element
1135             *                   node, but need not be.
1136             *
1137             * @param inScope    true if all namespaces in scope should be returned,
1138             *                   false if only the namespace declarations should be
1139             *                   returned.
1140             * @return handle of first namespace, or DTM.NULL to indicate none exists.
1141             */
1142            public int getFirstNamespaceNode(int nodeHandle, boolean inScope) {
1143    
1144                    return NULL;
1145            }
1146    
1147            /**
1148             * Given a node handle, advance to its next sibling.
1149             *
1150             * %TBD% This currently uses the DTM-internal definition of
1151             * sibling; eg, the last attr's next sib is the first
1152             * child. In the old DTM, the DOM proxy layer provided the
1153             * additional logic for the public view.  If we're rewriting
1154             * for XPath emulation, that test must be done here.
1155             *
1156             * %TBD% CODE INTERACTION WITH INCREMENTAL PARSE - If not yet
1157             * resolved, should wait for more nodes to be added to the document
1158             * and tries again.
1159             *
1160             * @param nodeHandle int Handle of the node.
1161             * @return int Node-number of next sibling,
1162             * or DTM.NULL to indicate none exists.
1163             * */
1164            public int getNextSibling(int nodeHandle) {
1165                    nodeHandle &= NODEHANDLE_MASK;
1166                    // Document root has no next sibling
1167                    if (nodeHandle == 0)
1168                            return NULL;
1169    
1170                    short type = (short) (nodes.readEntry(nodeHandle, 0) & 0xFFFF);
1171                    if ((type == ELEMENT_NODE) || (type == ATTRIBUTE_NODE) ||
1172                                    (type == ENTITY_REFERENCE_NODE)) {
1173                            int nextSib = nodes.readEntry(nodeHandle, 2);
1174                            if (nextSib == NULL)
1175                                    return NULL;
1176                            if (nextSib != 0)
1177                                    return (m_docHandle | nextSib);
1178                            // ###shs should cycle/wait if nextSib is 0? Working on threading next
1179                    }
1180                    // Next Sibling is in the next position if it shares the same parent
1181                    int thisParent = nodes.readEntry(nodeHandle, 1);
1182    
1183                    if (nodes.readEntry(++nodeHandle, 1) == thisParent)
1184                            return (m_docHandle | nodeHandle);
1185    
1186                    return NULL;
1187            }
1188    
1189            /**
1190             * Given a node handle, find its preceeding sibling.
1191             * WARNING: DTM is asymmetric; this operation is resolved by search, and is
1192             * relatively expensive.
1193             *
1194             * @param nodeHandle the id of the node.
1195             * @return int Node-number of the previous sib,
1196             * or DTM.NULL to indicate none exists.
1197             */
1198            public int getPreviousSibling(int nodeHandle) {
1199                    nodeHandle &= NODEHANDLE_MASK;
1200                    // Document root has no previous sibling
1201                    if (nodeHandle == 0)
1202                            return NULL;
1203    
1204                    int parent = nodes.readEntry(nodeHandle, 1);
1205                    int kid = NULL;
1206                    for (int nextkid = getFirstChild(parent); nextkid != nodeHandle;
1207                                    nextkid = getNextSibling(nextkid)) {
1208                            kid = nextkid;
1209                    }
1210                    return kid | m_docHandle;
1211            }
1212    
1213            /**
1214             * Given a node handle, advance to the next attribute. If an
1215             * element, we advance to its first attribute; if an attr, we advance to
1216             * the next attr on the same node.
1217             *
1218             * @param nodeHandle int Handle of the node.
1219             * @return int DTM node-number of the resolved attr,
1220             * or DTM.NULL to indicate none exists.
1221             */
1222            public int getNextAttribute(int nodeHandle) {
1223                    nodeHandle &= NODEHANDLE_MASK;
1224                    nodes.readSlot(nodeHandle, gotslot);
1225    
1226                    //%REVIEW% Why are we using short here? There's no storage
1227                    //reduction for an automatic variable, especially one used
1228                    //so briefly, and it typically costs more cycles to process
1229                    //than an int would.
1230                    short type = (short) (gotslot[0] & 0xFFFF);
1231    
1232                    if (type == ELEMENT_NODE) {
1233                            return getFirstAttribute(nodeHandle);
1234                    } else if (type == ATTRIBUTE_NODE) {
1235                            if (gotslot[2] != NULL)
1236                                    return (m_docHandle | gotslot[2]);
1237                    }
1238                    return NULL;
1239            }
1240    
1241            /**
1242             * Given a namespace handle, advance to the next namespace.
1243             *
1244             * %TBD% THIS METHOD DOES NOT MATCH THE CURRENT SIGNATURE IN
1245             * THE DTM INTERFACE.  FIX IT, OR JUSTIFY CHANGING THE DTM
1246             * API.
1247             *
1248             * @param namespaceHandle handle to node which must be of type NAMESPACE_NODE.
1249             * @return handle of next namespace, or DTM.NULL to indicate none exists.
1250             */
1251            public int getNextNamespaceNode(int baseHandle,int namespaceHandle, boolean inScope) {
1252                    // ###shs need to work on namespace
1253                    return NULL;
1254            }
1255    
1256            /**
1257             * Given a node handle, advance to its next descendant.
1258             * If not yet resolved, waits for more nodes to be added to the document and
1259             * tries again.
1260             *
1261             * @param subtreeRootHandle
1262             * @param nodeHandle int Handle of the node.
1263             * @return handle of next descendant,
1264             * or DTM.NULL to indicate none exists.
1265             */
1266            public int getNextDescendant(int subtreeRootHandle, int nodeHandle) {
1267                    subtreeRootHandle &= NODEHANDLE_MASK;
1268                    nodeHandle &= NODEHANDLE_MASK;
1269                    // Document root [Document Node? -- jjk] - no next-sib
1270                    if (nodeHandle == 0)
1271                            return NULL;
1272                    while (!m_isError) {
1273                            // Document done and node out of bounds
1274                            if (done && (nodeHandle > nodes.slotsUsed()))
1275                                    break;
1276                            if (nodeHandle > subtreeRootHandle) {
1277                                    nodes.readSlot(nodeHandle+1, gotslot);
1278                                    if (gotslot[2] != 0) {
1279                                            short type = (short) (gotslot[0] & 0xFFFF);
1280                                            if (type == ATTRIBUTE_NODE) {
1281                                                    nodeHandle +=2;
1282                                            } else {
1283                                                    int nextParentPos = gotslot[1];
1284                                                    if (nextParentPos >= subtreeRootHandle)
1285                                                            return (m_docHandle | (nodeHandle+1));
1286                                                    else
1287                                                            break;
1288                                            }
1289                                    } else if (!done) {
1290                                            // Add wait logic here
1291                                    } else
1292                                            break;
1293                            } else {
1294                                    nodeHandle++;
1295                            }
1296                    }
1297                    // Probably should throw error here like original instead of returning
1298                    return NULL;
1299            }
1300    
1301            /**
1302             * Given a node handle, advance to the next node on the following axis.
1303             *
1304             * @param axisContextHandle the start of the axis that is being traversed.
1305             * @param nodeHandle
1306             * @return handle of next sibling,
1307             * or DTM.NULL to indicate none exists.
1308             */
1309            public int getNextFollowing(int axisContextHandle, int nodeHandle) {
1310                    //###shs still working on
1311                    return NULL;
1312            }
1313    
1314            /**
1315             * Given a node handle, advance to the next node on the preceding axis.
1316             *
1317             * @param axisContextHandle the start of the axis that is being traversed.
1318             * @param nodeHandle the id of the node.
1319             * @return int Node-number of preceding sibling,
1320             * or DTM.NULL to indicate none exists.
1321             */
1322            public int getNextPreceding(int axisContextHandle, int nodeHandle) {
1323                    // ###shs copied from Xalan 1, what is this suppose to do?
1324                    nodeHandle &= NODEHANDLE_MASK;
1325                    while (nodeHandle > 1) {
1326                            nodeHandle--;
1327                            if (ATTRIBUTE_NODE == (nodes.readEntry(nodeHandle, 0) & 0xFFFF))
1328                                    continue;
1329    
1330                            // if nodeHandle is _not_ an ancestor of
1331                            // axisContextHandle, specialFind will return it.
1332                            // If it _is_ an ancestor, specialFind will return -1
1333    
1334                            // %REVIEW% unconditional return defeats the
1335                            // purpose of the while loop -- does this
1336                            // logic make any sense?
1337    
1338                            return (m_docHandle | nodes.specialFind(axisContextHandle, nodeHandle));
1339                    }
1340                    return NULL;
1341            }
1342    
1343            /**
1344             * Given a node handle, find its parent node.
1345             *
1346             * @param nodeHandle the id of the node.
1347             * @return int Node-number of parent,
1348             * or DTM.NULL to indicate none exists.
1349             */
1350            public int getParent(int nodeHandle) {
1351                    // Should check to see within range?
1352    
1353                    // Document Root should not have to be handled differently
1354                    return (m_docHandle | nodes.readEntry(nodeHandle, 1));
1355            }
1356    
1357            /**
1358             * Returns the root element of the document.
1359             * @return nodeHandle to the Document Root.
1360             */
1361            public int getDocumentRoot() {
1362                    return (m_docHandle | m_docElement);
1363            }
1364    
1365            /**
1366             * Given a node handle, find the owning document node.
1367             *
1368             * @return int Node handle of document, which should always be valid.
1369             */
1370            public int getDocument() {
1371                    return m_docHandle;
1372            }
1373    
1374            /**
1375             * Given a node handle, find the owning document node.  This has the exact
1376             * same semantics as the DOM Document method of the same name, in that if
1377             * the nodeHandle is a document node, it will return NULL.
1378             *
1379             * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
1380             * binding layer. Included here as a convenience function and to
1381             * aid porting of DOM code to DTM.</p>
1382             *
1383             * @param nodeHandle the id of the node.
1384             * @return int Node handle of owning document, or NULL if the nodeHandle is
1385             *             a document.
1386             */
1387            public int getOwnerDocument(int nodeHandle) {
1388                    // Assumption that Document Node is always in 0 slot
1389                    if ((nodeHandle & NODEHANDLE_MASK) == 0)
1390                            return NULL;
1391                    return (nodeHandle & DOCHANDLE_MASK);
1392            }
1393    
1394            /**
1395             * Given a node handle, find the owning document node.  This has the DTM
1396             * semantics; a Document node is its own owner.
1397             *
1398             * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
1399             * binding layer. Included here as a convenience function and to
1400             * aid porting of DOM code to DTM.</p>
1401             *
1402             * @param nodeHandle the id of the node.
1403             * @return int Node handle of owning document, or NULL if the nodeHandle is
1404             *             a document.
1405             */
1406            public int getDocumentRoot(int nodeHandle) {
1407                    // Assumption that Document Node is always in 0 slot
1408                    if ((nodeHandle & NODEHANDLE_MASK) == 0)
1409                            return NULL;
1410                    return (nodeHandle & DOCHANDLE_MASK);
1411            }
1412    
1413            /**
1414             * Get the string-value of a node as a String object
1415             * (see http://www.w3.org/TR/xpath#data-model
1416             * for the definition of a node's string-value).
1417             *
1418             * @param nodeHandle The node ID.
1419             *
1420             * @return A string object that represents the string-value of the given node.
1421             */
1422            public XMLString getStringValue(int nodeHandle) {
1423            // ###zaj - researching
1424            nodes.readSlot(nodeHandle, gotslot);
1425            int nodetype=gotslot[0] & 0xFF;
1426            String value=null;
1427    
1428            switch (nodetype) {
1429            case TEXT_NODE:
1430            case COMMENT_NODE:
1431            case CDATA_SECTION_NODE:
1432                    value= m_char.getString(gotslot[2], gotslot[3]);
1433                    break;
1434            case PROCESSING_INSTRUCTION_NODE:
1435            case ATTRIBUTE_NODE:
1436            case ELEMENT_NODE:
1437            case ENTITY_REFERENCE_NODE:
1438            default:
1439                    break;
1440            }
1441            return m_xsf.newstr( value );
1442    
1443            }
1444    
1445            /**
1446             * Get number of character array chunks in
1447             * 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 the
1453             * 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 tells us how many
1457             * separate accesses will be required to retrieve the entire
1458             * content. PLEASE NOTE that this may not be the same as the
1459             * number of SAX characters() events that caused the text node
1460             * to be built in the first place, since m_chars buffering may
1461             * be on different boundaries than the parser's buffers.
1462             *
1463             * @param nodeHandle The node ID.
1464             *
1465             * @return number of character array chunks in
1466             *         the string-value of a node.
1467             * */
1468            //###zaj - tbd
1469            public int getStringValueChunkCount(int nodeHandle)
1470            {
1471                    //###zaj    return value
1472                    return 0;
1473            }
1474    
1475            /**
1476             * Get a character array chunk in the string-value of a node.
1477             * (see http://www.w3.org/TR/xpath#data-model
1478             * for the definition of a node's string-value).
1479             * Note that a single text node may have multiple text chunks.
1480             *
1481             * EXPLANATION: This method is an artifact of the fact that
1482             * the underlying m_chars object may not store characters in a
1483             * single contiguous array -- for example,the current
1484             * FastStringBuffer may split a single node's text across
1485             * multiple allocation units.  This call retrieves a single
1486             * contiguous portion of the text -- as much as m-chars was
1487             * able to store in a single allocation unit.  PLEASE NOTE
1488             * that this may not be the same granularityas the SAX
1489             * characters() events that caused the text node to be built
1490             * in the first place, since m_chars buffering may be on
1491             * different boundaries than the parser's buffers.
1492             *
1493             * @param nodeHandle The node ID.
1494             * @param chunkIndex Which chunk to get.
1495             * @param startAndLen An array of 2 where the start position and length of
1496             *                    the chunk will be returned.
1497             *
1498             * @return The character array reference where the chunk occurs.  */
1499            //###zaj - tbd
1500            public char[] getStringValueChunk(int nodeHandle, int chunkIndex,
1501                                                                                                                                                    int[] startAndLen) {return new char[0];}
1502    
1503            /**
1504             * Given a node handle, return an ID that represents the node's expanded name.
1505             *
1506             * @param nodeHandle The handle to the node in question.
1507             *
1508             * @return the expanded-name id of the node.
1509             */
1510            public int getExpandedTypeID(int nodeHandle) {
1511               nodes.readSlot(nodeHandle, gotslot);
1512               String qName = m_localNames.indexToString(gotslot[3]);
1513               // Remove prefix from qName
1514               // %TBD% jjk This is assuming the elementName is the qName.
1515               int colonpos = qName.indexOf(":");
1516               String localName = qName.substring(colonpos+1);
1517               // Get NS
1518               String namespace = m_nsNames.indexToString(gotslot[0] << 16);
1519               // Create expanded name
1520               String expandedName = namespace + ":" + localName;
1521               int expandedNameID = m_nsNames.stringToIndex(expandedName);
1522    
1523            return expandedNameID;
1524            }
1525    
1526    
1527            /**
1528             * Given an expanded name, return an ID.  If the expanded-name does not
1529             * exist in the internal tables, the entry will be created, and the ID will
1530             * be returned.  Any additional nodes that are created that have this
1531             * expanded name will use this ID.
1532             *
1533             * @return the expanded-name id of the node.
1534             */
1535            public int getExpandedTypeID(String namespace, String localName, int type) {
1536               // Create expanded name
1537              // %TBD% jjk Expanded name is bitfield-encoded as
1538              // typeID[6]nsuriID[10]localID[16]. Switch to that form, and to
1539              // accessing the ns/local via their tables rather than confusing
1540              // nsnames and expandednames.
1541               String expandedName = namespace + ":" + localName;
1542               int expandedNameID = m_nsNames.stringToIndex(expandedName);
1543    
1544               return expandedNameID;
1545            }
1546    
1547    
1548            /**
1549             * Given an expanded-name ID, return the local name part.
1550             *
1551             * @param ExpandedNameID an ID that represents an expanded-name.
1552             * @return String Local name of this node.
1553             */
1554            public String getLocalNameFromExpandedNameID(int ExpandedNameID) {
1555    
1556               // Get expanded name
1557               String expandedName = m_localNames.indexToString(ExpandedNameID);
1558               // Remove prefix from expanded name
1559               int colonpos = expandedName.indexOf(":");
1560               String localName = expandedName.substring(colonpos+1);
1561               return localName;
1562            }
1563    
1564    
1565            /**
1566             * Given an expanded-name ID, return the namespace URI part.
1567             *
1568             * @param ExpandedNameID an ID that represents an expanded-name.
1569             * @return String URI value of this node's namespace, or null if no
1570             * namespace was resolved.
1571            */
1572            public String getNamespaceFromExpandedNameID(int ExpandedNameID) {
1573    
1574               String expandedName = m_localNames.indexToString(ExpandedNameID);
1575               // Remove local name from expanded name
1576               int colonpos = expandedName.indexOf(":");
1577               String nsName = expandedName.substring(0, colonpos);
1578    
1579            return nsName;
1580            }
1581    
1582    
1583            /**
1584             * fixednames
1585            */
1586            private static final String[] fixednames=
1587            {
1588                    null,null,                                                      // nothing, Element
1589                    null,"#text",                                           // Attr, Text
1590                    "#cdata_section",null,  // CDATA, EntityReference
1591                    null,null,                                                      // Entity, PI
1592                    "#comment","#document", // Comment, Document
1593                    null,"#document-fragment", // Doctype, DocumentFragment
1594                    null};                                                                  // Notation
1595    
1596            /**
1597             * Given a node handle, return its DOM-style node name. This will
1598             * include names such as #text or #document.
1599             *
1600             * @param nodeHandle the id of the node.
1601             * @return String Name of this node, which may be an empty string.
1602             * %REVIEW% Document when empty string is possible...
1603             */
1604            public String getNodeName(int nodeHandle) {
1605                    nodes.readSlot(nodeHandle, gotslot);
1606                    short type = (short) (gotslot[0] & 0xFFFF);
1607                    String name = fixednames[type];
1608                    if (null == name) {
1609                      int i=gotslot[3];
1610                      /**/System.out.println("got i="+i+" "+(i>>16)+"/"+(i&0xffff));
1611    
1612                      name=m_localNames.indexToString(i & 0xFFFF);
1613                      String prefix=m_prefixNames.indexToString(i >>16);
1614                      if(prefix!=null && prefix.length()>0)
1615                        name=prefix+":"+name;
1616                    }
1617                    return name;
1618            }
1619    
1620            /**
1621             * Given a node handle, return the XPath node name.  This should be
1622             * the name as described by the XPath data model, NOT the DOM-style
1623             * name.
1624             *
1625             * @param nodeHandle the id of the node.
1626             * @return String Name of this node.
1627             */
1628            public String getNodeNameX(int nodeHandle) {return null;}
1629    
1630            /**
1631             * Given a node handle, return its DOM-style localname.
1632             * (As defined in Namespaces, this is the portion of the name after any
1633             * colon character)
1634             *
1635             * %REVIEW% What's the local name of something other than Element/Attr?
1636             * Should this be DOM-style (undefined unless namespaced), or other?
1637             *
1638             * @param nodeHandle the id of the node.
1639             * @return String Local name of this node.
1640             */
1641            public String getLocalName(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_localNames.indexToString(i & 0xFFFF);
1648                      if(name==null) name="";
1649                    }
1650                    return name;
1651            }
1652    
1653            /**
1654             * Given a namespace handle, return the prefix that the namespace decl is
1655             * mapping.
1656             * Given a node handle, return the prefix used to map to the namespace.
1657             *
1658             * <p> %REVIEW% Are you sure you want "" for no prefix?  </p>
1659             *
1660             * %REVIEW%  Should this be DOM-style (undefined unless namespaced),
1661             * or other?
1662             *
1663             * @param nodeHandle the id of the node.
1664             * @return String prefix of this node's name, or "" if no explicit
1665             * namespace prefix was given.
1666             */
1667            public String getPrefix(int nodeHandle) {
1668                    nodes.readSlot(nodeHandle, gotslot);
1669                    short type = (short) (gotslot[0] & 0xFFFF);
1670                    String name = "";
1671                    if((type==ELEMENT_NODE) || (type==ATTRIBUTE_NODE)) {
1672                      int i=gotslot[3];
1673                      name=m_prefixNames.indexToString(i >>16);
1674                      if(name==null) name="";
1675                    }
1676                    return name;
1677            }
1678    
1679            /**
1680             * Given a node handle, return its DOM-style namespace URI
1681             * (As defined in Namespaces, this is the declared URI which this node's
1682             * prefix -- or default in lieu thereof -- was mapped to.)
1683             *
1684             * @param nodeHandle the id of the node.
1685             * @return String URI value of this node's namespace, or null if no
1686             * namespace was resolved.
1687             */
1688            public String getNamespaceURI(int nodeHandle) {return null;}
1689    
1690            /**
1691             * Given a node handle, return its node value. This is mostly
1692             * as defined by the DOM, but may ignore some conveniences.
1693             * <p>
1694             *
1695             * @param nodeHandle The node id.
1696             * @return String Value of this node, or null if not
1697             * meaningful for this node type.
1698             */
1699            public String getNodeValue(int nodeHandle)
1700            {
1701                    nodes.readSlot(nodeHandle, gotslot);
1702                    int nodetype=gotslot[0] & 0xFF;             // ###zaj use mask to get node type
1703                    String value=null;
1704    
1705                    switch (nodetype) {                     // ###zaj todo - document nodetypes
1706                    case ATTRIBUTE_NODE:
1707                            nodes.readSlot(nodeHandle+1, gotslot);
1708                    case TEXT_NODE:
1709                    case COMMENT_NODE:
1710                    case CDATA_SECTION_NODE:
1711                            value=m_char.getString(gotslot[2], gotslot[3]);         //###zaj
1712                            break;
1713                    case PROCESSING_INSTRUCTION_NODE:
1714                    case ELEMENT_NODE:
1715                    case ENTITY_REFERENCE_NODE:
1716                    default:
1717                            break;
1718                    }
1719                    return value;
1720            }
1721    
1722            /**
1723             * Given a node handle, return its DOM-style node type.
1724             * <p>
1725             * %REVIEW% Generally, returning short is false economy. Return int?
1726             *
1727             * @param nodeHandle The node id.
1728             * @return int Node type, as per the DOM's Node._NODE constants.
1729             */
1730            public short getNodeType(int nodeHandle) {
1731                    return(short) (nodes.readEntry(nodeHandle, 0) & 0xFFFF);
1732            }
1733    
1734            /**
1735             * Get the depth level of this node in the tree (equals 1 for
1736             * a parentless node).
1737             *
1738             * @param nodeHandle The node id.
1739             * @return the number of ancestors, plus one
1740             * @xsl.usage internal
1741             */
1742            public short getLevel(int nodeHandle) {
1743                    short count = 0;
1744                    while (nodeHandle != 0) {
1745                            count++;
1746                            nodeHandle = nodes.readEntry(nodeHandle, 1);
1747                    }
1748                    return count;
1749            }
1750    
1751            // ============== Document query functions ==============
1752    
1753            /**
1754             * Tests whether DTM DOM implementation implements a specific feature and
1755             * that feature is supported by this node.
1756             *
1757             * @param feature The name of the feature to test.
1758             * @param version This is the version number of the feature to test.
1759             *   If the version is not
1760             *   specified, supporting any version of the feature will cause the
1761             *   method to return <code>true</code>.
1762             * @return Returns <code>true</code> if the specified feature is
1763             *   supported on this node, <code>false</code> otherwise.
1764             */
1765            public boolean isSupported(String feature, String version) {return false;}
1766    
1767            /**
1768             * Return the base URI of the document entity. If it is not known
1769             * (because the document was parsed from a socket connection or from
1770             * standard input, for example), the value of this property is unknown.
1771             *
1772             * @return the document base URI String object or null if unknown.
1773             */
1774            public String getDocumentBaseURI()
1775            {
1776    
1777              return m_documentBaseURI;
1778            }
1779    
1780            /**
1781             * Set the base URI of the document entity.
1782             *
1783             * @param baseURI the document base URI String object or null if unknown.
1784             */
1785            public void setDocumentBaseURI(String baseURI)
1786            {
1787    
1788              m_documentBaseURI = baseURI;
1789            }
1790    
1791            /**
1792             * Return the system identifier of the document entity. If
1793             * it is not known, the value of this property is unknown.
1794             *
1795             * @param nodeHandle The node id, which can be any valid node handle.
1796             * @return the system identifier String object or null if unknown.
1797             */
1798            public String getDocumentSystemIdentifier(int nodeHandle) {return null;}
1799    
1800            /**
1801             * Return the name of the character encoding scheme
1802             *        in which the document entity is expressed.
1803             *
1804             * @param nodeHandle The node id, which can be any valid node handle.
1805             * @return the document encoding String object.
1806             */
1807            public String getDocumentEncoding(int nodeHandle) {return null;}
1808    
1809            /**
1810             * Return an indication of the standalone status of the document,
1811             *        either "yes" or "no". This property is derived from the optional
1812             *        standalone document declaration in the XML declaration at the
1813             *        beginning of the document entity, and has no value if there is no
1814             *        standalone document declaration.
1815             *
1816             * @param nodeHandle The node id, which can be any valid node handle.
1817             * @return the document standalone String object, either "yes", "no", or null.
1818             */
1819            public String getDocumentStandalone(int nodeHandle) {return null;}
1820    
1821            /**
1822             * Return a string representing the XML version of the document. This
1823             * property is derived from the XML declaration optionally present at the
1824             * beginning of the document entity, and has no value if there is no XML
1825             * declaration.
1826             *
1827             * @param documentHandle the document handle
1828             *
1829             * @return the document version String object
1830             */
1831            public String getDocumentVersion(int documentHandle) {return null;}
1832    
1833            /**
1834             * Return an indication of
1835             * whether the processor has read the complete DTD. Its value is a
1836             * boolean. If it is false, then certain properties (indicated in their
1837             * descriptions below) may be unknown. If it is true, those properties
1838             * are never unknown.
1839             *
1840             * @return <code>true</code> if all declarations were processed {};
1841             *         <code>false</code> otherwise.
1842             */
1843            public boolean getDocumentAllDeclarationsProcessed() {return false;}
1844    
1845            /**
1846             *   A document type declaration information item has the following properties:
1847             *
1848             *     1. [system identifier] The system identifier of the external subset, if
1849             *        it exists. Otherwise this property has no value.
1850             *
1851             * @return the system identifier String object, or null if there is none.
1852             */
1853            public String getDocumentTypeDeclarationSystemIdentifier() {return null;}
1854    
1855            /**
1856             * Return the public identifier of the external subset,
1857             * normalized as described in 4.2.2 External Entities [XML]. If there is
1858             * no external subset or if it has no public identifier, this property
1859             * has no value.
1860             *
1861             * @return the public identifier String object, or null if there is none.
1862             */
1863            public String getDocumentTypeDeclarationPublicIdentifier() {return null;}
1864    
1865            /**
1866             * Returns the <code>Element</code> whose <code>ID</code> is given by
1867             * <code>elementId</code>. If no such element exists, returns
1868             * <code>DTM.NULL</code>. Behavior is not defined if more than one element
1869             * has this <code>ID</code>. Attributes (including those
1870             * with the name "ID") are not of type ID unless so defined by DTD/Schema
1871             * information available to the DTM implementation.
1872             * Implementations that do not know whether attributes are of type ID or
1873             * not are expected to return <code>DTM.NULL</code>.
1874             *
1875             * <p>%REVIEW% Presumably IDs are still scoped to a single document,
1876             * and this operation searches only within a single document, right?
1877             * Wouldn't want collisions between DTMs in the same process.</p>
1878             *
1879             * @param elementId The unique <code>id</code> value for an element.
1880             * @return The handle of the matching element.
1881             */
1882            public int getElementById(String elementId) {return 0;}
1883    
1884            /**
1885             * The getUnparsedEntityURI function returns the URI of the unparsed
1886             * entity with the specified name in the same document as the context
1887             * node (see [3.3 Unparsed Entities]). It returns the empty string if
1888             * there is no such entity.
1889             * <p>
1890             * XML processors may choose to use the System Identifier (if one
1891             * is provided) to resolve the entity, rather than the URI in the
1892             * Public Identifier. The details are dependent on the processor, and
1893             * we would have to support some form of plug-in resolver to handle
1894             * this properly. Currently, we simply return the System Identifier if
1895             * present, and hope that it a usable URI or that our caller can
1896             * map it to one.
1897             * TODO: Resolve Public Identifiers... or consider changing function name.
1898             * <p>
1899             * If we find a relative URI
1900             * reference, XML expects it to be resolved in terms of the base URI
1901             * of the document. The DOM doesn't do that for us, and it isn't
1902             * entirely clear whether that should be done here; currently that's
1903             * pushed up to a higher level of our application. (Note that DOM Level
1904             * 1 didn't store the document's base URI.)
1905             * TODO: Consider resolving Relative URIs.
1906             * <p>
1907             * (The DOM's statement that "An XML processor may choose to
1908             * completely expand entities before the structure model is passed
1909             * to the DOM" refers only to parsed entities, not unparsed, and hence
1910             * doesn't affect this function.)
1911             *
1912             * @param name A string containing the Entity Name of the unparsed
1913             * entity.
1914             *
1915             * @return String containing the URI of the Unparsed Entity, or an
1916             * empty string if no such entity exists.
1917             */
1918            public String getUnparsedEntityURI(String name) {return null;}
1919    
1920    
1921            // ============== Boolean methods ================
1922    
1923            /**
1924             * Return true if the xsl:strip-space or xsl:preserve-space was processed
1925             * during construction of the DTM document.
1926             *
1927             * <p>%REVEIW% Presumes a 1:1 mapping from DTM to Document, since
1928             * we aren't saying which Document to query...?</p>
1929             */
1930            public boolean supportsPreStripping() {return false;}
1931    
1932            /**
1933             * Figure out whether nodeHandle2 should be considered as being later
1934             * in the document than nodeHandle1, in Document Order as defined
1935             * by the XPath model. This may not agree with the ordering defined
1936             * by other XML applications.
1937             * <p>
1938             * There are some cases where ordering isn't defined, and neither are
1939             * the results of this function -- though we'll generally return true.
1940             *
1941             * TODO: Make sure this does the right thing with attribute nodes!!!
1942             *
1943             * @param nodeHandle1 DOM Node to perform position comparison on.
1944             * @param nodeHandle2 DOM Node to perform position comparison on .
1945             *
1946             * @return false if node2 comes before node1, otherwise return true.
1947             * You can think of this as
1948             * <code>(node1.documentOrderPosition &lt;= node2.documentOrderPosition)</code>.
1949             */
1950            public boolean isNodeAfter(int nodeHandle1, int nodeHandle2) {return false;}
1951    
1952            /**
1953             *     2. [element content whitespace] A boolean indicating whether the
1954             *        character is white space appearing within element content (see [XML],
1955             *        2.10 "White Space Handling"). Note that validating XML processors are
1956             *        required by XML 1.0 to provide this information. If there is no
1957             *        declaration for the containing element, this property has no value for
1958             *        white space characters. If no declaration has been read, but the [all
1959             *        declarations processed] property of the document information item is
1960             *        false (so there may be an unread declaration), then the value of this
1961             *        property is unknown for white space characters. It is always false for
1962             *        characters that are not white space.
1963             *
1964             * @param nodeHandle the node ID.
1965             * @return <code>true</code> if the character data is whitespace;
1966             *         <code>false</code> otherwise.
1967             */
1968            public boolean isCharacterElementContentWhitespace(int nodeHandle) {return false;}
1969    
1970            /**
1971             *    10. [all declarations processed] This property is not strictly speaking
1972             *        part of the infoset of the document. Rather it is an indication of
1973             *        whether the processor has read the complete DTD. Its value is a
1974             *        boolean. If it is false, then certain properties (indicated in their
1975             *        descriptions below) may be unknown. If it is true, those properties
1976             *        are never unknown.
1977             *
1978             * @param documentHandle A node handle that must identify a document.
1979             * @return <code>true</code> if all declarations were processed;
1980             *         <code>false</code> otherwise.
1981             */
1982            public boolean isDocumentAllDeclarationsProcessed(int documentHandle) {return false;}
1983    
1984            /**
1985             *     5. [specified] A flag indicating whether this attribute was actually
1986             *        specified in the start-tag of its element, or was defaulted from the
1987             *        DTD.
1988             *
1989             * @param attributeHandle the attribute handle
1990             * @return <code>true</code> if the attribute was specified;
1991             *         <code>false</code> if it was defaulted.
1992             */
1993            public boolean isAttributeSpecified(int attributeHandle) {return false;}
1994    
1995            // ========== Direct SAX Dispatch, for optimization purposes ========
1996    
1997            /**
1998             * Directly call the
1999             * characters method on the passed ContentHandler for the
2000             * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
2001             * for the definition of a node's string-value). Multiple calls to the
2002             * ContentHandler's characters methods may well occur for a single call to
2003             * this method.
2004             *
2005             * @param nodeHandle The node ID.
2006             * @param ch A non-null reference to a ContentHandler.
2007             *
2008             * @throws org.xml.sax.SAXException
2009             */
2010            public void dispatchCharactersEvents(
2011                                                                                                                                                            int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize)
2012            throws org.xml.sax.SAXException {}
2013    
2014            /**
2015             * Directly create SAX parser events from a subtree.
2016             *
2017             * @param nodeHandle The node ID.
2018             * @param ch A non-null reference to a ContentHandler.
2019             *
2020             * @throws org.xml.sax.SAXException
2021             */
2022    
2023            public void dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler ch)
2024            throws org.xml.sax.SAXException {}
2025    
2026            /**
2027             * Return an DOM node for the given node.
2028             *
2029             * @param nodeHandle The node ID.
2030             *
2031             * @return A node representation of the DTM node.
2032             */
2033            public org.w3c.dom.Node getNode(int nodeHandle)
2034            {
2035              return null;
2036            }
2037    
2038            // ==== Construction methods (may not be supported by some implementations!) =====
2039            // %REVIEW% jjk: These probably aren't the right API. At the very least
2040            // they need to deal with current-insertion-location and end-element
2041            // issues.
2042    
2043            /**
2044             * Append a child to the end of the child list of the current node. Please note that the node
2045             * is always cloned if it is owned by another document.
2046             *
2047             * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2048             * Does it become the last child of the Document? Of the root element?</p>
2049             *
2050             * @param newChild Must be a valid new node handle.
2051             * @param clone true if the child should be cloned into the document.
2052             * @param cloneDepth if the clone argument is true, specifies that the
2053             *                   clone should include all it's children.
2054             */
2055            public void appendChild(int newChild, boolean clone, boolean cloneDepth) {
2056                    boolean sameDoc = ((newChild & DOCHANDLE_MASK) == m_docHandle);
2057                    if (clone || !sameDoc) {
2058    
2059                    } else {
2060    
2061                    }
2062            }
2063    
2064            /**
2065             * Append a text node child that will be constructed from a string,
2066             * to the end of the document.
2067             *
2068             * <p>%REVIEW% "End of the document" needs to be defined more clearly.
2069             * Does it become the last child of the Document? Of the root element?</p>
2070             *
2071             * @param str Non-null reference to a string.
2072             */
2073            public void appendTextChild(String str) {
2074                    // ###shs Think more about how this differs from createTextNode
2075              //%TBD%
2076            }
2077    
2078    
2079      //================================================================
2080      // ==== BUILDER methods ====
2081      // %TBD% jjk: SHOULD PROBABLY BE INLINED, unless we want to support
2082      // both SAX1 and SAX2 and share this logic between them.
2083    
2084      /** Append a text child at the current insertion point. Assumes that the
2085       * actual content of the text has previously been appended to the m_char
2086       * buffer (shared with the builder).
2087       *
2088       * @param m_char_current_start int Starting offset of node's content in m_char.
2089       * @param contentLength int Length of node's content in m_char.
2090       * */
2091      void appendTextChild(int m_char_current_start,int contentLength)
2092      {
2093        // create a Text Node
2094        // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
2095        int w0 = TEXT_NODE;
2096        // W1: Parent
2097        int w1 = currentParent;
2098        // W2: Start position within m_char
2099        int w2 = m_char_current_start;
2100        // W3: Length of the full string
2101        int w3 = contentLength;
2102    
2103        int ourslot = appendNode(w0, w1, w2, w3);
2104        previousSibling = ourslot;
2105      }
2106    
2107      /** Append a comment child at the current insertion point. Assumes that the
2108       * actual content of the comment has previously been appended to the m_char
2109       * buffer (shared with the builder).
2110       *
2111       * @param m_char_current_start int Starting offset of node's content in m_char.
2112       * @param contentLength int Length of node's content in m_char.
2113       * */
2114      void appendComment(int m_char_current_start,int contentLength)
2115      {
2116        // create a Comment Node
2117        // %TBD% may be possible to combine with appendNode()to replace the next chunk of code
2118        int w0 = COMMENT_NODE;
2119        // W1: Parent
2120        int w1 = currentParent;
2121        // W2: Start position within m_char
2122        int w2 = m_char_current_start;
2123        // W3: Length of the full string
2124        int w3 = contentLength;
2125    
2126        int ourslot = appendNode(w0, w1, w2, w3);
2127        previousSibling = ourslot;
2128      }
2129    
2130    
2131      /** Append an Element child at the current insertion point. This
2132       * Element then _becomes_ the insertion point; subsequent appends
2133       * become its lastChild until an appendEndElement() call is made.
2134       *
2135       * Assumes that the symbols (local name, namespace URI and prefix)
2136       * have already been added to the pools
2137       *
2138       * Note that this _only_ handles the Element node itself. Attrs and
2139       * namespace nodes are unbundled in the ContentHandler layer
2140       * and appended separately.
2141       *
2142       * @param namespaceIndex: Index within the namespaceURI string pool
2143       * @param localNameIndex Index within the local name string pool
2144       * @param prefixIndex: Index within the prefix string pool
2145       * */
2146      void appendStartElement(int namespaceIndex,int localNameIndex, int prefixIndex)
2147      {
2148                    // do document root node creation here on the first element, create nodes for
2149                    // this element and its attributes, store the element, namespace, and attritute
2150                    // name indexes to the nodes array, keep track of the current node and parent
2151                    // element used
2152    
2153                    // W0  High:  Namespace  Low:  Node Type
2154                    int w0 = (namespaceIndex << 16) | ELEMENT_NODE;
2155                    // W1: Parent
2156                    int w1 = currentParent;
2157                    // W2: Next  (initialized as 0)
2158                    int w2 = 0;
2159                    // W3: Tagname high: prefix Low: local name
2160                    int w3 = localNameIndex | prefixIndex<<16;
2161                    /**/System.out.println("set w3="+w3+" "+(w3>>16)+"/"+(w3&0xffff));
2162    
2163                    //int ourslot = nodes.appendSlot(w0, w1, w2, w3);
2164                    int ourslot = appendNode(w0, w1, w2, w3);
2165                    currentParent = ourslot;
2166                    previousSibling = 0;
2167    
2168                    // set the root element pointer when creating the first element node
2169                    if (m_docElement == NULL)
2170                            m_docElement = ourslot;
2171      }
2172    
2173      /** Append a Namespace Declaration child at the current insertion point.
2174       * Assumes that the symbols (namespace URI and prefix) have already been
2175       * added to the pools
2176       *
2177       * @param prefixIndex: Index within the prefix string pool
2178       * @param namespaceIndex: Index within the namespaceURI string pool
2179       * @param isID: If someone really insists on writing a bad DTD, it is
2180       * theoretically possible for a namespace declaration to also be declared
2181       * as being a node ID. I don't really want to support that stupidity,
2182       * but I'm not sure we can refuse to accept it.
2183       * */
2184      void appendNSDeclaration(int prefixIndex, int namespaceIndex,
2185                               boolean isID)
2186      {
2187        // %REVIEW% I'm assigning this node the "namespace for namespaces"
2188        // which the DOM defined. It is expected that the Namespace spec will
2189        // adopt this as official. It isn't strictly needed since it's implied
2190        // by the nodetype, but for now...
2191    
2192        // %REVIEW% Prefix need not be recorded; it's implied too. But
2193        // recording it might simplify the design.
2194    
2195        // %TBD% isID is not currently honored.
2196    
2197        final int namespaceForNamespaces=m_nsNames.stringToIndex("http://www.w3.org/2000/xmlns/");
2198    
2199        // W0  High:  Namespace  Low:  Node Type
2200        int w0 = NAMESPACE_NODE | (m_nsNames.stringToIndex("http://www.w3.org/2000/xmlns/")<<16);
2201    
2202        // W1:  Parent
2203        int w1 = currentParent;
2204        // W2:  CURRENTLY UNUSED -- It's next-sib in attrs, but we have no kids.
2205        int w2 = 0;
2206        // W3:  namespace name
2207        int w3 = namespaceIndex;
2208        // Add node
2209        int ourslot = appendNode(w0, w1, w2, w3);
2210        previousSibling = ourslot;  // Should attributes be previous siblings
2211        previousSiblingWasParent = false;
2212        return ;//(m_docHandle | ourslot);
2213      }
2214    
2215      /** Append an Attribute child at the current insertion
2216       * point.  Assumes that the symbols (namespace URI, local name, and
2217       * prefix) have already been added to the pools, and that the content has
2218       * already been appended to m_char. Note that the attribute's content has
2219       * been flattened into a single string; DTM does _NOT_ attempt to model
2220       * the details of entity references within attribute values.
2221       *
2222       * @param namespaceIndex int Index within the namespaceURI string pool
2223       * @param localNameIndex int Index within the local name string pool
2224       * @param prefixIndex int Index within the prefix string pool
2225       * @param isID boolean True if this attribute was declared as an ID
2226       * (for use in supporting getElementByID).
2227       * @param m_char_current_start int Starting offset of node's content in m_char.
2228       * @param contentLength int Length of node's content in m_char.
2229       * */
2230      void appendAttribute(int namespaceIndex, int localNameIndex, int prefixIndex,
2231                           boolean isID,
2232                           int m_char_current_start, int contentLength)
2233      {
2234        // %TBD% isID is not currently honored.
2235    
2236        // W0  High:  Namespace  Low:  Node Type
2237        int w0 = ATTRIBUTE_NODE | namespaceIndex<<16;
2238    
2239        // W1:  Parent
2240        int w1 = currentParent;
2241        // W2:  Next (not yet resolved)
2242        int w2 = 0;
2243        // W3:  Tagname high: prefix Low: local name
2244        int w3 = localNameIndex | prefixIndex<<16;
2245        /**/System.out.println("set w3="+w3+" "+(w3>>16)+"/"+(w3&0xffff));
2246        // Add node
2247        int ourslot = appendNode(w0, w1, w2, w3);
2248        previousSibling = ourslot;  // Should attributes be previous siblings
2249    
2250        // Attribute's content is currently appended as a Text Node
2251    
2252        // W0: Node Type
2253        w0 = TEXT_NODE;
2254        // W1: Parent
2255        w1 = ourslot;
2256        // W2: Start Position within buffer
2257        w2 = m_char_current_start;
2258        // W3: Length
2259        w3 = contentLength;
2260        appendNode(w0, w1, w2, w3);
2261    
2262        // Attrs are Parents
2263        previousSiblingWasParent = true;
2264        return ;//(m_docHandle | ourslot);
2265      }
2266    
2267      /**
2268       * This returns a stateless "traverser", that can navigate over an
2269       * XPath axis, though not in document order.
2270       *
2271       * @param axis One of Axes.ANCESTORORSELF, etc.
2272       *
2273       * @return A DTMAxisIterator, or null if the given axis isn't supported.
2274       */
2275      public DTMAxisTraverser getAxisTraverser(final int axis)
2276      {
2277        return null;
2278      }
2279    
2280      /**
2281       * This is a shortcut to the iterators that implement the
2282       * supported XPath axes (only namespace::) is not supported.
2283       * Returns a bare-bones iterator that must be initialized
2284       * with a start node (using iterator.setStartNode()).
2285       *
2286       * @param axis One of Axes.ANCESTORORSELF, etc.
2287       *
2288       * @return A DTMAxisIterator, or null if the given axis isn't supported.
2289       */
2290      public DTMAxisIterator getAxisIterator(final int axis)
2291      {
2292        // %TBD%
2293        return null;
2294      }
2295    
2296      /**
2297       * Get an iterator that can navigate over an XPath Axis, predicated by
2298       * the extended type ID.
2299       *
2300       *
2301       * @param axis
2302       * @param type An extended type ID.
2303       *
2304       * @return A DTMAxisIterator, or null if the given axis isn't supported.
2305       */
2306      public DTMAxisIterator getTypedAxisIterator(final int axis, final int type)
2307      {
2308        // %TBD%
2309        return null;
2310      }
2311    
2312    
2313      /** Terminate the element currently acting as an insertion point. Subsequent
2314       * insertions will occur as the last child of this element's parent.
2315       * */
2316      void appendEndElement()
2317      {
2318        // pop up the stacks
2319    
2320        if (previousSiblingWasParent)
2321          nodes.writeEntry(previousSibling, 2, NULL);
2322    
2323        // Pop parentage
2324        previousSibling = currentParent;
2325        nodes.readSlot(currentParent, gotslot);
2326        currentParent = gotslot[1] & 0xFFFF;
2327    
2328        // The element just being finished will be
2329        // the previous sibling for the next operation
2330        previousSiblingWasParent = true;
2331    
2332        // Pop a level of namespace table
2333        // namespaceTable.removeLastElem();
2334      }
2335    
2336      /**  Starting a new document. Perform any resets/initialization
2337       * not already handled.
2338       * */
2339      void appendStartDocument()
2340      {
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      {
2353        done = true;
2354        // %TBD% may need to notice the last slot number and slot count to avoid
2355        // residual data from provious use of this DTM
2356      }
2357    
2358      /**
2359       * For the moment all the run time properties are ignored by this
2360       * class.
2361       *
2362       * @param property a <code>String</code> value
2363       * @param value an <code>Object</code> value
2364       */
2365      public void setProperty(String property, Object value)
2366      {
2367      }
2368    
2369      /**
2370       * Source information is not handled yet, so return
2371       * <code>null</code> here.
2372       *
2373       * @param node an <code>int</code> value
2374       * @return null
2375       */
2376      public SourceLocator getSourceLocatorFor(int node)
2377      {
2378        return null;
2379      }
2380    
2381    
2382      /**
2383       * A dummy routine to satisify the abstract interface. If the DTM
2384       * implememtation that extends the default base requires notification
2385       * of registration, they can override this method.
2386       */
2387       public void documentRegistration()
2388       {
2389       }
2390    
2391      /**
2392       * A dummy routine to satisify the abstract interface. If the DTM
2393       * implememtation that extends the default base requires notification
2394       * when the document is being released, they can override this method
2395       */
2396       public void documentRelease()
2397       {
2398       }
2399    
2400       /**
2401        * Migrate a DTM built with an old DTMManager to a new DTMManager.
2402        * After the migration, the new DTMManager will treat the DTM as
2403        * one that is built by itself.
2404        * This is used to support DTM sharing between multiple transformations.
2405        * @param manager the DTMManager
2406        */
2407       public void migrateTo(DTMManager manager)
2408       {
2409       }
2410    
2411    }