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