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 <= 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 }