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