1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id: DTMDefaultBase.java 468653 2006-10-28 07:07:05Z minchau $ 20 */ 21 package org.apache.xml.dtm.ref; 22 23 import org.apache.xml.dtm.*; 24 import org.apache.xml.utils.SuballocatedIntVector; 25 import org.apache.xml.utils.BoolStack; 26 27 import java.util.Vector; 28 29 import javax.xml.transform.Source; 30 31 import org.apache.xml.utils.XMLString; 32 import org.apache.xml.utils.XMLStringFactory; 33 34 import org.apache.xml.res.XMLMessages; 35 import org.apache.xml.res.XMLErrorResources; 36 37 import java.io.*; // for dumpDTM 38 39 /** 40 * The <code>DTMDefaultBase</code> class serves as a helper base for DTMs. 41 * It sets up structures for navigation and type, while leaving data 42 * management and construction to the derived classes. 43 */ 44 public abstract class DTMDefaultBase implements DTM 45 { 46 static final boolean JJK_DEBUG=false; 47 48 // This constant is likely to be removed in the future. Use the 49 // getDocument() method instead of ROOTNODE to get at the root 50 // node of a DTM. 51 /** The identity of the root node. */ 52 public static final int ROOTNODE = 0; 53 54 /** 55 * The number of nodes, which is also used to determine the next 56 * node index. 57 */ 58 protected int m_size = 0; 59 60 /** The expanded names, one array element for each node. */ 61 protected SuballocatedIntVector m_exptype; 62 63 /** First child values, one array element for each node. */ 64 protected SuballocatedIntVector m_firstch; 65 66 /** Next sibling values, one array element for each node. */ 67 protected SuballocatedIntVector m_nextsib; 68 69 /** Previous sibling values, one array element for each node. */ 70 protected SuballocatedIntVector m_prevsib; 71 72 /** Previous sibling values, one array element for each node. */ 73 protected SuballocatedIntVector m_parent; 74 75 /** Vector of SuballocatedIntVectors of NS decl sets */ 76 protected Vector m_namespaceDeclSets = null; 77 78 /** SuballocatedIntVector of elements at which corresponding 79 * namespaceDeclSets were defined */ 80 protected SuballocatedIntVector m_namespaceDeclSetElements = null; 81 82 /** 83 * These hold indexes to elements based on namespace and local name. 84 * The base lookup is the the namespace. The second lookup is the local 85 * name, and the last array contains the the first free element 86 * at the start, and the list of element handles following. 87 */ 88 protected int[][][] m_elemIndexes; 89 90 /** The default block size of the node arrays */ 91 public static final int DEFAULT_BLOCKSIZE = 512; // favor small docs. 92 93 /** The number of blocks for the node arrays */ 94 public static final int DEFAULT_NUMBLOCKS = 32; 95 96 /** The number of blocks used for small documents & RTFs */ 97 public static final int DEFAULT_NUMBLOCKS_SMALL = 4; 98 99 /** The block size of the node arrays */ 100 //protected final int m_blocksize; 101 102 /** 103 * The value to use when the information has not been built yet. 104 */ 105 protected static final int NOTPROCESSED = DTM.NULL - 1; 106 107 /** 108 * The DTM manager who "owns" this DTM. 109 */ 110 111 public DTMManager m_mgr; 112 113 /** 114 * m_mgr cast to DTMManagerDefault, or null if it isn't an instance 115 * (Efficiency hook) 116 */ 117 protected DTMManagerDefault m_mgrDefault=null; 118 119 120 /** The document identity number(s). If we have overflowed the addressing 121 * range of the first that was assigned to us, we may add others. */ 122 protected SuballocatedIntVector m_dtmIdent; 123 124 /** The mask for the identity. 125 %REVIEW% Should this really be set to the _DEFAULT? What if 126 a particular DTM wanted to use another value? */ 127 //protected final static int m_mask = DTMManager.IDENT_NODE_DEFAULT; 128 129 /** The base URI for this document. */ 130 protected String m_documentBaseURI; 131 132 /** 133 * The whitespace filter that enables elements to strip whitespace or not. 134 */ 135 protected DTMWSFilter m_wsfilter; 136 137 /** Flag indicating whether to strip whitespace nodes */ 138 protected boolean m_shouldStripWS = false; 139 140 /** Stack of flags indicating whether to strip whitespace nodes */ 141 protected BoolStack m_shouldStripWhitespaceStack; 142 143 /** The XMLString factory for creating XMLStrings. */ 144 protected XMLStringFactory m_xstrf; 145 146 /** 147 * The table for exandedNameID lookups. This may or may not be the same 148 * table as is contained in the DTMManagerDefault. 149 */ 150 protected ExpandedNameTable m_expandedNameTable; 151 152 /** true if indexing is turned on. */ 153 protected boolean m_indexing; 154 155 /** 156 * Construct a DTMDefaultBase object using the default block size. 157 * 158 * @param mgr The DTMManager who owns this DTM. 159 * @param source The object that is used to specify the construction source. 160 * @param dtmIdentity The DTM identity ID for this DTM. 161 * @param whiteSpaceFilter The white space filter for this DTM, which may 162 * be null. 163 * @param xstringfactory The factory to use for creating XMLStrings. 164 * @param doIndexing true if the caller considers it worth it to use 165 * indexing schemes. 166 */ DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing)167 public DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity, 168 DTMWSFilter whiteSpaceFilter, 169 XMLStringFactory xstringfactory, boolean doIndexing) 170 { 171 this(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, 172 doIndexing, DEFAULT_BLOCKSIZE, true, false); 173 } 174 175 /** 176 * Construct a DTMDefaultBase object from a DOM node. 177 * 178 * @param mgr The DTMManager who owns this DTM. 179 * @param source The object that is used to specify the construction source. 180 * @param dtmIdentity The DTM identity ID for this DTM. 181 * @param whiteSpaceFilter The white space filter for this DTM, which may 182 * be null. 183 * @param xstringfactory The factory to use for creating XMLStrings. 184 * @param doIndexing true if the caller considers it worth it to use 185 * indexing schemes. 186 * @param blocksize The block size of the DTM. 187 * @param usePrevsib true if we want to build the previous sibling node array. 188 * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM. 189 */ DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing, int blocksize, boolean usePrevsib, boolean newNameTable)190 public DTMDefaultBase(DTMManager mgr, Source source, int dtmIdentity, 191 DTMWSFilter whiteSpaceFilter, 192 XMLStringFactory xstringfactory, boolean doIndexing, 193 int blocksize, boolean usePrevsib, 194 boolean newNameTable) 195 { 196 // Use smaller sizes for the internal node arrays if the block size 197 // is small. 198 int numblocks; 199 if (blocksize <= 64) 200 { 201 numblocks = DEFAULT_NUMBLOCKS_SMALL; 202 m_dtmIdent= new SuballocatedIntVector(4, 1); 203 } 204 else 205 { 206 numblocks = DEFAULT_NUMBLOCKS; 207 m_dtmIdent= new SuballocatedIntVector(32); 208 } 209 210 m_exptype = new SuballocatedIntVector(blocksize, numblocks); 211 m_firstch = new SuballocatedIntVector(blocksize, numblocks); 212 m_nextsib = new SuballocatedIntVector(blocksize, numblocks); 213 m_parent = new SuballocatedIntVector(blocksize, numblocks); 214 215 // Only create the m_prevsib array if the usePrevsib flag is true. 216 // Some DTM implementations (e.g. SAXImpl) do not need this array. 217 // We can save the time to build it in those cases. 218 if (usePrevsib) 219 m_prevsib = new SuballocatedIntVector(blocksize, numblocks); 220 221 m_mgr = mgr; 222 if(mgr instanceof DTMManagerDefault) 223 m_mgrDefault=(DTMManagerDefault)mgr; 224 225 m_documentBaseURI = (null != source) ? source.getSystemId() : null; 226 m_dtmIdent.setElementAt(dtmIdentity,0); 227 m_wsfilter = whiteSpaceFilter; 228 m_xstrf = xstringfactory; 229 m_indexing = doIndexing; 230 231 if (doIndexing) 232 { 233 m_expandedNameTable = new ExpandedNameTable(); 234 } 235 else 236 { 237 // Note that this fails if we aren't talking to an instance of 238 // DTMManagerDefault 239 m_expandedNameTable = m_mgrDefault.getExpandedNameTable(this); 240 } 241 242 if (null != whiteSpaceFilter) 243 { 244 m_shouldStripWhitespaceStack = new BoolStack(); 245 246 pushShouldStripWhitespace(false); 247 } 248 } 249 250 /** 251 * Ensure that the size of the element indexes can hold the information. 252 * 253 * @param namespaceID Namespace ID index. 254 * @param LocalNameID Local name ID. 255 */ ensureSizeOfIndex(int namespaceID, int LocalNameID)256 protected void ensureSizeOfIndex(int namespaceID, int LocalNameID) 257 { 258 259 if (null == m_elemIndexes) 260 { 261 m_elemIndexes = new int[namespaceID + 20][][]; 262 } 263 else if (m_elemIndexes.length <= namespaceID) 264 { 265 int[][][] indexes = m_elemIndexes; 266 267 m_elemIndexes = new int[namespaceID + 20][][]; 268 269 System.arraycopy(indexes, 0, m_elemIndexes, 0, indexes.length); 270 } 271 272 int[][] localNameIndex = m_elemIndexes[namespaceID]; 273 274 if (null == localNameIndex) 275 { 276 localNameIndex = new int[LocalNameID + 100][]; 277 m_elemIndexes[namespaceID] = localNameIndex; 278 } 279 else if (localNameIndex.length <= LocalNameID) 280 { 281 int[][] indexes = localNameIndex; 282 283 localNameIndex = new int[LocalNameID + 100][]; 284 285 System.arraycopy(indexes, 0, localNameIndex, 0, indexes.length); 286 287 m_elemIndexes[namespaceID] = localNameIndex; 288 } 289 290 int[] elemHandles = localNameIndex[LocalNameID]; 291 292 if (null == elemHandles) 293 { 294 elemHandles = new int[128]; 295 localNameIndex[LocalNameID] = elemHandles; 296 elemHandles[0] = 1; 297 } 298 else if (elemHandles.length <= elemHandles[0] + 1) 299 { 300 int[] indexes = elemHandles; 301 302 elemHandles = new int[elemHandles[0] + 1024]; 303 304 System.arraycopy(indexes, 0, elemHandles, 0, indexes.length); 305 306 localNameIndex[LocalNameID] = elemHandles; 307 } 308 } 309 310 /** 311 * Add a node to the element indexes. The node will not be added unless 312 * it's an element. 313 * 314 * @param expandedTypeID The expanded type ID of the node. 315 * @param identity The node identity index. 316 */ indexNode(int expandedTypeID, int identity)317 protected void indexNode(int expandedTypeID, int identity) 318 { 319 320 ExpandedNameTable ent = m_expandedNameTable; 321 short type = ent.getType(expandedTypeID); 322 323 if (DTM.ELEMENT_NODE == type) 324 { 325 int namespaceID = ent.getNamespaceID(expandedTypeID); 326 int localNameID = ent.getLocalNameID(expandedTypeID); 327 328 ensureSizeOfIndex(namespaceID, localNameID); 329 330 int[] index = m_elemIndexes[namespaceID][localNameID]; 331 332 index[index[0]] = identity; 333 334 index[0]++; 335 } 336 } 337 338 /** 339 * Find the first index that occurs in the list that is greater than or 340 * equal to the given value. 341 * 342 * @param list A list of integers. 343 * @param start The start index to begin the search. 344 * @param len The number of items to search. 345 * @param value Find the slot that has a value that is greater than or 346 * identical to this argument. 347 * 348 * @return The index in the list of the slot that is higher or identical 349 * to the identity argument, or -1 if no node is higher or equal. 350 */ findGTE(int[] list, int start, int len, int value)351 protected int findGTE(int[] list, int start, int len, int value) 352 { 353 354 int low = start; 355 int high = start + (len - 1); 356 int end = high; 357 358 while (low <= high) 359 { 360 int mid = (low + high) / 2; 361 int c = list[mid]; 362 363 if (c > value) 364 high = mid - 1; 365 else if (c < value) 366 low = mid + 1; 367 else 368 return mid; 369 } 370 371 return (low <= end && list[low] > value) ? low : -1; 372 } 373 374 /** 375 * Find the first matching element from the index at or after the 376 * given node. 377 * 378 * @param nsIndex The namespace index lookup. 379 * @param lnIndex The local name index lookup. 380 * @param firstPotential The first potential match that is worth looking at. 381 * 382 * @return The first node that is greater than or equal to the 383 * firstPotential argument, or DTM.NOTPROCESSED if not found. 384 */ findElementFromIndex(int nsIndex, int lnIndex, int firstPotential)385 int findElementFromIndex(int nsIndex, int lnIndex, int firstPotential) 386 { 387 388 int[][][] indexes = m_elemIndexes; 389 390 if (null != indexes && nsIndex < indexes.length) 391 { 392 int[][] lnIndexs = indexes[nsIndex]; 393 394 if (null != lnIndexs && lnIndex < lnIndexs.length) 395 { 396 int[] elems = lnIndexs[lnIndex]; 397 398 if (null != elems) 399 { 400 int pos = findGTE(elems, 1, elems[0], firstPotential); 401 402 if (pos > -1) 403 { 404 return elems[pos]; 405 } 406 } 407 } 408 } 409 410 return NOTPROCESSED; 411 } 412 413 /** 414 * Get the next node identity value in the list, and call the iterator 415 * if it hasn't been added yet. 416 * 417 * @param identity The node identity (index). 418 * @return identity+1, or DTM.NULL. 419 */ getNextNodeIdentity(int identity)420 protected abstract int getNextNodeIdentity(int identity); 421 422 /** 423 * This method should try and build one or more nodes in the table. 424 * 425 * @return The true if a next node is found or false if 426 * there are no more nodes. 427 */ nextNode()428 protected abstract boolean nextNode(); 429 430 /** 431 * Get the number of nodes that have been added. 432 * 433 * @return the number of nodes that have been mapped. 434 */ getNumberOfNodes()435 protected abstract int getNumberOfNodes(); 436 437 /** Stateless axis traversers, lazely built. */ 438 protected DTMAxisTraverser[] m_traversers; 439 440 // /** 441 // * Ensure that the size of the information arrays can hold another entry 442 // * at the given index. 443 // * 444 // * @param index On exit from this function, the information arrays sizes must be 445 // * at least index+1. 446 // */ 447 // protected void ensureSize(int index) 448 // { 449 // // We've cut over to Suballocated*Vector, which are self-sizing. 450 // } 451 452 /** 453 * Get the simple type ID for the given node identity. 454 * 455 * @param identity The node identity. 456 * 457 * @return The simple type ID, or DTM.NULL. 458 */ _type(int identity)459 protected short _type(int identity) 460 { 461 462 int info = _exptype(identity); 463 464 if (NULL != info) 465 return m_expandedNameTable.getType(info); 466 else 467 return NULL; 468 } 469 470 /** 471 * Get the expanded type ID for the given node identity. 472 * 473 * @param identity The node identity. 474 * 475 * @return The expanded type ID, or DTM.NULL. 476 */ _exptype(int identity)477 protected int _exptype(int identity) 478 { 479 if (identity == DTM.NULL) 480 return NULL; 481 // Reorganized test and loop into single flow 482 // Tiny performance improvement, saves a few bytes of code, clearer. 483 // %OPT% Other internal getters could be treated simliarly 484 while (identity>=m_size) 485 { 486 if (!nextNode() && identity >= m_size) 487 return NULL; 488 } 489 return m_exptype.elementAt(identity); 490 491 } 492 493 /** 494 * Get the level in the tree for the given node identity. 495 * 496 * @param identity The node identity. 497 * 498 * @return The tree level, or DTM.NULL. 499 */ _level(int identity)500 protected int _level(int identity) 501 { 502 while (identity>=m_size) 503 { 504 boolean isMore = nextNode(); 505 if (!isMore && identity >= m_size) 506 return NULL; 507 } 508 509 int i=0; 510 while(NULL != (identity=_parent(identity))) 511 ++i; 512 return i; 513 } 514 515 /** 516 * Get the first child for the given node identity. 517 * 518 * @param identity The node identity. 519 * 520 * @return The first child identity, or DTM.NULL. 521 */ _firstch(int identity)522 protected int _firstch(int identity) 523 { 524 525 // Boiler-plate code for each of the _xxx functions, except for the array. 526 int info = (identity >= m_size) ? NOTPROCESSED : m_firstch.elementAt(identity); 527 528 // Check to see if the information requested has been processed, and, 529 // if not, advance the iterator until we the information has been 530 // processed. 531 while (info == NOTPROCESSED) 532 { 533 boolean isMore = nextNode(); 534 535 if (identity >= m_size &&!isMore) 536 return NULL; 537 else 538 { 539 info = m_firstch.elementAt(identity); 540 if(info == NOTPROCESSED && !isMore) 541 return NULL; 542 } 543 } 544 545 return info; 546 } 547 548 /** 549 * Get the next sibling for the given node identity. 550 * 551 * @param identity The node identity. 552 * 553 * @return The next sibling identity, or DTM.NULL. 554 */ _nextsib(int identity)555 protected int _nextsib(int identity) 556 { 557 // Boiler-plate code for each of the _xxx functions, except for the array. 558 int info = (identity >= m_size) ? NOTPROCESSED : m_nextsib.elementAt(identity); 559 560 // Check to see if the information requested has been processed, and, 561 // if not, advance the iterator until we the information has been 562 // processed. 563 while (info == NOTPROCESSED) 564 { 565 boolean isMore = nextNode(); 566 567 if (identity >= m_size &&!isMore) 568 return NULL; 569 else 570 { 571 info = m_nextsib.elementAt(identity); 572 if(info == NOTPROCESSED && !isMore) 573 return NULL; 574 } 575 } 576 577 return info; 578 } 579 580 /** 581 * Get the previous sibling for the given node identity. 582 * 583 * @param identity The node identity. 584 * 585 * @return The previous sibling identity, or DTM.NULL. 586 */ _prevsib(int identity)587 protected int _prevsib(int identity) 588 { 589 590 if (identity < m_size) 591 return m_prevsib.elementAt(identity); 592 593 // Check to see if the information requested has been processed, and, 594 // if not, advance the iterator until we the information has been 595 // processed. 596 while (true) 597 { 598 boolean isMore = nextNode(); 599 600 if (identity >= m_size && !isMore) 601 return NULL; 602 else if (identity < m_size) 603 return m_prevsib.elementAt(identity); 604 } 605 } 606 607 /** 608 * Get the parent for the given node identity. 609 * 610 * @param identity The node identity. 611 * 612 * @return The parent identity, or DTM.NULL. 613 */ _parent(int identity)614 protected int _parent(int identity) 615 { 616 617 if (identity < m_size) 618 return m_parent.elementAt(identity); 619 620 // Check to see if the information requested has been processed, and, 621 // if not, advance the iterator until we the information has been 622 // processed. 623 while (true) 624 { 625 boolean isMore = nextNode(); 626 627 if (identity >= m_size && !isMore) 628 return NULL; 629 else if (identity < m_size) 630 return m_parent.elementAt(identity); 631 } 632 } 633 634 /** 635 * Diagnostics function to dump the DTM. 636 */ dumpDTM(OutputStream os)637 public void dumpDTM(OutputStream os) 638 { 639 try 640 { 641 if(os==null) 642 { 643 File f = new File("DTMDump"+((Object)this).hashCode()+".txt"); 644 System.err.println("Dumping... "+f.getAbsolutePath()); 645 os=new FileOutputStream(f); 646 } 647 PrintStream ps = new PrintStream(os); 648 649 while (nextNode()){} 650 651 int nRecords = m_size; 652 653 ps.println("Total nodes: " + nRecords); 654 655 for (int index = 0; index < nRecords; ++index) 656 { 657 int i=makeNodeHandle(index); 658 ps.println("=========== index=" + index + " handle=" + i + " ==========="); 659 ps.println("NodeName: " + getNodeName(i)); 660 ps.println("NodeNameX: " + getNodeNameX(i)); 661 ps.println("LocalName: " + getLocalName(i)); 662 ps.println("NamespaceURI: " + getNamespaceURI(i)); 663 ps.println("Prefix: " + getPrefix(i)); 664 665 int exTypeID = _exptype(index); 666 667 ps.println("Expanded Type ID: " 668 + Integer.toHexString(exTypeID)); 669 670 int type = _type(index); 671 String typestring; 672 673 switch (type) 674 { 675 case DTM.ATTRIBUTE_NODE : 676 typestring = "ATTRIBUTE_NODE"; 677 break; 678 case DTM.CDATA_SECTION_NODE : 679 typestring = "CDATA_SECTION_NODE"; 680 break; 681 case DTM.COMMENT_NODE : 682 typestring = "COMMENT_NODE"; 683 break; 684 case DTM.DOCUMENT_FRAGMENT_NODE : 685 typestring = "DOCUMENT_FRAGMENT_NODE"; 686 break; 687 case DTM.DOCUMENT_NODE : 688 typestring = "DOCUMENT_NODE"; 689 break; 690 case DTM.DOCUMENT_TYPE_NODE : 691 typestring = "DOCUMENT_NODE"; 692 break; 693 case DTM.ELEMENT_NODE : 694 typestring = "ELEMENT_NODE"; 695 break; 696 case DTM.ENTITY_NODE : 697 typestring = "ENTITY_NODE"; 698 break; 699 case DTM.ENTITY_REFERENCE_NODE : 700 typestring = "ENTITY_REFERENCE_NODE"; 701 break; 702 case DTM.NAMESPACE_NODE : 703 typestring = "NAMESPACE_NODE"; 704 break; 705 case DTM.NOTATION_NODE : 706 typestring = "NOTATION_NODE"; 707 break; 708 case DTM.NULL : 709 typestring = "NULL"; 710 break; 711 case DTM.PROCESSING_INSTRUCTION_NODE : 712 typestring = "PROCESSING_INSTRUCTION_NODE"; 713 break; 714 case DTM.TEXT_NODE : 715 typestring = "TEXT_NODE"; 716 break; 717 default : 718 typestring = "Unknown!"; 719 break; 720 } 721 722 ps.println("Type: " + typestring); 723 724 int firstChild = _firstch(index); 725 726 if (DTM.NULL == firstChild) 727 ps.println("First child: DTM.NULL"); 728 else if (NOTPROCESSED == firstChild) 729 ps.println("First child: NOTPROCESSED"); 730 else 731 ps.println("First child: " + firstChild); 732 733 if (m_prevsib != null) 734 { 735 int prevSibling = _prevsib(index); 736 737 if (DTM.NULL == prevSibling) 738 ps.println("Prev sibling: DTM.NULL"); 739 else if (NOTPROCESSED == prevSibling) 740 ps.println("Prev sibling: NOTPROCESSED"); 741 else 742 ps.println("Prev sibling: " + prevSibling); 743 } 744 745 int nextSibling = _nextsib(index); 746 747 if (DTM.NULL == nextSibling) 748 ps.println("Next sibling: DTM.NULL"); 749 else if (NOTPROCESSED == nextSibling) 750 ps.println("Next sibling: NOTPROCESSED"); 751 else 752 ps.println("Next sibling: " + nextSibling); 753 754 int parent = _parent(index); 755 756 if (DTM.NULL == parent) 757 ps.println("Parent: DTM.NULL"); 758 else if (NOTPROCESSED == parent) 759 ps.println("Parent: NOTPROCESSED"); 760 else 761 ps.println("Parent: " + parent); 762 763 int level = _level(index); 764 765 ps.println("Level: " + level); 766 ps.println("Node Value: " + getNodeValue(i)); 767 ps.println("String Value: " + getStringValue(i)); 768 } 769 } 770 catch(IOException ioe) 771 { 772 ioe.printStackTrace(System.err); 773 throw new RuntimeException(ioe.getMessage()); 774 } 775 } 776 777 /** 778 * Diagnostics function to dump a single node. 779 * 780 * %REVIEW% KNOWN GLITCH: If you pass it a node index rather than a 781 * node handle, it works just fine... but the displayed identity 782 * number before the colon is different, which complicates comparing 783 * it with nodes printed the other way. We could always OR the DTM ID 784 * into the value, to suppress that distinction... 785 * 786 * %REVIEW% This might want to be moved up to DTMDefaultBase, or possibly 787 * DTM itself, since it's a useful diagnostic and uses only DTM's public 788 * APIs. 789 */ dumpNode(int nodeHandle)790 public String dumpNode(int nodeHandle) 791 { 792 if(nodeHandle==DTM.NULL) 793 return "[null]"; 794 795 String typestring; 796 switch (getNodeType(nodeHandle)) 797 { 798 case DTM.ATTRIBUTE_NODE : 799 typestring = "ATTR"; 800 break; 801 case DTM.CDATA_SECTION_NODE : 802 typestring = "CDATA"; 803 break; 804 case DTM.COMMENT_NODE : 805 typestring = "COMMENT"; 806 break; 807 case DTM.DOCUMENT_FRAGMENT_NODE : 808 typestring = "DOC_FRAG"; 809 break; 810 case DTM.DOCUMENT_NODE : 811 typestring = "DOC"; 812 break; 813 case DTM.DOCUMENT_TYPE_NODE : 814 typestring = "DOC_TYPE"; 815 break; 816 case DTM.ELEMENT_NODE : 817 typestring = "ELEMENT"; 818 break; 819 case DTM.ENTITY_NODE : 820 typestring = "ENTITY"; 821 break; 822 case DTM.ENTITY_REFERENCE_NODE : 823 typestring = "ENT_REF"; 824 break; 825 case DTM.NAMESPACE_NODE : 826 typestring = "NAMESPACE"; 827 break; 828 case DTM.NOTATION_NODE : 829 typestring = "NOTATION"; 830 break; 831 case DTM.NULL : 832 typestring = "null"; 833 break; 834 case DTM.PROCESSING_INSTRUCTION_NODE : 835 typestring = "PI"; 836 break; 837 case DTM.TEXT_NODE : 838 typestring = "TEXT"; 839 break; 840 default : 841 typestring = "Unknown!"; 842 break; 843 } 844 845 StringBuffer sb=new StringBuffer(); 846 sb.append("["+nodeHandle+": "+typestring+ 847 "(0x"+Integer.toHexString(getExpandedTypeID(nodeHandle))+") "+ 848 getNodeNameX(nodeHandle)+" {"+getNamespaceURI(nodeHandle)+"}"+ 849 "=\""+ getNodeValue(nodeHandle)+"\"]"); 850 return sb.toString(); 851 } 852 853 // ========= DTM Implementation Control Functions. ============== 854 855 /** 856 * Set an implementation dependent feature. 857 * <p> 858 * %REVIEW% Do we really expect to set features on DTMs? 859 * 860 * @param featureId A feature URL. 861 * @param state true if this feature should be on, false otherwise. 862 */ setFeature(String featureId, boolean state)863 public void setFeature(String featureId, boolean state){} 864 865 // ========= Document Navigation Functions ========= 866 867 /** 868 * Given a node handle, test if it has child nodes. 869 * <p> %REVIEW% This is obviously useful at the DOM layer, where it 870 * would permit testing this without having to create a proxy 871 * node. It's less useful in the DTM API, where 872 * (dtm.getFirstChild(nodeHandle)!=DTM.NULL) is just as fast and 873 * almost as self-evident. But it's a convenience, and eases porting 874 * of DOM code to DTM. </p> 875 * 876 * @param nodeHandle int Handle of the node. 877 * @return int true if the given node has child nodes. 878 */ hasChildNodes(int nodeHandle)879 public boolean hasChildNodes(int nodeHandle) 880 { 881 882 int identity = makeNodeIdentity(nodeHandle); 883 int firstChild = _firstch(identity); 884 885 return firstChild != DTM.NULL; 886 } 887 888 /** Given a node identity, return a node handle. If extended addressing 889 * has been used (multiple DTM IDs), we need to map the high bits of the 890 * identity into the proper DTM ID. 891 * 892 * This has been made FINAL to facilitate inlining, since we do not expect 893 * any subclass of DTMDefaultBase to ever change the algorithm. (I don't 894 * really like doing so, and would love to have an excuse not to...) 895 * 896 * %REVIEW% Is it worth trying to specialcase small documents? 897 * %REVIEW% Should this be exposed at the package/public layers? 898 * 899 * @param nodeIdentity Internal offset to this node's records. 900 * @return NodeHandle (external representation of node) 901 * */ makeNodeHandle(int nodeIdentity)902 final public int makeNodeHandle(int nodeIdentity) 903 { 904 if(NULL==nodeIdentity) return NULL; 905 906 if(JJK_DEBUG && nodeIdentity>DTMManager.IDENT_NODE_DEFAULT) 907 System.err.println("GONK! (only useful in limited situations)"); 908 909 return m_dtmIdent.elementAt(nodeIdentity >>> DTMManager.IDENT_DTM_NODE_BITS) 910 + (nodeIdentity & DTMManager.IDENT_NODE_DEFAULT) ; 911 } 912 913 /** Given a node handle, return a node identity. If extended addressing 914 * has been used (multiple DTM IDs), we need to map the high bits of the 915 * identity into the proper DTM ID and thence find the proper offset 916 * to add to the low bits of the identity 917 * 918 * This has been made FINAL to facilitate inlining, since we do not expect 919 * any subclass of DTMDefaultBase to ever change the algorithm. (I don't 920 * really like doing so, and would love to have an excuse not to...) 921 * 922 * %OPT% Performance is critical for this operation. 923 * 924 * %REVIEW% Should this be exposed at the package/public layers? 925 * 926 * @param nodeHandle (external representation of node) 927 * @return nodeIdentity Internal offset to this node's records. 928 * */ makeNodeIdentity(int nodeHandle)929 final public int makeNodeIdentity(int nodeHandle) 930 { 931 if(NULL==nodeHandle) return NULL; 932 933 if(m_mgrDefault!=null) 934 { 935 // Optimization: use the DTMManagerDefault's fast DTMID-to-offsets 936 // table. I'm not wild about this solution but this operation 937 // needs need extreme speed. 938 939 int whichDTMindex=nodeHandle>>>DTMManager.IDENT_DTM_NODE_BITS; 940 941 // %REVIEW% Wish I didn't have to perform the pre-test, but 942 // someone is apparently asking DTMs whether they contain nodes 943 // which really don't belong to them. That's probably a bug 944 // which should be fixed, but until it is: 945 if(m_mgrDefault.m_dtms[whichDTMindex]!=this) 946 return NULL; 947 else 948 return 949 m_mgrDefault.m_dtm_offsets[whichDTMindex] 950 | (nodeHandle & DTMManager.IDENT_NODE_DEFAULT); 951 } 952 953 int whichDTMid=m_dtmIdent.indexOf(nodeHandle & DTMManager.IDENT_DTM_DEFAULT); 954 return (whichDTMid==NULL) 955 ? NULL 956 : (whichDTMid << DTMManager.IDENT_DTM_NODE_BITS) 957 + (nodeHandle & DTMManager.IDENT_NODE_DEFAULT); 958 } 959 960 961 /** 962 * Given a node handle, get the handle of the node's first child. 963 * If not yet resolved, waits for more nodes to be added to the document and 964 * tries again. 965 * 966 * @param nodeHandle int Handle of the node. 967 * @return int DTM node-number of first child, or DTM.NULL to indicate none exists. 968 */ getFirstChild(int nodeHandle)969 public int getFirstChild(int nodeHandle) 970 { 971 972 int identity = makeNodeIdentity(nodeHandle); 973 int firstChild = _firstch(identity); 974 975 return makeNodeHandle(firstChild); 976 } 977 978 /** 979 * Given a node handle, get the handle of the node's first child. 980 * If not yet resolved, waits for more nodes to be added to the document and 981 * tries again. 982 * 983 * @param nodeHandle int Handle of the node. 984 * @return int DTM node-number of first child, or DTM.NULL to indicate none exists. 985 */ getTypedFirstChild(int nodeHandle, int nodeType)986 public int getTypedFirstChild(int nodeHandle, int nodeType) 987 { 988 989 int firstChild, eType; 990 if (nodeType < DTM.NTYPES) { 991 for (firstChild = _firstch(makeNodeIdentity(nodeHandle)); 992 firstChild != DTM.NULL; 993 firstChild = _nextsib(firstChild)) { 994 eType = _exptype(firstChild); 995 if (eType == nodeType 996 || (eType >= DTM.NTYPES 997 && m_expandedNameTable.getType(eType) == nodeType)) { 998 return makeNodeHandle(firstChild); 999 } 1000 } 1001 } else { 1002 for (firstChild = _firstch(makeNodeIdentity(nodeHandle)); 1003 firstChild != DTM.NULL; 1004 firstChild = _nextsib(firstChild)) { 1005 if (_exptype(firstChild) == nodeType) { 1006 return makeNodeHandle(firstChild); 1007 } 1008 } 1009 } 1010 return DTM.NULL; 1011 } 1012 1013 /** 1014 * Given a node handle, advance to its last child. 1015 * If not yet resolved, waits for more nodes to be added to the document and 1016 * tries again. 1017 * 1018 * @param nodeHandle int Handle of the node. 1019 * @return int Node-number of last child, 1020 * or DTM.NULL to indicate none exists. 1021 */ getLastChild(int nodeHandle)1022 public int getLastChild(int nodeHandle) 1023 { 1024 1025 int identity = makeNodeIdentity(nodeHandle); 1026 int child = _firstch(identity); 1027 int lastChild = DTM.NULL; 1028 1029 while (child != DTM.NULL) 1030 { 1031 lastChild = child; 1032 child = _nextsib(child); 1033 } 1034 1035 return makeNodeHandle(lastChild); 1036 } 1037 1038 /** 1039 * Retrieves an attribute node by by qualified name and namespace URI. 1040 * 1041 * @param nodeHandle int Handle of the node upon which to look up this attribute.. 1042 * @param namespaceURI The namespace URI of the attribute to 1043 * retrieve, or null. 1044 * @param name The local name of the attribute to 1045 * retrieve. 1046 * @return The attribute node handle with the specified name ( 1047 * <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such 1048 * attribute. 1049 */ getAttributeNode(int nodeHandle, String namespaceURI, String name)1050 public abstract int getAttributeNode(int nodeHandle, String namespaceURI, 1051 String name); 1052 1053 /** 1054 * Given a node handle, get the index of the node's first attribute. 1055 * 1056 * @param nodeHandle int Handle of the node. 1057 * @return Handle of first attribute, or DTM.NULL to indicate none exists. 1058 */ getFirstAttribute(int nodeHandle)1059 public int getFirstAttribute(int nodeHandle) 1060 { 1061 int nodeID = makeNodeIdentity(nodeHandle); 1062 1063 return makeNodeHandle(getFirstAttributeIdentity(nodeID)); 1064 } 1065 1066 /** 1067 * Given a node identity, get the index of the node's first attribute. 1068 * 1069 * @param identity int identity of the node. 1070 * @return Identity of first attribute, or DTM.NULL to indicate none exists. 1071 */ getFirstAttributeIdentity(int identity)1072 protected int getFirstAttributeIdentity(int identity) { 1073 int type = _type(identity); 1074 1075 if (DTM.ELEMENT_NODE == type) 1076 { 1077 // Assume that attributes and namespaces immediately follow the element. 1078 while (DTM.NULL != (identity = getNextNodeIdentity(identity))) 1079 { 1080 1081 // Assume this can not be null. 1082 type = _type(identity); 1083 1084 if (type == DTM.ATTRIBUTE_NODE) 1085 { 1086 return identity; 1087 } 1088 else if (DTM.NAMESPACE_NODE != type) 1089 { 1090 break; 1091 } 1092 } 1093 } 1094 1095 return DTM.NULL; 1096 } 1097 1098 /** 1099 * Given a node handle and an expanded type ID, get the index of the node's 1100 * attribute of that type, if any. 1101 * 1102 * @param nodeHandle int Handle of the node. 1103 * @param attType int expanded type ID of the required attribute. 1104 * @return Handle of attribute of the required type, or DTM.NULL to indicate 1105 * none exists. 1106 */ getTypedAttribute(int nodeHandle, int attType)1107 protected int getTypedAttribute(int nodeHandle, int attType) { 1108 int type = getNodeType(nodeHandle); 1109 if (DTM.ELEMENT_NODE == type) { 1110 int identity = makeNodeIdentity(nodeHandle); 1111 1112 while (DTM.NULL != (identity = getNextNodeIdentity(identity))) 1113 { 1114 type = _type(identity); 1115 1116 if (type == DTM.ATTRIBUTE_NODE) 1117 { 1118 if (_exptype(identity) == attType) return makeNodeHandle(identity); 1119 } 1120 else if (DTM.NAMESPACE_NODE != type) 1121 { 1122 break; 1123 } 1124 } 1125 } 1126 1127 return DTM.NULL; 1128 } 1129 1130 /** 1131 * Given a node handle, advance to its next sibling. 1132 * If not yet resolved, waits for more nodes to be added to the document and 1133 * tries again. 1134 * @param nodeHandle int Handle of the node. 1135 * @return int Node-number of next sibling, 1136 * or DTM.NULL to indicate none exists. 1137 */ getNextSibling(int nodeHandle)1138 public int getNextSibling(int nodeHandle) 1139 { 1140 if (nodeHandle == DTM.NULL) 1141 return DTM.NULL; 1142 return makeNodeHandle(_nextsib(makeNodeIdentity(nodeHandle))); 1143 } 1144 1145 /** 1146 * Given a node handle, advance to its next sibling. 1147 * If not yet resolved, waits for more nodes to be added to the document and 1148 * tries again. 1149 * @param nodeHandle int Handle of the node. 1150 * @return int Node-number of next sibling, 1151 * or DTM.NULL to indicate none exists. 1152 */ getTypedNextSibling(int nodeHandle, int nodeType)1153 public int getTypedNextSibling(int nodeHandle, int nodeType) 1154 { 1155 if (nodeHandle == DTM.NULL) 1156 return DTM.NULL; 1157 int node = makeNodeIdentity(nodeHandle); 1158 int eType; 1159 while ((node = _nextsib(node)) != DTM.NULL && 1160 ((eType = _exptype(node)) != nodeType && 1161 m_expandedNameTable.getType(eType)!= nodeType)); 1162 //_type(node) != nodeType)); 1163 1164 return (node == DTM.NULL ? DTM.NULL : makeNodeHandle(node)); 1165 } 1166 1167 /** 1168 * Given a node handle, find its preceeding sibling. 1169 * WARNING: DTM is asymmetric; this operation is resolved by search, and is 1170 * relatively expensive. 1171 * 1172 * @param nodeHandle the id of the node. 1173 * @return int Node-number of the previous sib, 1174 * or DTM.NULL to indicate none exists. 1175 */ getPreviousSibling(int nodeHandle)1176 public int getPreviousSibling(int nodeHandle) 1177 { 1178 if (nodeHandle == DTM.NULL) 1179 return DTM.NULL; 1180 1181 if (m_prevsib != null) 1182 return makeNodeHandle(_prevsib(makeNodeIdentity(nodeHandle))); 1183 else 1184 { 1185 // If the previous sibling array is not built, we get at 1186 // the previous sibling using the parent, firstch and 1187 // nextsib arrays. 1188 int nodeID = makeNodeIdentity(nodeHandle); 1189 int parent = _parent(nodeID); 1190 int node = _firstch(parent); 1191 int result = DTM.NULL; 1192 while (node != nodeID) 1193 { 1194 result = node; 1195 node = _nextsib(node); 1196 } 1197 return makeNodeHandle(result); 1198 } 1199 } 1200 1201 /** 1202 * Given a node handle, advance to the next attribute. 1203 * If an attr, we advance to 1204 * the next attr on the same node. If not an attribute, we return NULL. 1205 * 1206 * @param nodeHandle int Handle of the node. 1207 * @return int DTM node-number of the resolved attr, 1208 * or DTM.NULL to indicate none exists. 1209 */ getNextAttribute(int nodeHandle)1210 public int getNextAttribute(int nodeHandle) { 1211 int nodeID = makeNodeIdentity(nodeHandle); 1212 1213 if (_type(nodeID) == DTM.ATTRIBUTE_NODE) { 1214 return makeNodeHandle(getNextAttributeIdentity(nodeID)); 1215 } 1216 1217 return DTM.NULL; 1218 } 1219 1220 /** 1221 * Given a node identity for an attribute, advance to the next attribute. 1222 * 1223 * @param identity int identity of the attribute node. This 1224 * <strong>must</strong> be an attribute node. 1225 * 1226 * @return int DTM node-identity of the resolved attr, 1227 * or DTM.NULL to indicate none exists. 1228 * 1229 */ getNextAttributeIdentity(int identity)1230 protected int getNextAttributeIdentity(int identity) { 1231 // Assume that attributes and namespace nodes immediately follow the element 1232 while (DTM.NULL != (identity = getNextNodeIdentity(identity))) { 1233 int type = _type(identity); 1234 1235 if (type == DTM.ATTRIBUTE_NODE) { 1236 return identity; 1237 } else if (type != DTM.NAMESPACE_NODE) { 1238 break; 1239 } 1240 } 1241 1242 return DTM.NULL; 1243 } 1244 1245 /** Lazily created namespace lists. */ 1246 private Vector m_namespaceLists = null; // on demand 1247 1248 1249 /** Build table of namespace declaration 1250 * locations during DTM construction. Table is a Vector of 1251 * SuballocatedIntVectors containing the namespace node HANDLES declared at 1252 * that ID, plus an SuballocatedIntVector of the element node INDEXES at which 1253 * these declarations appeared. 1254 * 1255 * NOTE: Since this occurs during model build, nodes will be encountered 1256 * in doucment order and thus the table will be ordered by element, 1257 * permitting binary-search as a possible retrieval optimization. 1258 * 1259 * %REVIEW% Directly managed arrays rather than vectors? 1260 * %REVIEW% Handles or IDs? Given usage, I think handles. 1261 * */ declareNamespaceInContext(int elementNodeIndex,int namespaceNodeIndex)1262 protected void declareNamespaceInContext(int elementNodeIndex,int namespaceNodeIndex) 1263 { 1264 SuballocatedIntVector nsList=null; 1265 if(m_namespaceDeclSets==null) 1266 { 1267 1268 // First 1269 m_namespaceDeclSetElements=new SuballocatedIntVector(32); 1270 m_namespaceDeclSetElements.addElement(elementNodeIndex); 1271 m_namespaceDeclSets=new Vector(); 1272 nsList=new SuballocatedIntVector(32); 1273 m_namespaceDeclSets.addElement(nsList); 1274 } 1275 else 1276 { 1277 // Most recent. May be -1 (none) if DTM was pruned. 1278 // %OPT% Is there a lastElement() method? Should there be? 1279 int last=m_namespaceDeclSetElements.size()-1; 1280 1281 if(last>=0 && elementNodeIndex==m_namespaceDeclSetElements.elementAt(last)) 1282 { 1283 nsList=(SuballocatedIntVector)m_namespaceDeclSets.elementAt(last); 1284 } 1285 } 1286 if(nsList==null) 1287 { 1288 m_namespaceDeclSetElements.addElement(elementNodeIndex); 1289 1290 SuballocatedIntVector inherited = 1291 findNamespaceContext(_parent(elementNodeIndex)); 1292 1293 if (inherited!=null) { 1294 // %OPT% Count-down might be faster, but debuggability may 1295 // be better this way, and if we ever decide we want to 1296 // keep this ordered by expanded-type... 1297 int isize=inherited.size(); 1298 1299 // Base the size of a new namespace list on the 1300 // size of the inherited list - but within reason! 1301 nsList=new SuballocatedIntVector(Math.max(Math.min(isize+16,2048), 1302 32)); 1303 1304 for(int i=0;i<isize;++i) 1305 { 1306 nsList.addElement(inherited.elementAt(i)); 1307 } 1308 } else { 1309 nsList=new SuballocatedIntVector(32); 1310 } 1311 1312 m_namespaceDeclSets.addElement(nsList); 1313 } 1314 1315 // Handle overwriting inherited. 1316 // %OPT% Keep sorted? (By expanded-name rather than by doc order...) 1317 // Downside: Would require insertElementAt if not found, 1318 // which has recopying costs. But these are generally short lists... 1319 int newEType=_exptype(namespaceNodeIndex); 1320 1321 for(int i=nsList.size()-1;i>=0;--i) 1322 { 1323 if(newEType==getExpandedTypeID(nsList.elementAt(i))) 1324 { 1325 nsList.setElementAt(makeNodeHandle(namespaceNodeIndex),i); 1326 return; 1327 } 1328 } 1329 nsList.addElement(makeNodeHandle(namespaceNodeIndex)); 1330 } 1331 1332 /** Retrieve list of namespace declaration locations 1333 * active at this node. List is an SuballocatedIntVector whose 1334 * entries are the namespace node HANDLES declared at that ID. 1335 * 1336 * %REVIEW% Directly managed arrays rather than vectors? 1337 * %REVIEW% Handles or IDs? Given usage, I think handles. 1338 * */ findNamespaceContext(int elementNodeIndex)1339 protected SuballocatedIntVector findNamespaceContext(int elementNodeIndex) 1340 { 1341 if (null!=m_namespaceDeclSetElements) 1342 { 1343 // %OPT% Is binary-search really saving us a lot versus linear? 1344 // (... It may be, in large docs with many NS decls.) 1345 int wouldBeAt=findInSortedSuballocatedIntVector(m_namespaceDeclSetElements, 1346 elementNodeIndex); 1347 if(wouldBeAt>=0) // Found it 1348 return (SuballocatedIntVector) m_namespaceDeclSets.elementAt(wouldBeAt); 1349 if(wouldBeAt == -1) // -1-wouldbeat == 0 1350 return null; // Not after anything; definitely not found 1351 1352 // Not found, but we know where it should have been. 1353 // Search back until we find an ancestor or run out. 1354 wouldBeAt=-1-wouldBeAt; 1355 1356 // Decrement wouldBeAt to find last possible ancestor 1357 int candidate=m_namespaceDeclSetElements.elementAt(-- wouldBeAt); 1358 int ancestor=_parent(elementNodeIndex); 1359 1360 // Special case: if the candidate is before the given node, and 1361 // is in the earliest possible position in the document, it 1362 // must have the namespace declarations we're interested in. 1363 if (wouldBeAt == 0 && candidate < ancestor) { 1364 int rootHandle = getDocumentRoot(makeNodeHandle(elementNodeIndex)); 1365 int rootID = makeNodeIdentity(rootHandle); 1366 int uppermostNSCandidateID; 1367 1368 if (getNodeType(rootHandle) == DTM.DOCUMENT_NODE) { 1369 int ch = _firstch(rootID); 1370 uppermostNSCandidateID = (ch != DTM.NULL) ? ch : rootID; 1371 } else { 1372 uppermostNSCandidateID = rootID; 1373 } 1374 1375 if (candidate == uppermostNSCandidateID) { 1376 return (SuballocatedIntVector)m_namespaceDeclSets.elementAt(wouldBeAt); 1377 } 1378 } 1379 1380 while(wouldBeAt>=0 && ancestor>0) 1381 { 1382 if (candidate==ancestor) { 1383 // Found ancestor in list 1384 return (SuballocatedIntVector)m_namespaceDeclSets.elementAt(wouldBeAt); 1385 } else if (candidate<ancestor) { 1386 // Too deep in tree 1387 do { 1388 ancestor=_parent(ancestor); 1389 } while (candidate < ancestor); 1390 } else if(wouldBeAt > 0){ 1391 // Too late in list 1392 candidate=m_namespaceDeclSetElements.elementAt(--wouldBeAt); 1393 } 1394 else 1395 break; 1396 } 1397 } 1398 1399 return null; // No namespaces known at this node 1400 } 1401 1402 /** 1403 * Subroutine: Locate the specified node within 1404 * m_namespaceDeclSetElements, or the last element which 1405 * preceeds it in document order 1406 * 1407 * %REVIEW% Inlne this into findNamespaceContext? Create SortedSuballocatedIntVector type? 1408 * 1409 * @return If positive or zero, the index of the found item. 1410 * If negative, index of the point at which it would have appeared, 1411 * encoded as -1-index and hence reconvertable by subtracting 1412 * it from -1. (Encoding because I don't want to recompare the strings 1413 * but don't want to burn bytes on a datatype to hold a flagged value.) 1414 */ findInSortedSuballocatedIntVector(SuballocatedIntVector vector, int lookfor)1415 protected int findInSortedSuballocatedIntVector(SuballocatedIntVector vector, int lookfor) 1416 { 1417 // Binary search 1418 int i = 0; 1419 if(vector != null) { 1420 int first = 0; 1421 int last = vector.size() - 1; 1422 1423 while (first <= last) { 1424 i = (first + last) / 2; 1425 int test = lookfor-vector.elementAt(i); 1426 if(test == 0) { 1427 return i; // Name found 1428 } 1429 else if (test < 0) { 1430 last = i - 1; // looked too late 1431 } 1432 else { 1433 first = i + 1; // looked ot early 1434 } 1435 } 1436 1437 if (first > i) { 1438 i = first; // Clean up at loop end 1439 } 1440 } 1441 1442 return -1 - i; // not-found has to be encoded. 1443 } 1444 1445 1446 /** 1447 * Given a node handle, get the index of the node's first child. 1448 * If not yet resolved, waits for more nodes to be added to the document and 1449 * tries again 1450 * 1451 * @param nodeHandle handle to node, which should probably be an element 1452 * node, but need not be. 1453 * 1454 * @param inScope true if all namespaces in scope should be returned, 1455 * false if only the namespace declarations should be 1456 * returned. 1457 * @return handle of first namespace, or DTM.NULL to indicate none exists. 1458 */ getFirstNamespaceNode(int nodeHandle, boolean inScope)1459 public int getFirstNamespaceNode(int nodeHandle, boolean inScope) 1460 { 1461 if(inScope) 1462 { 1463 int identity = makeNodeIdentity(nodeHandle); 1464 if (_type(identity) == DTM.ELEMENT_NODE) 1465 { 1466 SuballocatedIntVector nsContext=findNamespaceContext(identity); 1467 if(nsContext==null || nsContext.size()<1) 1468 return NULL; 1469 1470 return nsContext.elementAt(0); 1471 } 1472 else 1473 return NULL; 1474 } 1475 else 1476 { 1477 // Assume that attributes and namespaces immediately 1478 // follow the element. 1479 // 1480 // %OPT% Would things be faster if all NS nodes were built 1481 // before all Attr nodes? Some costs at build time for 2nd 1482 // pass... 1483 int identity = makeNodeIdentity(nodeHandle); 1484 if (_type(identity) == DTM.ELEMENT_NODE) 1485 { 1486 while (DTM.NULL != (identity = getNextNodeIdentity(identity))) 1487 { 1488 int type = _type(identity); 1489 if (type == DTM.NAMESPACE_NODE) 1490 return makeNodeHandle(identity); 1491 else if (DTM.ATTRIBUTE_NODE != type) 1492 break; 1493 } 1494 return NULL; 1495 } 1496 else 1497 return NULL; 1498 } 1499 } 1500 1501 /** 1502 * Given a namespace handle, advance to the next namespace. 1503 * 1504 * @param baseHandle handle to original node from where the first namespace 1505 * was relative to (needed to return nodes in document order). 1506 * @param nodeHandle A namespace handle for which we will find the next node. 1507 * @param inScope true if all namespaces that are in scope should be processed, 1508 * otherwise just process the nodes in the given element handle. 1509 * @return handle of next namespace, or DTM.NULL to indicate none exists. 1510 */ getNextNamespaceNode(int baseHandle, int nodeHandle, boolean inScope)1511 public int getNextNamespaceNode(int baseHandle, int nodeHandle, 1512 boolean inScope) 1513 { 1514 if(inScope) 1515 { 1516 //Since we've been given the base, try direct lookup 1517 //(could look from nodeHandle but this is at least one 1518 //comparison/get-parent faster) 1519 //SuballocatedIntVector nsContext=findNamespaceContext(nodeHandle & m_mask); 1520 1521 SuballocatedIntVector nsContext=findNamespaceContext(makeNodeIdentity(baseHandle)); 1522 1523 if(nsContext==null) 1524 return NULL; 1525 int i=1 + nsContext.indexOf(nodeHandle); 1526 if(i<=0 || i==nsContext.size()) 1527 return NULL; 1528 1529 return nsContext.elementAt(i); 1530 } 1531 else 1532 { 1533 // Assume that attributes and namespace nodes immediately follow the element. 1534 int identity = makeNodeIdentity(nodeHandle); 1535 while (DTM.NULL != (identity = getNextNodeIdentity(identity))) 1536 { 1537 int type = _type(identity); 1538 if (type == DTM.NAMESPACE_NODE) 1539 { 1540 return makeNodeHandle(identity); 1541 } 1542 else if (type != DTM.ATTRIBUTE_NODE) 1543 { 1544 break; 1545 } 1546 } 1547 } 1548 return DTM.NULL; 1549 } 1550 1551 /** 1552 * Given a node handle, find its parent node. 1553 * 1554 * @param nodeHandle the id of the node. 1555 * @return int Node-number of parent, 1556 * or DTM.NULL to indicate none exists. 1557 */ getParent(int nodeHandle)1558 public int getParent(int nodeHandle) 1559 { 1560 1561 int identity = makeNodeIdentity(nodeHandle); 1562 1563 if (identity > 0) 1564 return makeNodeHandle(_parent(identity)); 1565 else 1566 return DTM.NULL; 1567 } 1568 1569 /** 1570 * Find the Document node handle for the document currently under construction. 1571 * PLEASE NOTE that most people should use getOwnerDocument(nodeHandle) instead; 1572 * this version of the operation is primarily intended for use during negotiation 1573 * with the DTM Manager. 1574 * 1575 * @return int Node handle of document, which should always be valid. 1576 */ getDocument()1577 public int getDocument() 1578 { 1579 return m_dtmIdent.elementAt(0); // makeNodeHandle(0) 1580 } 1581 1582 /** 1583 * Given a node handle, find the owning document node. This has the exact 1584 * same semantics as the DOM Document method of the same name, in that if 1585 * the nodeHandle is a document node, it will return NULL. 1586 * 1587 * <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM 1588 * binding layer. Included here as a convenience function and to 1589 * aid porting of DOM code to DTM.</p> 1590 * 1591 * @param nodeHandle the id of the node. 1592 * @return int Node handle of owning document, or -1 if the node was a Docment 1593 */ getOwnerDocument(int nodeHandle)1594 public int getOwnerDocument(int nodeHandle) 1595 { 1596 1597 if (DTM.DOCUMENT_NODE == getNodeType(nodeHandle)) 1598 return DTM.NULL; 1599 1600 return getDocumentRoot(nodeHandle); 1601 } 1602 1603 /** 1604 * Given a node handle, find the owning document node. Unlike the DOM, 1605 * this considers the owningDocument of a Document to be itself. 1606 * 1607 * @param nodeHandle the id of the node. 1608 * @return int Node handle of owning document, or the nodeHandle if it is 1609 * a Document. 1610 */ getDocumentRoot(int nodeHandle)1611 public int getDocumentRoot(int nodeHandle) 1612 { 1613 return getManager().getDTM(nodeHandle).getDocument(); 1614 } 1615 1616 /** 1617 * Get the string-value of a node as a String object 1618 * (see http://www.w3.org/TR/xpath#data-model 1619 * for the definition of a node's string-value). 1620 * 1621 * @param nodeHandle The node ID. 1622 * 1623 * @return A string object that represents the string-value of the given node. 1624 */ getStringValue(int nodeHandle)1625 public abstract XMLString getStringValue(int nodeHandle); 1626 1627 /** 1628 * Get number of character array chunks in 1629 * the string-value of a node. 1630 * (see http://www.w3.org/TR/xpath#data-model 1631 * for the definition of a node's string-value). 1632 * Note that a single text node may have multiple text chunks. 1633 * 1634 * @param nodeHandle The node ID. 1635 * 1636 * @return number of character array chunks in 1637 * the string-value of a node. 1638 */ getStringValueChunkCount(int nodeHandle)1639 public int getStringValueChunkCount(int nodeHandle) 1640 { 1641 1642 // %TBD% 1643 error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//("getStringValueChunkCount not yet supported!"); 1644 1645 return 0; 1646 } 1647 1648 /** 1649 * Get a character array chunk in the string-value of a node. 1650 * (see http://www.w3.org/TR/xpath#data-model 1651 * for the definition of a node's string-value). 1652 * Note that a single text node may have multiple text chunks. 1653 * 1654 * @param nodeHandle The node ID. 1655 * @param chunkIndex Which chunk to get. 1656 * @param startAndLen An array of 2 where the start position and length of 1657 * the chunk will be returned. 1658 * 1659 * @return The character array reference where the chunk occurs. 1660 */ getStringValueChunk(int nodeHandle, int chunkIndex, int[] startAndLen)1661 public char[] getStringValueChunk(int nodeHandle, int chunkIndex, 1662 int[] startAndLen) 1663 { 1664 1665 // %TBD% 1666 error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"getStringValueChunk not yet supported!"); 1667 1668 return null; 1669 } 1670 1671 /** 1672 * Given a node handle, return an ID that represents the node's expanded name. 1673 * 1674 * @param nodeHandle The handle to the node in question. 1675 * 1676 * @return the expanded-name id of the node. 1677 */ getExpandedTypeID(int nodeHandle)1678 public int getExpandedTypeID(int nodeHandle) 1679 { 1680 // %REVIEW% This _should_ only be null if someone asked the wrong DTM about the node... 1681 // which one would hope would never happen... 1682 int id=makeNodeIdentity(nodeHandle); 1683 if(id==NULL) 1684 return NULL; 1685 return _exptype(id); 1686 } 1687 1688 /** 1689 * Given an expanded name, return an ID. If the expanded-name does not 1690 * exist in the internal tables, the entry will be created, and the ID will 1691 * be returned. Any additional nodes that are created that have this 1692 * expanded name will use this ID. 1693 * 1694 * @param type The simple type, i.e. one of ELEMENT, ATTRIBUTE, etc. 1695 * 1696 * @param namespace The namespace URI, which may be null, may be an empty 1697 * string (which will be the same as null), or may be a 1698 * namespace URI. 1699 * @param localName The local name string, which must be a valid 1700 * <a href="http://www.w3.org/TR/REC-xml-names/">NCName</a>. 1701 * 1702 * @return the expanded-name id of the node. 1703 */ getExpandedTypeID(String namespace, String localName, int type)1704 public int getExpandedTypeID(String namespace, String localName, int type) 1705 { 1706 1707 ExpandedNameTable ent = m_expandedNameTable; 1708 1709 return ent.getExpandedTypeID(namespace, localName, type); 1710 } 1711 1712 /** 1713 * Given an expanded-name ID, return the local name part. 1714 * 1715 * @param expandedNameID an ID that represents an expanded-name. 1716 * @return String Local name of this node. 1717 */ getLocalNameFromExpandedNameID(int expandedNameID)1718 public String getLocalNameFromExpandedNameID(int expandedNameID) 1719 { 1720 return m_expandedNameTable.getLocalName(expandedNameID); 1721 } 1722 1723 /** 1724 * Given an expanded-name ID, return the namespace URI part. 1725 * 1726 * @param expandedNameID an ID that represents an expanded-name. 1727 * @return String URI value of this node's namespace, or null if no 1728 * namespace was resolved. 1729 */ getNamespaceFromExpandedNameID(int expandedNameID)1730 public String getNamespaceFromExpandedNameID(int expandedNameID) 1731 { 1732 return m_expandedNameTable.getNamespace(expandedNameID); 1733 } 1734 1735 /** 1736 * Returns the namespace type of a specific node 1737 * @param nodeHandle the id of the node. 1738 * @return the ID of the namespace. 1739 */ getNamespaceType(final int nodeHandle)1740 public int getNamespaceType(final int nodeHandle) 1741 { 1742 1743 int identity = makeNodeIdentity(nodeHandle); 1744 int expandedNameID = _exptype(identity); 1745 1746 return m_expandedNameTable.getNamespaceID(expandedNameID); 1747 } 1748 1749 /** 1750 * Given a node handle, return its DOM-style node name. This will 1751 * include names such as #text or #document. 1752 * 1753 * @param nodeHandle the id of the node. 1754 * @return String Name of this node, which may be an empty string. 1755 * %REVIEW% Document when empty string is possible... 1756 * %REVIEW-COMMENT% It should never be empty, should it? 1757 */ getNodeName(int nodeHandle)1758 public abstract String getNodeName(int nodeHandle); 1759 1760 /** 1761 * Given a node handle, return the XPath node name. This should be 1762 * the name as described by the XPath data model, NOT the DOM-style 1763 * name. 1764 * 1765 * @param nodeHandle the id of the node. 1766 * @return String Name of this node, which may be an empty string. 1767 */ getNodeNameX(int nodeHandle)1768 public String getNodeNameX(int nodeHandle) 1769 { 1770 1771 /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */ 1772 error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!"); 1773 1774 return null; 1775 } 1776 1777 /** 1778 * Given a node handle, return its XPath-style localname. 1779 * (As defined in Namespaces, this is the portion of the name after any 1780 * colon character). 1781 * 1782 * @param nodeHandle the id of the node. 1783 * @return String Local name of this node. 1784 */ getLocalName(int nodeHandle)1785 public abstract String getLocalName(int nodeHandle); 1786 1787 /** 1788 * Given a namespace handle, return the prefix that the namespace decl is 1789 * mapping. 1790 * Given a node handle, return the prefix used to map to the namespace. 1791 * 1792 * <p> %REVIEW% Are you sure you want "" for no prefix? </p> 1793 * <p> %REVIEW-COMMENT% I think so... not totally sure. -sb </p> 1794 * 1795 * @param nodeHandle the id of the node. 1796 * @return String prefix of this node's name, or "" if no explicit 1797 * namespace prefix was given. 1798 */ getPrefix(int nodeHandle)1799 public abstract String getPrefix(int nodeHandle); 1800 1801 /** 1802 * Given a node handle, return its DOM-style namespace URI 1803 * (As defined in Namespaces, this is the declared URI which this node's 1804 * prefix -- or default in lieu thereof -- was mapped to.) 1805 * 1806 * <p>%REVIEW% Null or ""? -sb</p> 1807 * 1808 * @param nodeHandle the id of the node. 1809 * @return String URI value of this node's namespace, or null if no 1810 * namespace was resolved. 1811 */ getNamespaceURI(int nodeHandle)1812 public abstract String getNamespaceURI(int nodeHandle); 1813 1814 /** 1815 * Given a node handle, return its node value. This is mostly 1816 * as defined by the DOM, but may ignore some conveniences. 1817 * <p> 1818 * 1819 * @param nodeHandle The node id. 1820 * @return String Value of this node, or null if not 1821 * meaningful for this node type. 1822 */ getNodeValue(int nodeHandle)1823 public abstract String getNodeValue(int nodeHandle); 1824 1825 /** 1826 * Given a node handle, return its DOM-style node type. 1827 * <p> 1828 * %REVIEW% Generally, returning short is false economy. Return int? 1829 * %REVIEW% Make assumption that node has already arrived. Is OK? 1830 * 1831 * @param nodeHandle The node id. 1832 * @return int Node type, as per the DOM's Node._NODE constants. 1833 */ getNodeType(int nodeHandle)1834 public short getNodeType(int nodeHandle) 1835 { 1836 if (nodeHandle == DTM.NULL) 1837 return DTM.NULL; 1838 return m_expandedNameTable.getType(_exptype(makeNodeIdentity(nodeHandle))); 1839 } 1840 1841 /** 1842 * Get the depth level of this node in the tree (equals 1 for 1843 * a parentless node). 1844 * 1845 * @param nodeHandle The node id. 1846 * @return the number of ancestors, plus one 1847 * @xsl.usage internal 1848 */ getLevel(int nodeHandle)1849 public short getLevel(int nodeHandle) 1850 { 1851 // Apparently, the axis walker stuff requires levels to count from 1. 1852 int identity = makeNodeIdentity(nodeHandle); 1853 return (short) (_level(identity) + 1); 1854 } 1855 1856 /** 1857 * Get the identity of this node in the tree 1858 * 1859 * @param nodeHandle The node handle. 1860 * @return the node identity 1861 * @xsl.usage internal 1862 */ getNodeIdent(int nodeHandle)1863 public int getNodeIdent(int nodeHandle) 1864 { 1865 /*if (nodeHandle != DTM.NULL) 1866 return nodeHandle & m_mask; 1867 else 1868 return DTM.NULL;*/ 1869 1870 return makeNodeIdentity(nodeHandle); 1871 } 1872 1873 /** 1874 * Get the handle of this node in the tree 1875 * 1876 * @param nodeId The node identity. 1877 * @return the node handle 1878 * @xsl.usage internal 1879 */ getNodeHandle(int nodeId)1880 public int getNodeHandle(int nodeId) 1881 { 1882 /*if (nodeId != DTM.NULL) 1883 return nodeId | m_dtmIdent; 1884 else 1885 return DTM.NULL;*/ 1886 1887 return makeNodeHandle(nodeId); 1888 } 1889 1890 // ============== Document query functions ============== 1891 1892 /** 1893 * Tests whether DTM DOM implementation implements a specific feature and 1894 * that feature is supported by this node. 1895 * 1896 * @param feature The name of the feature to test. 1897 * @param version This is the version number of the feature to test. 1898 * If the version is not 1899 * specified, supporting any version of the feature will cause the 1900 * method to return <code>true</code>. 1901 * @return Returns <code>true</code> if the specified feature is 1902 * supported on this node, <code>false</code> otherwise. 1903 */ isSupported(String feature, String version)1904 public boolean isSupported(String feature, String version) 1905 { 1906 1907 // %TBD% 1908 return false; 1909 } 1910 1911 /** 1912 * Return the base URI of the document entity. If it is not known 1913 * (because the document was parsed from a socket connection or from 1914 * standard input, for example), the value of this property is unknown. 1915 * 1916 * @return the document base URI String object or null if unknown. 1917 */ getDocumentBaseURI()1918 public String getDocumentBaseURI() 1919 { 1920 return m_documentBaseURI; 1921 } 1922 1923 /** 1924 * Set the base URI of the document entity. 1925 * 1926 * @param baseURI the document base URI String object or null if unknown. 1927 */ setDocumentBaseURI(String baseURI)1928 public void setDocumentBaseURI(String baseURI) 1929 { 1930 m_documentBaseURI = baseURI; 1931 } 1932 1933 /** 1934 * Return the system identifier of the document entity. If 1935 * it is not known, the value of this property is unknown. 1936 * 1937 * @param nodeHandle The node id, which can be any valid node handle. 1938 * @return the system identifier String object or null if unknown. 1939 */ getDocumentSystemIdentifier(int nodeHandle)1940 public String getDocumentSystemIdentifier(int nodeHandle) 1941 { 1942 1943 // %REVIEW% OK? -sb 1944 return m_documentBaseURI; 1945 } 1946 1947 /** 1948 * Return the name of the character encoding scheme 1949 * in which the document entity is expressed. 1950 * 1951 * @param nodeHandle The node id, which can be any valid node handle. 1952 * @return the document encoding String object. 1953 * @xsl.usage internal 1954 */ getDocumentEncoding(int nodeHandle)1955 public String getDocumentEncoding(int nodeHandle) 1956 { 1957 1958 // %REVIEW% OK?? -sb 1959 return "UTF-8"; 1960 } 1961 1962 /** 1963 * Return an indication of the standalone status of the document, 1964 * either "yes" or "no". This property is derived from the optional 1965 * standalone document declaration in the XML declaration at the 1966 * beginning of the document entity, and has no value if there is no 1967 * standalone document declaration. 1968 * 1969 * @param nodeHandle The node id, which can be any valid node handle. 1970 * @return the document standalone String object, either "yes", "no", or null. 1971 */ getDocumentStandalone(int nodeHandle)1972 public String getDocumentStandalone(int nodeHandle) 1973 { 1974 return null; 1975 } 1976 1977 /** 1978 * Return a string representing the XML version of the document. This 1979 * property is derived from the XML declaration optionally present at the 1980 * beginning of the document entity, and has no value if there is no XML 1981 * declaration. 1982 * 1983 * @param documentHandle The document handle 1984 * 1985 * @return the document version String object. 1986 */ getDocumentVersion(int documentHandle)1987 public String getDocumentVersion(int documentHandle) 1988 { 1989 return null; 1990 } 1991 1992 /** 1993 * Return an indication of 1994 * whether the processor has read the complete DTD. Its value is a 1995 * boolean. If it is false, then certain properties (indicated in their 1996 * descriptions below) may be unknown. If it is true, those properties 1997 * are never unknown. 1998 * 1999 * @return <code>true</code> if all declarations were processed; 2000 * <code>false</code> otherwise. 2001 */ getDocumentAllDeclarationsProcessed()2002 public boolean getDocumentAllDeclarationsProcessed() 2003 { 2004 2005 // %REVIEW% OK? 2006 return true; 2007 } 2008 2009 /** 2010 * A document type declaration information item has the following properties: 2011 * 2012 * 1. [system identifier] The system identifier of the external subset, if 2013 * it exists. Otherwise this property has no value. 2014 * 2015 * @return the system identifier String object, or null if there is none. 2016 */ getDocumentTypeDeclarationSystemIdentifier()2017 public abstract String getDocumentTypeDeclarationSystemIdentifier(); 2018 2019 /** 2020 * Return the public identifier of the external subset, 2021 * normalized as described in 4.2.2 External Entities [XML]. If there is 2022 * no external subset or if it has no public identifier, this property 2023 * has no value. 2024 * 2025 * @return the public identifier String object, or null if there is none. 2026 */ getDocumentTypeDeclarationPublicIdentifier()2027 public abstract String getDocumentTypeDeclarationPublicIdentifier(); 2028 2029 /** 2030 * Returns the <code>Element</code> whose <code>ID</code> is given by 2031 * <code>elementId</code>. If no such element exists, returns 2032 * <code>DTM.NULL</code>. Behavior is not defined if more than one element 2033 * has this <code>ID</code>. Attributes (including those 2034 * with the name "ID") are not of type ID unless so defined by DTD/Schema 2035 * information available to the DTM implementation. 2036 * Implementations that do not know whether attributes are of type ID or 2037 * not are expected to return <code>DTM.NULL</code>. 2038 * 2039 * <p>%REVIEW% Presumably IDs are still scoped to a single document, 2040 * and this operation searches only within a single document, right? 2041 * Wouldn't want collisions between DTMs in the same process.</p> 2042 * 2043 * @param elementId The unique <code>id</code> value for an element. 2044 * @return The handle of the matching element. 2045 */ getElementById(String elementId)2046 public abstract int getElementById(String elementId); 2047 2048 /** 2049 * The getUnparsedEntityURI function returns the URI of the unparsed 2050 * entity with the specified name in the same document as the context 2051 * node (see [3.3 Unparsed Entities]). It returns the empty string if 2052 * there is no such entity. 2053 * <p> 2054 * XML processors may choose to use the System Identifier (if one 2055 * is provided) to resolve the entity, rather than the URI in the 2056 * Public Identifier. The details are dependent on the processor, and 2057 * we would have to support some form of plug-in resolver to handle 2058 * this properly. Currently, we simply return the System Identifier if 2059 * present, and hope that it a usable URI or that our caller can 2060 * map it to one. 2061 * TODO: Resolve Public Identifiers... or consider changing function name. 2062 * <p> 2063 * If we find a relative URI 2064 * reference, XML expects it to be resolved in terms of the base URI 2065 * of the document. The DOM doesn't do that for us, and it isn't 2066 * entirely clear whether that should be done here; currently that's 2067 * pushed up to a higher level of our application. (Note that DOM Level 2068 * 1 didn't store the document's base URI.) 2069 * TODO: Consider resolving Relative URIs. 2070 * <p> 2071 * (The DOM's statement that "An XML processor may choose to 2072 * completely expand entities before the structure model is passed 2073 * to the DOM" refers only to parsed entities, not unparsed, and hence 2074 * doesn't affect this function.) 2075 * 2076 * @param name A string containing the Entity Name of the unparsed 2077 * entity. 2078 * 2079 * @return String containing the URI of the Unparsed Entity, or an 2080 * empty string if no such entity exists. 2081 */ getUnparsedEntityURI(String name)2082 public abstract String getUnparsedEntityURI(String name); 2083 2084 // ============== Boolean methods ================ 2085 2086 /** 2087 * Return true if the xsl:strip-space or xsl:preserve-space was processed 2088 * during construction of the DTM document. 2089 * 2090 * @return true if this DTM supports prestripping. 2091 */ supportsPreStripping()2092 public boolean supportsPreStripping() 2093 { 2094 return true; 2095 } 2096 2097 /** 2098 * Figure out whether nodeHandle2 should be considered as being later 2099 * in the document than nodeHandle1, in Document Order as defined 2100 * by the XPath model. This may not agree with the ordering defined 2101 * by other XML applications. 2102 * <p> 2103 * There are some cases where ordering isn't defined, and neither are 2104 * the results of this function -- though we'll generally return false. 2105 * 2106 * @param nodeHandle1 Node handle to perform position comparison on. 2107 * @param nodeHandle2 Second Node handle to perform position comparison on . 2108 * 2109 * @return true if node1 comes before node2, otherwise return false. 2110 * You can think of this as 2111 * <code>(node1.documentOrderPosition <= node2.documentOrderPosition)</code>. 2112 */ isNodeAfter(int nodeHandle1, int nodeHandle2)2113 public boolean isNodeAfter(int nodeHandle1, int nodeHandle2) 2114 { 2115 // These return NULL if the node doesn't belong to this document. 2116 int index1 = makeNodeIdentity(nodeHandle1); 2117 int index2 = makeNodeIdentity(nodeHandle2); 2118 2119 return index1!=NULL && index2!=NULL && index1 <= index2; 2120 } 2121 2122 /** 2123 * 2. [element content whitespace] A boolean indicating whether the 2124 * character is white space appearing within element content (see [XML], 2125 * 2.10 "White Space Handling"). Note that validating XML processors are 2126 * required by XML 1.0 to provide this information. If there is no 2127 * declaration for the containing element, this property has no value for 2128 * white space characters. If no declaration has been read, but the [all 2129 * declarations processed] property of the document information item is 2130 * false (so there may be an unread declaration), then the value of this 2131 * property is unknown for white space characters. It is always false for 2132 * characters that are not white space. 2133 * 2134 * @param nodeHandle the node ID. 2135 * @return <code>true</code> if the character data is whitespace; 2136 * <code>false</code> otherwise. 2137 */ isCharacterElementContentWhitespace(int nodeHandle)2138 public boolean isCharacterElementContentWhitespace(int nodeHandle) 2139 { 2140 2141 // %TBD% 2142 return false; 2143 } 2144 2145 /** 2146 * 10. [all declarations processed] This property is not strictly speaking 2147 * part of the infoset of the document. Rather it is an indication of 2148 * whether the processor has read the complete DTD. Its value is a 2149 * boolean. If it is false, then certain properties (indicated in their 2150 * descriptions below) may be unknown. If it is true, those properties 2151 * are never unknown. 2152 * 2153 * @param documentHandle A node handle that must identify a document. 2154 * @return <code>true</code> if all declarations were processed; 2155 * <code>false</code> otherwise. 2156 */ isDocumentAllDeclarationsProcessed(int documentHandle)2157 public boolean isDocumentAllDeclarationsProcessed(int documentHandle) 2158 { 2159 return true; 2160 } 2161 2162 /** 2163 * 5. [specified] A flag indicating whether this attribute was actually 2164 * specified in the start-tag of its element, or was defaulted from the 2165 * DTD. 2166 * 2167 * @param attributeHandle The attribute handle in question. 2168 * 2169 * @return <code>true</code> if the attribute was specified; 2170 * <code>false</code> if it was defaulted. 2171 */ isAttributeSpecified(int attributeHandle)2172 public abstract boolean isAttributeSpecified(int attributeHandle); 2173 2174 // ========== Direct SAX Dispatch, for optimization purposes ======== 2175 2176 /** 2177 * Directly call the 2178 * characters method on the passed ContentHandler for the 2179 * string-value of the given node (see http://www.w3.org/TR/xpath#data-model 2180 * for the definition of a node's string-value). Multiple calls to the 2181 * ContentHandler's characters methods may well occur for a single call to 2182 * this method. 2183 * 2184 * @param nodeHandle The node ID. 2185 * @param ch A non-null reference to a ContentHandler. 2186 * @param normalize true if the content should be normalized according to 2187 * the rules for the XPath 2188 * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a> 2189 * function. 2190 * 2191 * @throws org.xml.sax.SAXException 2192 */ dispatchCharactersEvents( int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize)2193 public abstract void dispatchCharactersEvents( 2194 int nodeHandle, org.xml.sax.ContentHandler ch, boolean normalize) 2195 throws org.xml.sax.SAXException; 2196 2197 /** 2198 * Directly create SAX parser events from a subtree. 2199 * 2200 * @param nodeHandle The node ID. 2201 * @param ch A non-null reference to a ContentHandler. 2202 * 2203 * @throws org.xml.sax.SAXException 2204 */ dispatchToEvents( int nodeHandle, org.xml.sax.ContentHandler ch)2205 public abstract void dispatchToEvents( 2206 int nodeHandle, org.xml.sax.ContentHandler ch) 2207 throws org.xml.sax.SAXException; 2208 2209 /** 2210 * Return an DOM node for the given node. 2211 * 2212 * @param nodeHandle The node ID. 2213 * 2214 * @return A node representation of the DTM node. 2215 */ getNode(int nodeHandle)2216 public org.w3c.dom.Node getNode(int nodeHandle) 2217 { 2218 return new DTMNodeProxy(this, nodeHandle); 2219 } 2220 2221 // ==== Construction methods (may not be supported by some implementations!) ===== 2222 2223 /** 2224 * Append a child to the end of the document. Please note that the node 2225 * is always cloned if it is owned by another document. 2226 * 2227 * <p>%REVIEW% "End of the document" needs to be defined more clearly. 2228 * Does it become the last child of the Document? Of the root element?</p> 2229 * 2230 * @param newChild Must be a valid new node handle. 2231 * @param clone true if the child should be cloned into the document. 2232 * @param cloneDepth if the clone argument is true, specifies that the 2233 * clone should include all it's children. 2234 */ appendChild(int newChild, boolean clone, boolean cloneDepth)2235 public void appendChild(int newChild, boolean clone, boolean cloneDepth) 2236 { 2237 error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendChild not yet supported!"); 2238 } 2239 2240 /** 2241 * Append a text node child that will be constructed from a string, 2242 * to the end of the document. 2243 * 2244 * <p>%REVIEW% "End of the document" needs to be defined more clearly. 2245 * Does it become the last child of the Document? Of the root element?</p> 2246 * 2247 * @param str Non-null reverence to a string. 2248 */ appendTextChild(String str)2249 public void appendTextChild(String str) 2250 { 2251 error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"appendTextChild not yet supported!"); 2252 } 2253 2254 /** 2255 * Simple error for asserts and the like. 2256 * 2257 * @param msg Error message to report. 2258 */ error(String msg)2259 protected void error(String msg) 2260 { 2261 throw new DTMException(msg); 2262 } 2263 2264 /** 2265 * Find out whether or not to strip whispace nodes. 2266 * 2267 * 2268 * @return whether or not to strip whispace nodes. 2269 */ getShouldStripWhitespace()2270 protected boolean getShouldStripWhitespace() 2271 { 2272 return m_shouldStripWS; 2273 } 2274 2275 /** 2276 * Set whether to strip whitespaces and push in current value of 2277 * m_shouldStripWS in m_shouldStripWhitespaceStack. 2278 * 2279 * @param shouldStrip Flag indicating whether to strip whitespace nodes 2280 */ pushShouldStripWhitespace(boolean shouldStrip)2281 protected void pushShouldStripWhitespace(boolean shouldStrip) 2282 { 2283 2284 m_shouldStripWS = shouldStrip; 2285 2286 if (null != m_shouldStripWhitespaceStack) 2287 m_shouldStripWhitespaceStack.push(shouldStrip); 2288 } 2289 2290 /** 2291 * Set whether to strip whitespaces at this point by popping out 2292 * m_shouldStripWhitespaceStack. 2293 * 2294 */ popShouldStripWhitespace()2295 protected void popShouldStripWhitespace() 2296 { 2297 if (null != m_shouldStripWhitespaceStack) 2298 m_shouldStripWS = m_shouldStripWhitespaceStack.popAndTop(); 2299 } 2300 2301 /** 2302 * Set whether to strip whitespaces and set the top of the stack to 2303 * the current value of m_shouldStripWS. 2304 * 2305 * 2306 * @param shouldStrip Flag indicating whether to strip whitespace nodes 2307 */ setShouldStripWhitespace(boolean shouldStrip)2308 protected void setShouldStripWhitespace(boolean shouldStrip) 2309 { 2310 2311 m_shouldStripWS = shouldStrip; 2312 2313 if (null != m_shouldStripWhitespaceStack) 2314 m_shouldStripWhitespaceStack.setTop(shouldStrip); 2315 } 2316 2317 /** 2318 * A dummy routine to satisify the abstract interface. If the DTM 2319 * implememtation that extends the default base requires notification 2320 * of registration, they can override this method. 2321 */ documentRegistration()2322 public void documentRegistration() 2323 { 2324 } 2325 2326 /** 2327 * A dummy routine to satisify the abstract interface. If the DTM 2328 * implememtation that extends the default base requires notification 2329 * when the document is being released, they can override this method 2330 */ documentRelease()2331 public void documentRelease() 2332 { 2333 } 2334 2335 /** 2336 * Migrate a DTM built with an old DTMManager to a new DTMManager. 2337 * After the migration, the new DTMManager will treat the DTM as 2338 * one that is built by itself. 2339 * This is used to support DTM sharing between multiple transformations. 2340 * @param mgr the DTMManager 2341 */ migrateTo(DTMManager mgr)2342 public void migrateTo(DTMManager mgr) 2343 { 2344 m_mgr = mgr; 2345 if(mgr instanceof DTMManagerDefault) 2346 m_mgrDefault=(DTMManagerDefault)mgr; 2347 } 2348 2349 /** Query which DTMManager this DTM is currently being handled by. 2350 * 2351 * %REVEW% Should this become part of the base DTM API? 2352 * 2353 * @return a DTMManager, or null if this is a "stand-alone" DTM. 2354 */ getManager()2355 public DTMManager getManager() 2356 { 2357 return m_mgr; 2358 } 2359 2360 /** Query which DTMIDs this DTM is currently using within the DTMManager. 2361 * 2362 * %REVEW% Should this become part of the base DTM API? 2363 * 2364 * @return an IntVector, or null if this is a "stand-alone" DTM. 2365 */ getDTMIDs()2366 public SuballocatedIntVector getDTMIDs() 2367 { 2368 if(m_mgr==null) return null; 2369 return m_dtmIdent; 2370 } 2371 } 2372