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