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