1/* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 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 22package com.sun.org.apache.xml.internal.dtm.ref; 23 24import javax.xml.transform.SourceLocator; 25 26import com.sun.org.apache.xml.internal.dtm.DTM; 27import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 28import com.sun.org.apache.xml.internal.dtm.DTMAxisTraverser; 29import com.sun.org.apache.xml.internal.dtm.DTMManager; 30import com.sun.org.apache.xml.internal.dtm.DTMWSFilter; 31import com.sun.org.apache.xml.internal.utils.FastStringBuffer; 32import com.sun.org.apache.xml.internal.utils.XMLString; 33import com.sun.org.apache.xml.internal.utils.XMLStringFactory; 34 35import org.xml.sax.Attributes; 36import org.xml.sax.ContentHandler; 37import org.xml.sax.Locator; 38import 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 */ 64public class DTMDocumentImpl 65implements 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 public String getNodeValue(int nodeHandle) 1701 { 1702 nodes.readSlot(nodeHandle, gotslot); 1703 int nodetype=gotslot[0] & 0xFF; // ###zaj use mask to get node type 1704 String value=null; 1705 1706 switch (nodetype) { // ###zaj todo - document nodetypes 1707 case ATTRIBUTE_NODE: 1708 nodes.readSlot(nodeHandle+1, gotslot); 1709 case TEXT_NODE: 1710 case COMMENT_NODE: 1711 case CDATA_SECTION_NODE: 1712 value=m_char.getString(gotslot[2], gotslot[3]); //###zaj 1713 break; 1714 case PROCESSING_INSTRUCTION_NODE: 1715 case ELEMENT_NODE: 1716 case ENTITY_REFERENCE_NODE: 1717 default: 1718 break; 1719 } 1720 return value; 1721 } 1722 1723 /** 1724 * Given a node handle, return its DOM-style node type. 1725 * <p> 1726 * %REVIEW% Generally, returning short is false economy. Return int? 1727 * 1728 * @param nodeHandle The node id. 1729 * @return int Node type, as per the DOM's Node._NODE constants. 1730 */ 1731 public short getNodeType(int nodeHandle) { 1732 return(short) (nodes.readEntry(nodeHandle, 0) & 0xFFFF); 1733 } 1734 1735 /** 1736 * Get the depth level of this node in the tree (equals 1 for 1737 * a parentless node). 1738 * 1739 * @param nodeHandle The node id. 1740 * @return the number of ancestors, plus one 1741 * @xsl.usage internal 1742 */ 1743 public short getLevel(int nodeHandle) { 1744 short count = 0; 1745 while (nodeHandle != 0) { 1746 count++; 1747 nodeHandle = nodes.readEntry(nodeHandle, 1); 1748 } 1749 return count; 1750 } 1751 1752 // ============== Document query functions ============== 1753 1754 /** 1755 * Tests whether DTM DOM implementation implements a specific feature and 1756 * that feature is supported by this node. 1757 * 1758 * @param feature The name of the feature to test. 1759 * @param version This is the version number of the feature to test. 1760 * If the version is not 1761 * specified, supporting any version of the feature will cause the 1762 * method to return <code>true</code>. 1763 * @return Returns <code>true</code> if the specified feature is 1764 * supported on this node, <code>false</code> otherwise. 1765 */ 1766 public boolean isSupported(String feature, String version) {return false;} 1767 1768 /** 1769 * Return the base URI of the document entity. If it is not known 1770 * (because the document was parsed from a socket connection or from 1771 * standard input, for example), the value of this property is unknown. 1772 * 1773 * @return the document base URI String object or null if unknown. 1774 */ 1775 public String getDocumentBaseURI() 1776 { 1777 1778 return m_documentBaseURI; 1779 } 1780 1781 /** 1782 * Set the base URI of the document entity. 1783 * 1784 * @param baseURI the document base URI String object or null if unknown. 1785 */ 1786 public void setDocumentBaseURI(String baseURI) 1787 { 1788 1789 m_documentBaseURI = baseURI; 1790 } 1791 1792 /** 1793 * Return the system identifier of the document entity. If 1794 * it is not known, the value of this property is unknown. 1795 * 1796 * @param nodeHandle The node id, which can be any valid node handle. 1797 * @return the system identifier String object or null if unknown. 1798 */ 1799 public String getDocumentSystemIdentifier(int nodeHandle) {return null;} 1800 1801 /** 1802 * Return the name of the character encoding scheme 1803 * in which the document entity is expressed. 1804 * 1805 * @param nodeHandle The node id, which can be any valid node handle. 1806 * @return the document encoding String object. 1807 */ 1808 public String getDocumentEncoding(int nodeHandle) {return null;} 1809 1810 /** 1811 * Return an indication of the standalone status of the document, 1812 * either "yes" or "no". This property is derived from the optional 1813 * standalone document declaration in the XML declaration at the 1814 * beginning of the document entity, and has no value if there is no 1815 * standalone document declaration. 1816 * 1817 * @param nodeHandle The node id, which can be any valid node handle. 1818 * @return the document standalone String object, either "yes", "no", or null. 1819 */ 1820 public String getDocumentStandalone(int nodeHandle) {return null;} 1821 1822 /** 1823 * Return a string representing the XML version of the document. This 1824 * property is derived from the XML declaration optionally present at the 1825 * beginning of the document entity, and has no value if there is no XML 1826 * declaration. 1827 * 1828 * @param documentHandle the document handle 1829 * 1830 * @return the document version String object 1831 */ 1832 public String getDocumentVersion(int documentHandle) {return null;} 1833 1834 /** 1835 * Return an indication of 1836 * whether the processor has read the complete DTD. Its value is a 1837 * boolean. If it is false, then certain properties (indicated in their 1838 * descriptions below) may be unknown. If it is true, those properties 1839 * are never unknown. 1840 * 1841 * @return <code>true</code> if all declarations were processed {}; 1842 * <code>false</code> otherwise. 1843 */ 1844 public boolean getDocumentAllDeclarationsProcessed() {return false;} 1845 1846 /** 1847 * A document type declaration information item has the following properties: 1848 * 1849 * 1. [system identifier] The system identifier of the external subset, if 1850 * it exists. Otherwise this property has no value. 1851 * 1852 * @return the system identifier String object, or null if there is none. 1853 */ 1854 public String getDocumentTypeDeclarationSystemIdentifier() {return null;} 1855 1856 /** 1857 * Return the public identifier of the external subset, 1858 * normalized as described in 4.2.2 External Entities [XML]. If there is 1859 * no external subset or if it has no public identifier, this property 1860 * has no value. 1861 * 1862 * @return the public identifier String object, or null if there is none. 1863 */ 1864 public String getDocumentTypeDeclarationPublicIdentifier() {return null;} 1865 1866 /** 1867 * Returns the <code>Element</code> whose <code>ID</code> is given by 1868 * <code>elementId</code>. If no such element exists, returns 1869 * <code>DTM.NULL</code>. Behavior is not defined if more than one element 1870 * has this <code>ID</code>. Attributes (including those 1871 * with the name "ID") are not of type ID unless so defined by DTD/Schema 1872 * information available to the DTM implementation. 1873 * Implementations that do not know whether attributes are of type ID or 1874 * not are expected to return <code>DTM.NULL</code>. 1875 * 1876 * <p>%REVIEW% Presumably IDs are still scoped to a single document, 1877 * and this operation searches only within a single document, right? 1878 * Wouldn't want collisions between DTMs in the same process.</p> 1879 * 1880 * @param elementId The unique <code>id</code> value for an element. 1881 * @return The handle of the matching element. 1882 */ 1883 public int getElementById(String elementId) {return 0;} 1884 1885 /** 1886 * The getUnparsedEntityURI function returns the URI of the unparsed 1887 * entity with the specified name in the same document as the context 1888 * node (see [3.3 Unparsed Entities]). It returns the empty string if 1889 * there is no such entity. 1890 * <p> 1891 * XML processors may choose to use the System Identifier (if one 1892 * is provided) to resolve the entity, rather than the URI in the 1893 * Public Identifier. The details are dependent on the processor, and 1894 * we would have to support some form of plug-in resolver to handle 1895 * this properly. Currently, we simply return the System Identifier if 1896 * present, and hope that it a usable URI or that our caller can 1897 * map it to one. 1898 * TODO: Resolve Public Identifiers... or consider changing function name. 1899 * <p> 1900 * If we find a relative URI 1901 * reference, XML expects it to be resolved in terms of the base URI 1902 * of the document. The DOM doesn't do that for us, and it isn't 1903 * entirely clear whether that should be done here; currently that's 1904 * pushed up to a higher level of our application. (Note that DOM Level 1905 * 1 didn't store the document's base URI.) 1906 * TODO: Consider resolving Relative URIs. 1907 * <p> 1908 * (The DOM's statement that "An XML processor may choose to 1909 * completely expand entities before the structure model is passed 1910 * to the DOM" refers only to parsed entities, not unparsed, and hence 1911 * doesn't affect this function.) 1912 * 1913 * @param name A string containing the Entity Name of the unparsed 1914 * entity. 1915 * 1916 * @return String containing the URI of the Unparsed Entity, or an 1917 * empty string if no such entity exists. 1918 */ 1919 public String getUnparsedEntityURI(String name) {return null;} 1920 1921 1922 // ============== Boolean methods ================ 1923 1924 /** 1925 * Return true if the xsl:strip-space or xsl:preserve-space was processed 1926 * during construction of the DTM document. 1927 * 1928 * <p>%REVEIW% Presumes a 1:1 mapping from DTM to Document, since 1929 * we aren't saying which Document to query...?</p> 1930 */ 1931 public boolean supportsPreStripping() {return false;} 1932 1933 /** 1934 * Figure out whether nodeHandle2 should be considered as being later 1935 * in the document than nodeHandle1, in Document Order as defined 1936 * by the XPath model. This may not agree with the ordering defined 1937 * by other XML applications. 1938 * <p> 1939 * There are some cases where ordering isn't defined, and neither are 1940 * the results of this function -- though we'll generally return true. 1941 * 1942 * TODO: Make sure this does the right thing with attribute nodes!!! 1943 * 1944 * @param nodeHandle1 DOM Node to perform position comparison on. 1945 * @param nodeHandle2 DOM Node to perform position comparison on . 1946 * 1947 * @return false if node2 comes before node1, otherwise return true. 1948 * You can think of this as 1949 * <code>(node1.documentOrderPosition <= node2.documentOrderPosition)</code>. 1950 */ 1951 public boolean isNodeAfter(int nodeHandle1, int nodeHandle2) {return false;} 1952 1953 /** 1954 * 2. [element content whitespace] A boolean indicating whether the 1955 * character is white space appearing within element content (see [XML], 1956 * 2.10 "White Space Handling"). Note that validating XML processors are 1957 * required by XML 1.0 to provide this information. If there is no 1958 * declaration for the containing element, this property has no value for 1959 * white space characters. If no declaration has been read, but the [all 1960 * declarations processed] property of the document information item is 1961 * false (so there may be an unread declaration), then the value of this 1962 * property is unknown for white space characters. It is always false for 1963 * characters that are not white space. 1964 * 1965 * @param nodeHandle the node ID. 1966 * @return <code>true</code> if the character data is whitespace; 1967 * <code>false</code> otherwise. 1968 */ 1969 public boolean isCharacterElementContentWhitespace(int nodeHandle) {return false;} 1970 1971 /** 1972 * 10. [all declarations processed] This property is not strictly speaking 1973 * part of the infoset of the document. Rather it is an indication of 1974 * whether the processor has read the complete DTD. Its value is a 1975 * boolean. If it is false, then certain properties (indicated in their 1976 * descriptions below) may be unknown. If it is true, those properties 1977 * are never unknown. 1978 * 1979 * @param documentHandle A node handle that must identify a document. 1980 * @return <code>true</code> if all declarations were processed; 1981 * <code>false</code> otherwise. 1982 */ 1983 public boolean isDocumentAllDeclarationsProcessed(int documentHandle) {return false;} 1984 1985 /** 1986 * 5. [specified] A flag indicating whether this attribute was actually 1987 * specified in the start-tag of its element, or was defaulted from the 1988 * DTD. 1989 * 1990 * @param attributeHandle the attribute handle 1991 * @return <code>true</code> if the attribute was specified; 1992 * <code>false</code> if it was defaulted. 1993 */ 1994 public boolean isAttributeSpecified(int attributeHandle) {return false;} 1995 1996 // ========== Direct SAX Dispatch, for optimization purposes ======== 1997 1998 /** 1999 * Directly call the 2000 * characters method on the passed ContentHandler for the 2001 * string-value of the given node (see http://www.w3.org/TR/xpath#data-model 2002 * for the definition of a node's string-value). Multiple calls to the 2003 * ContentHandler's characters methods may well occur for a single call to 2004 * this method. 2005 * 2006 * @param nodeHandle The node ID. 2007 * @param ch A non-null reference to a ContentHandler. 2008 * 2009 * @throws org.xml.sax.SAXException 2010 */ 2011 public void dispatchCharactersEvents( 2012 int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize) 2013 throws org.xml.sax.SAXException {} 2014 2015 /** 2016 * Directly create SAX parser events from a subtree. 2017 * 2018 * @param nodeHandle The node ID. 2019 * @param ch A non-null reference to a ContentHandler. 2020 * 2021 * @throws org.xml.sax.SAXException 2022 */ 2023 2024 public void dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler ch) 2025 throws org.xml.sax.SAXException {} 2026 2027 /** 2028 * Return an DOM node for the given node. 2029 * 2030 * @param nodeHandle The node ID. 2031 * 2032 * @return A node representation of the DTM node. 2033 */ 2034 public org.w3c.dom.Node getNode(int nodeHandle) 2035 { 2036 return null; 2037 } 2038 2039 // ==== Construction methods (may not be supported by some implementations!) ===== 2040 // %REVIEW% jjk: These probably aren't the right API. At the very least 2041 // they need to deal with current-insertion-location and end-element 2042 // issues. 2043 2044 /** 2045 * Append a child to the end of the child list of the current node. Please note that the node 2046 * is always cloned if it is owned by another document. 2047 * 2048 * <p>%REVIEW% "End of the document" needs to be defined more clearly. 2049 * Does it become the last child of the Document? Of the root element?</p> 2050 * 2051 * @param newChild Must be a valid new node handle. 2052 * @param clone true if the child should be cloned into the document. 2053 * @param cloneDepth if the clone argument is true, specifies that the 2054 * clone should include all it's children. 2055 */ 2056 public void appendChild(int newChild, boolean clone, boolean cloneDepth) { 2057 boolean sameDoc = ((newChild & DOCHANDLE_MASK) == m_docHandle); 2058 if (clone || !sameDoc) { 2059 2060 } else { 2061 2062 } 2063 } 2064 2065 /** 2066 * Append a text node child that will be constructed from a string, 2067 * to the end of the document. 2068 * 2069 * <p>%REVIEW% "End of the document" needs to be defined more clearly. 2070 * Does it become the last child of the Document? Of the root element?</p> 2071 * 2072 * @param str Non-null reference to a string. 2073 */ 2074 public void appendTextChild(String str) { 2075 // ###shs Think more about how this differs from createTextNode 2076 //%TBD% 2077 } 2078 2079 2080 //================================================================ 2081 // ==== BUILDER methods ==== 2082 // %TBD% jjk: SHOULD PROBABLY BE INLINED, unless we want to support 2083 // both SAX1 and SAX2 and share this logic between them. 2084 2085 /** Append a text child at the current insertion point. Assumes that the 2086 * actual content of the text has previously been appended to the m_char 2087 * buffer (shared with the builder). 2088 * 2089 * @param m_char_current_start int Starting offset of node's content in m_char. 2090 * @param contentLength int Length of node's content in m_char. 2091 * */ 2092 void appendTextChild(int m_char_current_start,int contentLength) 2093 { 2094 // create a Text Node 2095 // %TBD% may be possible to combine with appendNode()to replace the next chunk of code 2096 int w0 = TEXT_NODE; 2097 // W1: Parent 2098 int w1 = currentParent; 2099 // W2: Start position within m_char 2100 int w2 = m_char_current_start; 2101 // W3: Length of the full string 2102 int w3 = contentLength; 2103 2104 int ourslot = appendNode(w0, w1, w2, w3); 2105 previousSibling = ourslot; 2106 } 2107 2108 /** Append a comment child at the current insertion point. Assumes that the 2109 * actual content of the comment has previously been appended to the m_char 2110 * buffer (shared with the builder). 2111 * 2112 * @param m_char_current_start int Starting offset of node's content in m_char. 2113 * @param contentLength int Length of node's content in m_char. 2114 * */ 2115 void appendComment(int m_char_current_start,int contentLength) 2116 { 2117 // create a Comment Node 2118 // %TBD% may be possible to combine with appendNode()to replace the next chunk of code 2119 int w0 = COMMENT_NODE; 2120 // W1: Parent 2121 int w1 = currentParent; 2122 // W2: Start position within m_char 2123 int w2 = m_char_current_start; 2124 // W3: Length of the full string 2125 int w3 = contentLength; 2126 2127 int ourslot = appendNode(w0, w1, w2, w3); 2128 previousSibling = ourslot; 2129 } 2130 2131 2132 /** Append an Element child at the current insertion point. This 2133 * Element then _becomes_ the insertion point; subsequent appends 2134 * become its lastChild until an appendEndElement() call is made. 2135 * 2136 * Assumes that the symbols (local name, namespace URI and prefix) 2137 * have already been added to the pools 2138 * 2139 * Note that this _only_ handles the Element node itself. Attrs and 2140 * namespace nodes are unbundled in the ContentHandler layer 2141 * and appended separately. 2142 * 2143 * @param namespaceIndex: Index within the namespaceURI string pool 2144 * @param localNameIndex Index within the local name string pool 2145 * @param prefixIndex: Index within the prefix string pool 2146 * */ 2147 void appendStartElement(int namespaceIndex,int localNameIndex, int prefixIndex) 2148 { 2149 // do document root node creation here on the first element, create nodes for 2150 // this element and its attributes, store the element, namespace, and attritute 2151 // name indexes to the nodes array, keep track of the current node and parent 2152 // element used 2153 2154 // W0 High: Namespace Low: Node Type 2155 int w0 = (namespaceIndex << 16) | ELEMENT_NODE; 2156 // W1: Parent 2157 int w1 = currentParent; 2158 // W2: Next (initialized as 0) 2159 int w2 = 0; 2160 // W3: Tagname high: prefix Low: local name 2161 int w3 = localNameIndex | prefixIndex<<16; 2162 /**/System.out.println("set w3="+w3+" "+(w3>>16)+"/"+(w3&0xffff)); 2163 2164 //int ourslot = nodes.appendSlot(w0, w1, w2, w3); 2165 int ourslot = appendNode(w0, w1, w2, w3); 2166 currentParent = ourslot; 2167 previousSibling = 0; 2168 2169 // set the root element pointer when creating the first element node 2170 if (m_docElement == NULL) 2171 m_docElement = ourslot; 2172 } 2173 2174 /** Append a Namespace Declaration child at the current insertion point. 2175 * Assumes that the symbols (namespace URI and prefix) have already been 2176 * added to the pools 2177 * 2178 * @param prefixIndex: Index within the prefix string pool 2179 * @param namespaceIndex: Index within the namespaceURI string pool 2180 * @param isID: If someone really insists on writing a bad DTD, it is 2181 * theoretically possible for a namespace declaration to also be declared 2182 * as being a node ID. I don't really want to support that stupidity, 2183 * but I'm not sure we can refuse to accept it. 2184 * */ 2185 void appendNSDeclaration(int prefixIndex, int namespaceIndex, 2186 boolean isID) 2187 { 2188 // %REVIEW% I'm assigning this node the "namespace for namespaces" 2189 // which the DOM defined. It is expected that the Namespace spec will 2190 // adopt this as official. It isn't strictly needed since it's implied 2191 // by the nodetype, but for now... 2192 2193 // %REVIEW% Prefix need not be recorded; it's implied too. But 2194 // recording it might simplify the design. 2195 2196 // %TBD% isID is not currently honored. 2197 2198 final int namespaceForNamespaces=m_nsNames.stringToIndex("http://www.w3.org/2000/xmlns/"); 2199 2200 // W0 High: Namespace Low: Node Type 2201 int w0 = NAMESPACE_NODE | (m_nsNames.stringToIndex("http://www.w3.org/2000/xmlns/")<<16); 2202 2203 // W1: Parent 2204 int w1 = currentParent; 2205 // W2: CURRENTLY UNUSED -- It's next-sib in attrs, but we have no kids. 2206 int w2 = 0; 2207 // W3: namespace name 2208 int w3 = namespaceIndex; 2209 // Add node 2210 int ourslot = appendNode(w0, w1, w2, w3); 2211 previousSibling = ourslot; // Should attributes be previous siblings 2212 previousSiblingWasParent = false; 2213 return ;//(m_docHandle | ourslot); 2214 } 2215 2216 /** Append an Attribute child at the current insertion 2217 * point. Assumes that the symbols (namespace URI, local name, and 2218 * prefix) have already been added to the pools, and that the content has 2219 * already been appended to m_char. Note that the attribute's content has 2220 * been flattened into a single string; DTM does _NOT_ attempt to model 2221 * the details of entity references within attribute values. 2222 * 2223 * @param namespaceIndex int Index within the namespaceURI string pool 2224 * @param localNameIndex int Index within the local name string pool 2225 * @param prefixIndex int Index within the prefix string pool 2226 * @param isID boolean True if this attribute was declared as an ID 2227 * (for use in supporting getElementByID). 2228 * @param m_char_current_start int Starting offset of node's content in m_char. 2229 * @param contentLength int Length of node's content in m_char. 2230 * */ 2231 void appendAttribute(int namespaceIndex, int localNameIndex, int prefixIndex, 2232 boolean isID, 2233 int m_char_current_start, int contentLength) 2234 { 2235 // %TBD% isID is not currently honored. 2236 2237 // W0 High: Namespace Low: Node Type 2238 int w0 = ATTRIBUTE_NODE | namespaceIndex<<16; 2239 2240 // W1: Parent 2241 int w1 = currentParent; 2242 // W2: Next (not yet resolved) 2243 int w2 = 0; 2244 // W3: Tagname high: prefix Low: local name 2245 int w3 = localNameIndex | prefixIndex<<16; 2246 /**/System.out.println("set w3="+w3+" "+(w3>>16)+"/"+(w3&0xffff)); 2247 // Add node 2248 int ourslot = appendNode(w0, w1, w2, w3); 2249 previousSibling = ourslot; // Should attributes be previous siblings 2250 2251 // Attribute's content is currently appended as a Text Node 2252 2253 // W0: Node Type 2254 w0 = TEXT_NODE; 2255 // W1: Parent 2256 w1 = ourslot; 2257 // W2: Start Position within buffer 2258 w2 = m_char_current_start; 2259 // W3: Length 2260 w3 = contentLength; 2261 appendNode(w0, w1, w2, w3); 2262 2263 // Attrs are Parents 2264 previousSiblingWasParent = true; 2265 return ;//(m_docHandle | ourslot); 2266 } 2267 2268 /** 2269 * This returns a stateless "traverser", that can navigate over an 2270 * XPath axis, though not in document order. 2271 * 2272 * @param axis One of Axes.ANCESTORORSELF, etc. 2273 * 2274 * @return A DTMAxisIterator, or null if the given axis isn't supported. 2275 */ 2276 public DTMAxisTraverser getAxisTraverser(final int axis) 2277 { 2278 return null; 2279 } 2280 2281 /** 2282 * This is a shortcut to the iterators that implement the 2283 * supported XPath axes (only namespace::) is not supported. 2284 * Returns a bare-bones iterator that must be initialized 2285 * with a start node (using iterator.setStartNode()). 2286 * 2287 * @param axis One of Axes.ANCESTORORSELF, etc. 2288 * 2289 * @return A DTMAxisIterator, or null if the given axis isn't supported. 2290 */ 2291 public DTMAxisIterator getAxisIterator(final int axis) 2292 { 2293 // %TBD% 2294 return null; 2295 } 2296 2297 /** 2298 * Get an iterator that can navigate over an XPath Axis, predicated by 2299 * the extended type ID. 2300 * 2301 * 2302 * @param axis 2303 * @param type An extended type ID. 2304 * 2305 * @return A DTMAxisIterator, or null if the given axis isn't supported. 2306 */ 2307 public DTMAxisIterator getTypedAxisIterator(final int axis, final int type) 2308 { 2309 // %TBD% 2310 return null; 2311 } 2312 2313 2314 /** Terminate the element currently acting as an insertion point. Subsequent 2315 * insertions will occur as the last child of this element's parent. 2316 * */ 2317 void appendEndElement() 2318 { 2319 // pop up the stacks 2320 2321 if (previousSiblingWasParent) 2322 nodes.writeEntry(previousSibling, 2, NULL); 2323 2324 // Pop parentage 2325 previousSibling = currentParent; 2326 nodes.readSlot(currentParent, gotslot); 2327 currentParent = gotslot[1] & 0xFFFF; 2328 2329 // The element just being finished will be 2330 // the previous sibling for the next operation 2331 previousSiblingWasParent = true; 2332 2333 // Pop a level of namespace table 2334 // namespaceTable.removeLastElem(); 2335 } 2336 2337 /** Starting a new document. Perform any resets/initialization 2338 * not already handled. 2339 * */ 2340 void appendStartDocument() 2341 { 2342 2343 // %TBD% reset slot 0 to indicate ChunkedIntArray reuse or wait for 2344 // the next initDocument(). 2345 m_docElement = NULL; // reset nodeHandle to the root of the actual dtm doc content 2346 initDocument(0); 2347 } 2348 2349 /** All appends to this document have finished; do whatever final 2350 * cleanup is needed. 2351 * */ 2352 void appendEndDocument() 2353 { 2354 done = true; 2355 // %TBD% may need to notice the last slot number and slot count to avoid 2356 // residual data from provious use of this DTM 2357 } 2358 2359 /** 2360 * For the moment all the run time properties are ignored by this 2361 * class. 2362 * 2363 * @param property a <code>String</code> value 2364 * @param value an <code>Object</code> value 2365 */ 2366 public void setProperty(String property, Object value) 2367 { 2368 } 2369 2370 /** 2371 * Source information is not handled yet, so return 2372 * <code>null</code> here. 2373 * 2374 * @param node an <code>int</code> value 2375 * @return null 2376 */ 2377 public SourceLocator getSourceLocatorFor(int node) 2378 { 2379 return null; 2380 } 2381 2382 2383 /** 2384 * A dummy routine to satisify the abstract interface. If the DTM 2385 * implememtation that extends the default base requires notification 2386 * of registration, they can override this method. 2387 */ 2388 public void documentRegistration() 2389 { 2390 } 2391 2392 /** 2393 * A dummy routine to satisify the abstract interface. If the DTM 2394 * implememtation that extends the default base requires notification 2395 * when the document is being released, they can override this method 2396 */ 2397 public void documentRelease() 2398 { 2399 } 2400 2401 /** 2402 * Migrate a DTM built with an old DTMManager to a new DTMManager. 2403 * After the migration, the new DTMManager will treat the DTM as 2404 * one that is built by itself. 2405 * This is used to support DTM sharing between multiple transformations. 2406 * @param manager the DTMManager 2407 */ 2408 public void migrateTo(DTMManager manager) 2409 { 2410 } 2411 2412} 2413