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 }