1 /* 2 * Copyright (c) 2015, 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.xalan.internal.xsltc.dom; 22 23 import com.sun.org.apache.xalan.internal.xsltc.DOM; 24 import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM; 25 import com.sun.org.apache.xalan.internal.xsltc.StripFilter; 26 import com.sun.org.apache.xalan.internal.xsltc.TransletException; 27 import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary; 28 import com.sun.org.apache.xml.internal.dtm.Axis; 29 import com.sun.org.apache.xml.internal.dtm.DTM; 30 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 31 import com.sun.org.apache.xml.internal.dtm.DTMManager; 32 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter; 33 import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIterNodeList; 34 import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; 35 import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeProxy; 36 import com.sun.org.apache.xml.internal.dtm.ref.EmptyIterator; 37 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM2; 38 import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 39 import com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler; 40 import com.sun.org.apache.xml.internal.utils.SystemIDResolver; 41 import com.sun.org.apache.xml.internal.utils.XMLStringFactory; 42 import java.util.HashMap; 43 import java.util.Map; 44 import javax.xml.transform.Source; 45 import javax.xml.transform.dom.DOMSource; 46 import org.w3c.dom.Document; 47 import org.w3c.dom.DocumentType; 48 import org.w3c.dom.Entity; 49 import org.w3c.dom.NamedNodeMap; 50 import org.w3c.dom.Node; 51 import org.w3c.dom.NodeList; 52 import org.xml.sax.Attributes; 53 import org.xml.sax.SAXException; 54 55 56 /** 57 * SAXImpl is the core model for SAX input source. SAXImpl objects are 58 * usually created from an XSLTCDTMManager. 59 * 60 * <p>DOMSource inputs are handled using DOM2SAX + SAXImpl. SAXImpl has a 61 * few specific fields (e.g. _node2Ids, _document) to keep DOM-related 62 * information. They are used when the processing behavior between DOM and 63 * SAX has to be different. Examples of these include id function and 64 * unparsed entity. 65 * 66 * <p>SAXImpl extends SAX2DTM2 instead of SAX2DTM for better performance. 67 * @author Jacek Ambroziak 68 * @author Santiago Pericas-Geertsen 69 * @author Morten Jorgensen 70 * @author Douglas Sellers <douglasjsellers@hotmail.com> 71 * @LastModified: Oct 2017 72 */ 73 public final class SAXImpl extends SAX2DTM2 74 implements DOMEnhancedForDTM, DOMBuilder 75 { 76 77 /* ------------------------------------------------------------------- */ 78 /* DOMBuilder fields BEGIN */ 79 /* ------------------------------------------------------------------- */ 80 81 // Namespace prefix-to-uri mapping stuff 82 private int _uriCount = 0; 83 // private int _prefixCount = 0; 84 85 // Stack used to keep track of what whitespace text nodes are protected 86 // by xml:space="preserve" attributes and which nodes that are not. 87 private int[] _xmlSpaceStack; 88 private int _idx = 1; 89 private boolean _preserve = false; 90 91 // private static final String XML_STRING = "xml:"; 92 private static final String XML_PREFIX = "xml"; 93 private static final String XMLSPACE_STRING = "xml:space"; 94 private static final String PRESERVE_STRING = "preserve"; 95 // private static final String XMLNS_PREFIX = "xmlns"; 96 private static final String XML_URI = "http://www.w3.org/XML/1998/namespace"; 97 98 private boolean _escaping = true; 99 private boolean _disableEscaping = false; 100 private int _textNodeToProcess = DTM.NULL; 101 102 /* ------------------------------------------------------------------- */ 103 /* DOMBuilder fields END */ 104 /* ------------------------------------------------------------------- */ 105 106 // empty String for null attribute values 107 private final static String EMPTYSTRING = ""; 108 109 // empty iterator to be returned when there are no children 110 private final static DTMAxisIterator EMPTYITERATOR = EmptyIterator.getInstance(); 111 // The number of expanded names 112 private int _namesSize = -1; 113 114 // Namespace related stuff 115 private Map<Integer, Integer> _nsIndex = new HashMap<>(); 116 117 // The initial size of the text buffer 118 private int _size = 0; 119 120 // Tracks which textnodes are not escaped 121 private BitArray _dontEscape = null; 122 123 // The URI to this document 124 // private String _documentURI = null; 125 static private int _documentURIIndex = 0; 126 127 // The owner Document when the input source is DOMSource. 128 private Document _document; 129 130 // The Map for org.w3c.dom.Node to node id mapping. 131 // This is only used when the input is a DOMSource and the 132 // buildIdIndex flag is true. 133 private Map<Node, Integer> _node2Ids = null; 134 135 // True if the input source is a DOMSource. 136 private boolean _hasDOMSource = false; 137 138 // The DTMManager 139 private XSLTCDTMManager _dtmManager; 140 141 // Support for access/navigation through org.w3c.dom API 142 private Node[] _nodes; 143 private NodeList[] _nodeLists; 144 // private final static String XML_LANG_ATTRIBUTE = "http://www.w3.org/XML/1998/namespace:@lang"; 145 146 /** 147 * Define the origin of the document from which the tree was built 148 */ setDocumentURI(String uri)149 public void setDocumentURI(String uri) { 150 if (uri != null) { 151 setDocumentBaseURI(SystemIDResolver.getAbsoluteURI(uri)); 152 } 153 } 154 155 /** 156 * Returns the origin of the document from which the tree was built 157 */ getDocumentURI()158 public String getDocumentURI() { 159 String baseURI = getDocumentBaseURI(); 160 return (baseURI != null) ? baseURI : "rtf" + _documentURIIndex++; 161 } 162 getDocumentURI(int node)163 public String getDocumentURI(int node) { 164 return getDocumentURI(); 165 } 166 setupMapping(String[] names, String[] urisArray, int[] typesArray, String[] namespaces)167 public void setupMapping(String[] names, String[] urisArray, 168 int[] typesArray, String[] namespaces) { 169 // This method only has a function in DOM adapters 170 } 171 172 /** 173 * Lookup a namespace URI from a prefix starting at node. This method 174 * is used in the execution of xsl:element when the prefix is not known 175 * at compile time. 176 */ lookupNamespace(int node, String prefix)177 public String lookupNamespace(int node, String prefix) 178 throws TransletException 179 { 180 int anode, nsnode; 181 final AncestorIterator ancestors = new AncestorIterator(); 182 183 if (isElement(node)) { 184 ancestors.includeSelf(); 185 } 186 187 ancestors.setStartNode(node); 188 while ((anode = ancestors.next()) != DTM.NULL) { 189 final NamespaceIterator namespaces = new NamespaceIterator(); 190 191 namespaces.setStartNode(anode); 192 while ((nsnode = namespaces.next()) != DTM.NULL) { 193 if (getLocalName(nsnode).equals(prefix)) { 194 return getNodeValue(nsnode); 195 } 196 } 197 } 198 199 BasisLibrary.runTimeError(BasisLibrary.NAMESPACE_PREFIX_ERR, prefix); 200 return null; 201 } 202 203 /** 204 * Returns 'true' if a specific node is an element (of any type) 205 */ isElement(final int node)206 public boolean isElement(final int node) { 207 return getNodeType(node) == DTM.ELEMENT_NODE; 208 } 209 210 /** 211 * Returns 'true' if a specific node is an attribute (of any type) 212 */ isAttribute(final int node)213 public boolean isAttribute(final int node) { 214 return getNodeType(node) == DTM.ATTRIBUTE_NODE; 215 } 216 217 /** 218 * Returns the number of nodes in the tree (used for indexing) 219 */ getSize()220 public int getSize() { 221 return getNumberOfNodes(); 222 } 223 224 /** 225 * Part of the DOM interface - no function here. 226 */ setFilter(StripFilter filter)227 public void setFilter(StripFilter filter) { 228 } 229 230 231 /** 232 * Returns true if node1 comes before node2 in document order 233 */ lessThan(int node1, int node2)234 public boolean lessThan(int node1, int node2) { 235 if (node1 == DTM.NULL) { 236 return false; 237 } 238 239 if (node2 == DTM.NULL) { 240 return true; 241 } 242 243 return (node1 < node2); 244 } 245 246 /** 247 * Create an org.w3c.dom.Node from a node in the tree 248 */ makeNode(int index)249 public Node makeNode(int index) { 250 if (_nodes == null) { 251 _nodes = new Node[_namesSize]; 252 } 253 254 int nodeID = makeNodeIdentity(index); 255 if (nodeID < 0) { 256 return null; 257 } 258 else if (nodeID < _nodes.length) { 259 return (_nodes[nodeID] != null) ? _nodes[nodeID] 260 : (_nodes[nodeID] = new DTMNodeProxy((DTM)this, index)); 261 } 262 else { 263 return new DTMNodeProxy((DTM)this, index); 264 } 265 } 266 267 /** 268 * Create an org.w3c.dom.Node from a node in an iterator 269 * The iterator most be started before this method is called 270 */ makeNode(DTMAxisIterator iter)271 public Node makeNode(DTMAxisIterator iter) { 272 return makeNode(iter.next()); 273 } 274 275 /** 276 * Create an org.w3c.dom.NodeList from a node in the tree 277 */ makeNodeList(int index)278 public NodeList makeNodeList(int index) { 279 if (_nodeLists == null) { 280 _nodeLists = new NodeList[_namesSize]; 281 } 282 283 int nodeID = makeNodeIdentity(index); 284 if (nodeID < 0) { 285 return null; 286 } 287 else if (nodeID < _nodeLists.length) { 288 return (_nodeLists[nodeID] != null) ? _nodeLists[nodeID] 289 : (_nodeLists[nodeID] = new DTMAxisIterNodeList(this, 290 new SingletonIterator(index))); 291 } 292 else { 293 return new DTMAxisIterNodeList(this, new SingletonIterator(index)); 294 } 295 } 296 297 /** 298 * Create an org.w3c.dom.NodeList from a node iterator 299 * The iterator most be started before this method is called 300 */ makeNodeList(DTMAxisIterator iter)301 public NodeList makeNodeList(DTMAxisIterator iter) { 302 return new DTMAxisIterNodeList(this, iter); 303 } 304 305 /** 306 * Iterator that returns the namespace nodes as defined by the XPath data 307 * model for a given node, filtered by extended type ID. 308 */ 309 public class TypedNamespaceIterator extends NamespaceIterator { 310 311 private String _nsPrefix; 312 313 /** 314 * Constructor TypedChildrenIterator 315 * 316 * 317 * @param nodeType The extended type ID being requested. 318 */ TypedNamespaceIterator(int nodeType)319 public TypedNamespaceIterator(int nodeType) { 320 super(); 321 if(m_expandedNameTable != null){ 322 _nsPrefix = m_expandedNameTable.getLocalName(nodeType); 323 } 324 } 325 326 /** 327 * Get the next node in the iteration. 328 * 329 * @return The next node handle in the iteration, or END. 330 */ next()331 public int next() { 332 if ((_nsPrefix == null) ||(_nsPrefix.length() == 0) ){ 333 return (END); 334 } 335 int node = END; 336 for (node = super.next(); node != END; node = super.next()) { 337 if (_nsPrefix.compareTo(getLocalName(node))== 0) { 338 return returnNode(node); 339 } 340 } 341 return (END); 342 } 343 } // end of TypedNamespaceIterator 344 345 346 347 /************************************************************** 348 * This is a specialised iterator for predicates comparing node or 349 * attribute values to variable or parameter values. 350 */ 351 private final class NodeValueIterator extends InternalAxisIteratorBase 352 { 353 354 private DTMAxisIterator _source; 355 private String _value; 356 private boolean _op; 357 private final boolean _isReverse; 358 private int _returnType = RETURN_PARENT; 359 NodeValueIterator(DTMAxisIterator source, int returnType, String value, boolean op)360 public NodeValueIterator(DTMAxisIterator source, int returnType, 361 String value, boolean op) 362 { 363 _source = source; 364 _returnType = returnType; 365 _value = value; 366 _op = op; 367 _isReverse = source.isReverse(); 368 } 369 isReverse()370 public boolean isReverse() 371 { 372 return _isReverse; 373 } 374 cloneIterator()375 public DTMAxisIterator cloneIterator() 376 { 377 try { 378 NodeValueIterator clone = (NodeValueIterator)super.clone(); 379 clone._isRestartable = false; 380 clone._source = _source.cloneIterator(); 381 clone._value = _value; 382 clone._op = _op; 383 return clone.reset(); 384 } 385 catch (CloneNotSupportedException e) { 386 BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, 387 e.toString()); 388 return null; 389 } 390 } 391 setRestartable(boolean isRestartable)392 public void setRestartable(boolean isRestartable) 393 { 394 _isRestartable = isRestartable; 395 _source.setRestartable(isRestartable); 396 } 397 reset()398 public DTMAxisIterator reset() 399 { 400 _source.reset(); 401 return resetPosition(); 402 } 403 next()404 public int next() 405 { 406 int node; 407 while ((node = _source.next()) != END) { 408 String val = getStringValueX(node); 409 if (_value.equals(val) == _op) { 410 if (_returnType == RETURN_CURRENT) { 411 return returnNode(node); 412 } 413 else { 414 return returnNode(getParent(node)); 415 } 416 } 417 } 418 return END; 419 } 420 setStartNode(int node)421 public DTMAxisIterator setStartNode(int node) 422 { 423 if (_isRestartable) { 424 _source.setStartNode(_startNode = node); 425 return resetPosition(); 426 } 427 return this; 428 } 429 setMark()430 public void setMark() 431 { 432 _source.setMark(); 433 } 434 gotoMark()435 public void gotoMark() 436 { 437 _source.gotoMark(); 438 } 439 } // end NodeValueIterator 440 getNodeValueIterator(DTMAxisIterator iterator, int type, String value, boolean op)441 public DTMAxisIterator getNodeValueIterator(DTMAxisIterator iterator, int type, 442 String value, boolean op) 443 { 444 return(DTMAxisIterator)(new NodeValueIterator(iterator, type, value, op)); 445 } 446 447 /** 448 * Encapsulates an iterator in an OrderedIterator to ensure node order 449 */ orderNodes(DTMAxisIterator source, int node)450 public DTMAxisIterator orderNodes(DTMAxisIterator source, int node) 451 { 452 return new DupFilterIterator(source); 453 } 454 455 /** 456 * Returns singleton iterator containg the document root 457 * Works for them main document (mark == 0). It cannot be made 458 * to point to any other node through setStartNode(). 459 */ getIterator()460 public DTMAxisIterator getIterator() 461 { 462 return new SingletonIterator(getDocument(), true); 463 } 464 465 /** 466 * Get mapping from DOM namespace types to external namespace types 467 */ getNSType(int node)468 public int getNSType(int node) 469 { 470 String s = getNamespaceURI(node); 471 if (s == null) { 472 return 0; 473 } 474 int eType = getIdForNamespace(s); 475 return _nsIndex.get(eType); 476 } 477 478 479 480 /** 481 * Returns the namespace type of a specific node 482 */ getNamespaceType(final int node)483 public int getNamespaceType(final int node) 484 { 485 return super.getNamespaceType(node); 486 } 487 488 /** 489 * Sets up a translet-to-dom type mapping table 490 */ 491 /* 492 private int[] setupMapping(String[] names, String[] uris, int[] types, int nNames) { 493 // Padding with number of names, because they 494 // may need to be added, i.e for RTFs. See copy03 495 final int[] result = new int[m_expandedNameTable.getSize()]; 496 for (int i = 0; i < nNames; i++) { 497 //int type = getGeneralizedType(namesArray[i]); 498 int type = m_expandedNameTable.getExpandedTypeID(uris[i], names[i], types[i], false); 499 result[type] = type; 500 } 501 return result; 502 } 503 */ 504 505 /** 506 * Returns the internal type associated with an expanded QName 507 */ getGeneralizedType(final String name)508 public int getGeneralizedType(final String name) { 509 return getGeneralizedType(name, true); 510 } 511 512 /** 513 * Returns the internal type associated with an expanded QName 514 */ getGeneralizedType(final String name, boolean searchOnly)515 public int getGeneralizedType(final String name, boolean searchOnly) { 516 String lName, ns = null; 517 int index = -1; 518 int code; 519 520 // Is there a prefix? 521 if ((index = name.lastIndexOf(":"))> -1) { 522 ns = name.substring(0, index); 523 } 524 525 // Local part of name is after colon. lastIndexOf returns -1 if 526 // there is no colon, so lNameStartIdx will be zero in that case. 527 int lNameStartIdx = index+1; 528 529 // Distinguish attribute and element names. Attribute has @ before 530 // local part of name. 531 if (name.charAt(lNameStartIdx) == '@') { 532 code = DTM.ATTRIBUTE_NODE; 533 lNameStartIdx++; 534 } 535 else { 536 code = DTM.ELEMENT_NODE; 537 } 538 539 // Extract local name 540 lName = (lNameStartIdx == 0) ? name : name.substring(lNameStartIdx); 541 542 return m_expandedNameTable.getExpandedTypeID(ns, lName, code, searchOnly); 543 } 544 545 /** 546 * Get mapping from DOM element/attribute types to external types 547 */ getMapping(String[] names, String[] uris, int[] types)548 public short[] getMapping(String[] names, String[] uris, int[] types) 549 { 550 // Delegate the work to getMapping2 if the document is not fully built. 551 // Some of the processing has to be different in this case. 552 if (_namesSize < 0) { 553 return getMapping2(names, uris, types); 554 } 555 556 int i; 557 final int namesLength = names.length; 558 final int exLength = m_expandedNameTable.getSize(); 559 560 final short[] result = new short[exLength]; 561 562 // primitive types map to themselves 563 for (i = 0; i < DTM.NTYPES; i++) { 564 result[i] = (short)i; 565 } 566 567 for (i = NTYPES; i < exLength; i++) { 568 result[i] = m_expandedNameTable.getType(i); 569 } 570 571 // actual mapping of caller requested names 572 for (i = 0; i < namesLength; i++) { 573 int genType = m_expandedNameTable.getExpandedTypeID(uris[i], 574 names[i], 575 types[i], 576 true); 577 if (genType >= 0 && genType < exLength) { 578 result[genType] = (short)(i + DTM.NTYPES); 579 } 580 } 581 582 return result; 583 } 584 585 /** 586 * Get mapping from external element/attribute types to DOM types 587 */ getReverseMapping(String[] names, String[] uris, int[] types)588 public int[] getReverseMapping(String[] names, String[] uris, int[] types) 589 { 590 int i; 591 final int[] result = new int[names.length + DTM.NTYPES]; 592 593 // primitive types map to themselves 594 for (i = 0; i < DTM.NTYPES; i++) { 595 result[i] = i; 596 } 597 598 // caller's types map into appropriate dom types 599 for (i = 0; i < names.length; i++) { 600 int type = m_expandedNameTable.getExpandedTypeID(uris[i], names[i], types[i], true); 601 result[i+DTM.NTYPES] = type; 602 } 603 return(result); 604 } 605 606 /** 607 * Get mapping from DOM element/attribute types to external types. 608 * This method is used when the document is not fully built. 609 */ getMapping2(String[] names, String[] uris, int[] types)610 private short[] getMapping2(String[] names, String[] uris, int[] types) 611 { 612 int i; 613 final int namesLength = names.length; 614 final int exLength = m_expandedNameTable.getSize(); 615 int[] generalizedTypes = null; 616 if (namesLength > 0) { 617 generalizedTypes = new int[namesLength]; 618 } 619 620 int resultLength = exLength; 621 622 for (i = 0; i < namesLength; i++) { 623 // When the document is not fully built, the searchOnly 624 // flag should be set to false. That means we should add 625 // the type if it is not already in the expanded name table. 626 //generalizedTypes[i] = getGeneralizedType(names[i], false); 627 generalizedTypes[i] = 628 m_expandedNameTable.getExpandedTypeID(uris[i], 629 names[i], 630 types[i], 631 false); 632 if (_namesSize < 0 && generalizedTypes[i] >= resultLength) { 633 resultLength = generalizedTypes[i] + 1; 634 } 635 } 636 637 final short[] result = new short[resultLength]; 638 639 // primitive types map to themselves 640 for (i = 0; i < DTM.NTYPES; i++) { 641 result[i] = (short)i; 642 } 643 644 for (i = NTYPES; i < exLength; i++) { 645 result[i] = m_expandedNameTable.getType(i); 646 } 647 648 // actual mapping of caller requested names 649 for (i = 0; i < namesLength; i++) { 650 int genType = generalizedTypes[i]; 651 if (genType >= 0 && genType < resultLength) { 652 result[genType] = (short)(i + DTM.NTYPES); 653 } 654 } 655 656 return(result); 657 } 658 /** 659 * Get mapping from DOM namespace types to external namespace types 660 */ getNamespaceMapping(String[] namespaces)661 public short[] getNamespaceMapping(String[] namespaces) 662 { 663 int i; 664 final int nsLength = namespaces.length; 665 final int mappingLength = _uriCount; 666 667 final short[] result = new short[mappingLength]; 668 669 // Initialize all entries to -1 670 for (i=0; i<mappingLength; i++) { 671 result[i] = (short)(-1); 672 } 673 674 for (i=0; i<nsLength; i++) { 675 int eType = getIdForNamespace(namespaces[i]); 676 Integer type = _nsIndex.get(eType); 677 if (type != null) { 678 result[type] = (short)i; 679 } 680 } 681 682 return(result); 683 } 684 685 /** 686 * Get mapping from external namespace types to DOM namespace types 687 */ getReverseNamespaceMapping(String[] namespaces)688 public short[] getReverseNamespaceMapping(String[] namespaces) 689 { 690 int i; 691 final int length = namespaces.length; 692 final short[] result = new short[length]; 693 694 for (i = 0; i < length; i++) { 695 int eType = getIdForNamespace(namespaces[i]); 696 Integer type = _nsIndex.get(eType); 697 result[i] = (type == null) ? -1 : type.shortValue(); 698 } 699 700 return result; 701 } 702 703 /** 704 * Construct a SAXImpl object using the default block size. 705 */ SAXImpl(XSLTCDTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing, boolean buildIdIndex)706 public SAXImpl(XSLTCDTMManager mgr, Source source, 707 int dtmIdentity, DTMWSFilter whiteSpaceFilter, 708 XMLStringFactory xstringfactory, 709 boolean doIndexing, boolean buildIdIndex) 710 { 711 this(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, 712 doIndexing, DEFAULT_BLOCKSIZE, buildIdIndex, false); 713 } 714 715 /** 716 * Construct a SAXImpl object using the given block size. 717 */ SAXImpl(XSLTCDTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing, int blocksize, boolean buildIdIndex, boolean newNameTable)718 public SAXImpl(XSLTCDTMManager mgr, Source source, 719 int dtmIdentity, DTMWSFilter whiteSpaceFilter, 720 XMLStringFactory xstringfactory, 721 boolean doIndexing, int blocksize, 722 boolean buildIdIndex, 723 boolean newNameTable) 724 { 725 super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, 726 doIndexing, blocksize, false, buildIdIndex, newNameTable); 727 728 _dtmManager = mgr; 729 _size = blocksize; 730 731 // Use a smaller size for the space stack if the blocksize is small 732 _xmlSpaceStack = new int[blocksize <= 64 ? 4 : 64]; 733 734 /* From DOMBuilder */ 735 _xmlSpaceStack[0] = DTMDefaultBase.ROOTNODE; 736 737 // If the input source is DOMSource, set the _document field and 738 // create the node2Ids table. 739 if (source instanceof DOMSource) { 740 _hasDOMSource = true; 741 DOMSource domsrc = (DOMSource)source; 742 Node node = domsrc.getNode(); 743 if (node instanceof Document) { 744 _document = (Document)node; 745 } 746 else { 747 _document = node.getOwnerDocument(); 748 } 749 _node2Ids = new HashMap<>(); 750 } 751 } 752 753 /** 754 * Migrate a DTM built with an old DTMManager to a new DTMManager. 755 * After the migration, the new DTMManager will treat the DTM as 756 * one that is built by itself. 757 * This is used to support DTM sharing between multiple transformations. 758 * @param manager the DTMManager 759 */ migrateTo(DTMManager manager)760 public void migrateTo(DTMManager manager) { 761 super.migrateTo(manager); 762 if (manager instanceof XSLTCDTMManager) { 763 _dtmManager = (XSLTCDTMManager)manager; 764 } 765 } 766 767 /** 768 * Return the node identity for a given id String 769 * 770 * @param idString The id String 771 * @return The identity of the node whose id is the given String. 772 */ getElementById(String idString)773 public int getElementById(String idString) 774 { 775 Node node = _document.getElementById(idString); 776 if (node != null) { 777 Integer id = _node2Ids.get(node); 778 return (id != null) ? id : DTM.NULL; 779 } 780 else { 781 return DTM.NULL; 782 } 783 } 784 785 /** 786 * Return true if the input source is DOMSource. 787 */ hasDOMSource()788 public boolean hasDOMSource() 789 { 790 return _hasDOMSource; 791 } 792 793 /*---------------------------------------------------------------------------*/ 794 /* DOMBuilder methods begin */ 795 /*---------------------------------------------------------------------------*/ 796 797 /** 798 * Call this when an xml:space attribute is encountered to 799 * define the whitespace strip/preserve settings. 800 */ xmlSpaceDefine(String val, final int node)801 private void xmlSpaceDefine(String val, final int node) 802 { 803 final boolean setting = val.equals(PRESERVE_STRING); 804 if (setting != _preserve) { 805 _xmlSpaceStack[_idx++] = node; 806 _preserve = setting; 807 } 808 } 809 810 /** 811 * Call this from endElement() to revert strip/preserve setting 812 * to whatever it was before the corresponding startElement(). 813 */ xmlSpaceRevert(final int node)814 private void xmlSpaceRevert(final int node) 815 { 816 if (node == _xmlSpaceStack[_idx - 1]) { 817 _idx--; 818 _preserve = !_preserve; 819 } 820 } 821 822 /** 823 * Find out whether or not to strip whitespace nodes. 824 * 825 * 826 * @return whether or not to strip whitespace nodes. 827 */ getShouldStripWhitespace()828 protected boolean getShouldStripWhitespace() 829 { 830 return _preserve ? false : super.getShouldStripWhitespace(); 831 } 832 833 /** 834 * Creates a text-node and checks if it is a whitespace node. 835 */ handleTextEscaping()836 private void handleTextEscaping() { 837 if (_disableEscaping && _textNodeToProcess != DTM.NULL 838 && _type(_textNodeToProcess) == DTM.TEXT_NODE) { 839 if (_dontEscape == null) { 840 _dontEscape = new BitArray(_size); 841 } 842 843 // Resize the _dontEscape BitArray if necessary. 844 if (_textNodeToProcess >= _dontEscape.size()) { 845 _dontEscape.resize(_dontEscape.size() * 2); 846 } 847 848 _dontEscape.setBit(_textNodeToProcess); 849 _disableEscaping = false; 850 } 851 _textNodeToProcess = DTM.NULL; 852 } 853 854 855 /****************************************************************/ 856 /* SAX Interface Starts Here */ 857 /****************************************************************/ 858 859 /** 860 * SAX2: Receive notification of character data. 861 */ characters(char[] ch, int start, int length)862 public void characters(char[] ch, int start, int length) throws SAXException 863 { 864 super.characters(ch, start, length); 865 866 _disableEscaping = !_escaping; 867 _textNodeToProcess = getNumberOfNodes(); 868 } 869 870 /** 871 * SAX2: Receive notification of the beginning of a document. 872 */ startDocument()873 public void startDocument() throws SAXException 874 { 875 super.startDocument(); 876 877 _nsIndex.put(0, _uriCount++); 878 definePrefixAndUri(XML_PREFIX, XML_URI); 879 } 880 881 /** 882 * SAX2: Receive notification of the end of a document. 883 */ endDocument()884 public void endDocument() throws SAXException 885 { 886 super.endDocument(); 887 888 handleTextEscaping(); 889 _namesSize = m_expandedNameTable.getSize(); 890 } 891 892 /** 893 * Specialized interface used by DOM2SAX. This one has an extra Node 894 * parameter to build the Node -> id map. 895 */ startElement(String uri, String localName, String qname, Attributes attributes, Node node)896 public void startElement(String uri, String localName, 897 String qname, Attributes attributes, 898 Node node) 899 throws SAXException 900 { 901 this.startElement(uri, localName, qname, attributes); 902 903 if (m_buildIdIndex) { 904 _node2Ids.put(node, m_parents.peek()); 905 } 906 } 907 908 /** 909 * SAX2: Receive notification of the beginning of an element. 910 */ startElement(String uri, String localName, String qname, Attributes attributes)911 public void startElement(String uri, String localName, 912 String qname, Attributes attributes) 913 throws SAXException 914 { 915 super.startElement(uri, localName, qname, attributes); 916 917 handleTextEscaping(); 918 919 if (m_wsfilter != null) { 920 // Look for any xml:space attributes 921 // Depending on the implementation of attributes, this 922 // might be faster than looping through all attributes. ILENE 923 final int index = attributes.getIndex(XMLSPACE_STRING); 924 if (index >= 0) { 925 xmlSpaceDefine(attributes.getValue(index), m_parents.peek()); 926 } 927 } 928 } 929 930 /** 931 * SAX2: Receive notification of the end of an element. 932 */ endElement(String namespaceURI, String localName, String qname)933 public void endElement(String namespaceURI, String localName, String qname) 934 throws SAXException 935 { 936 super.endElement(namespaceURI, localName, qname); 937 938 handleTextEscaping(); 939 940 // Revert to strip/preserve-space setting from before this element 941 if (m_wsfilter != null) { 942 xmlSpaceRevert(m_previous); 943 } 944 } 945 946 /** 947 * SAX2: Receive notification of a processing instruction. 948 */ processingInstruction(String target, String data)949 public void processingInstruction(String target, String data) 950 throws SAXException 951 { 952 super.processingInstruction(target, data); 953 handleTextEscaping(); 954 } 955 956 /** 957 * SAX2: Receive notification of ignorable whitespace in element 958 * content. Similar to characters(char[], int, int). 959 */ ignorableWhitespace(char[] ch, int start, int length)960 public void ignorableWhitespace(char[] ch, int start, int length) 961 throws SAXException 962 { 963 super.ignorableWhitespace(ch, start, length); 964 _textNodeToProcess = getNumberOfNodes(); 965 } 966 967 /** 968 * SAX2: Begin the scope of a prefix-URI Namespace mapping. 969 */ startPrefixMapping(String prefix, String uri)970 public void startPrefixMapping(String prefix, String uri) 971 throws SAXException 972 { 973 super.startPrefixMapping(prefix, uri); 974 handleTextEscaping(); 975 976 definePrefixAndUri(prefix, uri); 977 } 978 definePrefixAndUri(String prefix, String uri)979 private void definePrefixAndUri(String prefix, String uri) 980 throws SAXException 981 { 982 // Check if the URI already exists before pushing on stack 983 Integer eType = getIdForNamespace(uri); 984 if (_nsIndex.get(eType) == null) { 985 _nsIndex.put(eType, _uriCount++); 986 } 987 } 988 989 /** 990 * SAX2: Report an XML comment anywhere in the document. 991 */ comment(char[] ch, int start, int length)992 public void comment(char[] ch, int start, int length) 993 throws SAXException 994 { 995 super.comment(ch, start, length); 996 handleTextEscaping(); 997 } 998 setEscaping(boolean value)999 public boolean setEscaping(boolean value) { 1000 final boolean temp = _escaping; 1001 _escaping = value; 1002 return temp; 1003 } 1004 1005 /*---------------------------------------------------------------------------*/ 1006 /* DOMBuilder methods end */ 1007 /*---------------------------------------------------------------------------*/ 1008 1009 /** 1010 * Prints the whole tree to standard output 1011 */ print(int node, int level)1012 public void print(int node, int level) 1013 { 1014 switch(getNodeType(node)) 1015 { 1016 case DTM.ROOT_NODE: 1017 case DTM.DOCUMENT_NODE: 1018 print(getFirstChild(node), level); 1019 break; 1020 case DTM.TEXT_NODE: 1021 case DTM.COMMENT_NODE: 1022 case DTM.PROCESSING_INSTRUCTION_NODE: 1023 System.out.print(getStringValueX(node)); 1024 break; 1025 default: 1026 final String name = getNodeName(node); 1027 System.out.print("<" + name); 1028 for (int a = getFirstAttribute(node); a != DTM.NULL; a = getNextAttribute(a)) 1029 { 1030 System.out.print("\n" + getNodeName(a) + "=\"" + getStringValueX(a) + "\""); 1031 } 1032 System.out.print('>'); 1033 for (int child = getFirstChild(node); child != DTM.NULL; 1034 child = getNextSibling(child)) { 1035 print(child, level + 1); 1036 } 1037 System.out.println("</" + name + '>'); 1038 break; 1039 } 1040 } 1041 1042 /** 1043 * Returns the name of a node (attribute or element). 1044 */ getNodeName(final int node)1045 public String getNodeName(final int node) 1046 { 1047 // Get the node type and make sure that it is within limits 1048 int nodeh = node; 1049 final short type = getNodeType(nodeh); 1050 switch(type) 1051 { 1052 case DTM.ROOT_NODE: 1053 case DTM.DOCUMENT_NODE: 1054 case DTM.TEXT_NODE: 1055 case DTM.COMMENT_NODE: 1056 return EMPTYSTRING; 1057 case DTM.NAMESPACE_NODE: 1058 return this.getLocalName(nodeh); 1059 default: 1060 return super.getNodeName(nodeh); 1061 } 1062 } 1063 1064 /** 1065 * Returns the namespace URI to which a node belongs 1066 */ getNamespaceName(final int node)1067 public String getNamespaceName(final int node) 1068 { 1069 if (node == DTM.NULL) { 1070 return ""; 1071 } 1072 1073 String s; 1074 return (s = getNamespaceURI(node)) == null ? EMPTYSTRING : s; 1075 } 1076 1077 1078 /** 1079 * Returns the attribute node of a given type (if any) for an element 1080 */ getAttributeNode(final int type, final int element)1081 public int getAttributeNode(final int type, final int element) 1082 { 1083 for (int attr = getFirstAttribute(element); 1084 attr != DTM.NULL; 1085 attr = getNextAttribute(attr)) 1086 { 1087 if (getExpandedTypeID(attr) == type) return attr; 1088 } 1089 return DTM.NULL; 1090 } 1091 1092 /** 1093 * Returns the value of a given attribute type of a given element 1094 */ getAttributeValue(final int type, final int element)1095 public String getAttributeValue(final int type, final int element) 1096 { 1097 final int attr = getAttributeNode(type, element); 1098 return (attr != DTM.NULL) ? getStringValueX(attr) : EMPTYSTRING; 1099 } 1100 1101 /** 1102 * This method is for testing/debugging only 1103 */ getAttributeValue(final String name, final int element)1104 public String getAttributeValue(final String name, final int element) 1105 { 1106 return getAttributeValue(getGeneralizedType(name), element); 1107 } 1108 1109 /** 1110 * Returns an iterator with all the children of a given node 1111 */ getChildren(final int node)1112 public DTMAxisIterator getChildren(final int node) 1113 { 1114 return (new ChildrenIterator()).setStartNode(node); 1115 } 1116 1117 /** 1118 * Returns an iterator with all children of a specific type 1119 * for a given node (element) 1120 */ getTypedChildren(final int type)1121 public DTMAxisIterator getTypedChildren(final int type) 1122 { 1123 return(new TypedChildrenIterator(type)); 1124 } 1125 1126 /** 1127 * This is a shortcut to the iterators that implement the 1128 * supported XPath axes (only namespace::) is not supported. 1129 * Returns a bare-bones iterator that must be initialized 1130 * with a start node (using iterator.setStartNode()). 1131 */ getAxisIterator(final int axis)1132 public DTMAxisIterator getAxisIterator(final int axis) 1133 { 1134 switch (axis) 1135 { 1136 case Axis.SELF: 1137 return new SingletonIterator(); 1138 case Axis.CHILD: 1139 return new ChildrenIterator(); 1140 case Axis.PARENT: 1141 return new ParentIterator(); 1142 case Axis.ANCESTOR: 1143 return new AncestorIterator(); 1144 case Axis.ANCESTORORSELF: 1145 return (new AncestorIterator()).includeSelf(); 1146 case Axis.ATTRIBUTE: 1147 return new AttributeIterator(); 1148 case Axis.DESCENDANT: 1149 return new DescendantIterator(); 1150 case Axis.DESCENDANTORSELF: 1151 return (new DescendantIterator()).includeSelf(); 1152 case Axis.FOLLOWING: 1153 return new FollowingIterator(); 1154 case Axis.PRECEDING: 1155 return new PrecedingIterator(); 1156 case Axis.FOLLOWINGSIBLING: 1157 return new FollowingSiblingIterator(); 1158 case Axis.PRECEDINGSIBLING: 1159 return new PrecedingSiblingIterator(); 1160 case Axis.NAMESPACE: 1161 return new NamespaceIterator(); 1162 case Axis.ROOT: 1163 return new RootIterator(); 1164 default: 1165 BasisLibrary.runTimeError(BasisLibrary.AXIS_SUPPORT_ERR, 1166 Axis.getNames(axis)); 1167 } 1168 return null; 1169 } 1170 1171 /** 1172 * Similar to getAxisIterator, but this one returns an iterator 1173 * containing nodes of a typed axis (ex.: child::foo) 1174 */ getTypedAxisIterator(int axis, int type)1175 public DTMAxisIterator getTypedAxisIterator(int axis, int type) 1176 { 1177 // Most common case handled first 1178 if (axis == Axis.CHILD) { 1179 return new TypedChildrenIterator(type); 1180 } 1181 1182 if (type == NO_TYPE) { 1183 return(EMPTYITERATOR); 1184 } 1185 1186 switch (axis) 1187 { 1188 case Axis.SELF: 1189 return new TypedSingletonIterator(type); 1190 case Axis.CHILD: 1191 return new TypedChildrenIterator(type); 1192 case Axis.PARENT: 1193 return new ParentIterator().setNodeType(type); 1194 case Axis.ANCESTOR: 1195 return new TypedAncestorIterator(type); 1196 case Axis.ANCESTORORSELF: 1197 return (new TypedAncestorIterator(type)).includeSelf(); 1198 case Axis.ATTRIBUTE: 1199 return new TypedAttributeIterator(type); 1200 case Axis.DESCENDANT: 1201 return new TypedDescendantIterator(type); 1202 case Axis.DESCENDANTORSELF: 1203 return (new TypedDescendantIterator(type)).includeSelf(); 1204 case Axis.FOLLOWING: 1205 return new TypedFollowingIterator(type); 1206 case Axis.PRECEDING: 1207 return new TypedPrecedingIterator(type); 1208 case Axis.FOLLOWINGSIBLING: 1209 return new TypedFollowingSiblingIterator(type); 1210 case Axis.PRECEDINGSIBLING: 1211 return new TypedPrecedingSiblingIterator(type); 1212 case Axis.NAMESPACE: 1213 return new TypedNamespaceIterator(type); 1214 case Axis.ROOT: 1215 return new TypedRootIterator(type); 1216 default: 1217 BasisLibrary.runTimeError(BasisLibrary.TYPED_AXIS_SUPPORT_ERR, 1218 Axis.getNames(axis)); 1219 } 1220 return null; 1221 } 1222 1223 /** 1224 * Do not think that this returns an iterator for the namespace axis. 1225 * It returns an iterator with nodes that belong in a certain namespace, 1226 * such as with <xsl:apply-templates select="blob/foo:*"/> 1227 * The 'axis' specifies the axis for the base iterator from which the 1228 * nodes are taken, while 'ns' specifies the namespace URI type. 1229 */ getNamespaceAxisIterator(int axis, int ns)1230 public DTMAxisIterator getNamespaceAxisIterator(int axis, int ns) 1231 { 1232 if (ns == NO_TYPE) { 1233 return EMPTYITERATOR; 1234 } 1235 else { 1236 switch (axis) { 1237 case Axis.CHILD: 1238 return new NamespaceChildrenIterator(ns); 1239 case Axis.ATTRIBUTE: 1240 return new NamespaceAttributeIterator(ns); 1241 default: 1242 return new NamespaceWildcardIterator(axis, ns); 1243 } 1244 } 1245 } 1246 1247 /** 1248 * Iterator that handles node tests that test for a namespace, but have 1249 * a wild card for the local name of the node, i.e., node tests of the 1250 * form <axis>::<prefix>:* 1251 */ 1252 public final class NamespaceWildcardIterator 1253 extends InternalAxisIteratorBase 1254 { 1255 /** 1256 * The namespace type index. 1257 */ 1258 protected int m_nsType; 1259 1260 /** 1261 * A nested typed axis iterator that retrieves nodes of the principal 1262 * node kind for that axis. 1263 */ 1264 protected DTMAxisIterator m_baseIterator; 1265 1266 /** 1267 * Constructor NamespaceWildcard 1268 * 1269 * @param axis The axis that this iterator will traverse 1270 * @param nsType The namespace type index 1271 */ NamespaceWildcardIterator(int axis, int nsType)1272 public NamespaceWildcardIterator(int axis, int nsType) { 1273 m_nsType = nsType; 1274 1275 // Create a nested iterator that will select nodes of 1276 // the principal node kind for the selected axis. 1277 switch (axis) { 1278 case Axis.ATTRIBUTE: { 1279 // For "attribute::p:*", the principal node kind is 1280 // attribute 1281 m_baseIterator = getAxisIterator(axis); 1282 break; 1283 } 1284 case Axis.NAMESPACE: { 1285 // This covers "namespace::p:*". It is syntactically 1286 // correct, though it doesn't make much sense. 1287 m_baseIterator = getAxisIterator(axis); 1288 break; 1289 } 1290 default: { 1291 // In all other cases, the principal node kind is 1292 // element 1293 m_baseIterator = getTypedAxisIterator(axis, 1294 DTM.ELEMENT_NODE); 1295 } 1296 } 1297 } 1298 1299 /** 1300 * Set start to END should 'close' the iterator, 1301 * i.e. subsequent call to next() should return END. 1302 * 1303 * @param node Sets the root of the iteration. 1304 * 1305 * @return A DTMAxisIterator set to the start of the iteration. 1306 */ setStartNode(int node)1307 public DTMAxisIterator setStartNode(int node) { 1308 if (_isRestartable) { 1309 _startNode = node; 1310 m_baseIterator.setStartNode(node); 1311 resetPosition(); 1312 } 1313 return this; 1314 } 1315 1316 /** 1317 * Get the next node in the iteration. 1318 * 1319 * @return The next node handle in the iteration, or END. 1320 */ next()1321 public int next() { 1322 int node; 1323 1324 while ((node = m_baseIterator.next()) != END) { 1325 // Return only nodes that are in the selected namespace 1326 if (getNSType(node) == m_nsType) { 1327 return returnNode(node); 1328 } 1329 } 1330 1331 return END; 1332 } 1333 1334 /** 1335 * Returns a deep copy of this iterator. The cloned iterator is not 1336 * reset. 1337 * 1338 * @return a deep copy of this iterator. 1339 */ cloneIterator()1340 public DTMAxisIterator cloneIterator() { 1341 try { 1342 DTMAxisIterator nestedClone = m_baseIterator.cloneIterator(); 1343 NamespaceWildcardIterator clone = 1344 (NamespaceWildcardIterator) super.clone(); 1345 1346 clone.m_baseIterator = nestedClone; 1347 clone.m_nsType = m_nsType; 1348 clone._isRestartable = false; 1349 1350 return clone; 1351 } catch (CloneNotSupportedException e) { 1352 BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, 1353 e.toString()); 1354 return null; 1355 } 1356 } 1357 1358 /** 1359 * True if this iterator has a reversed axis. 1360 * 1361 * @return <code>true</code> if this iterator is a reversed axis. 1362 */ isReverse()1363 public boolean isReverse() { 1364 return m_baseIterator.isReverse(); 1365 } 1366 setMark()1367 public void setMark() { 1368 m_baseIterator.setMark(); 1369 } 1370 gotoMark()1371 public void gotoMark() { 1372 m_baseIterator.gotoMark(); 1373 } 1374 } 1375 1376 /** 1377 * Iterator that returns children within a given namespace for a 1378 * given node. The functionality chould be achieved by putting a 1379 * filter on top of a basic child iterator, but a specialised 1380 * iterator is used for efficiency (both speed and size of translet). 1381 */ 1382 public final class NamespaceChildrenIterator 1383 extends InternalAxisIteratorBase 1384 { 1385 1386 /** The extended type ID being requested. */ 1387 private final int _nsType; 1388 1389 /** 1390 * Constructor NamespaceChildrenIterator 1391 * 1392 * 1393 * @param type The extended type ID being requested. 1394 */ NamespaceChildrenIterator(final int type)1395 public NamespaceChildrenIterator(final int type) { 1396 _nsType = type; 1397 } 1398 1399 /** 1400 * Set start to END should 'close' the iterator, 1401 * i.e. subsequent call to next() should return END. 1402 * 1403 * @param node Sets the root of the iteration. 1404 * 1405 * @return A DTMAxisIterator set to the start of the iteration. 1406 */ setStartNode(int node)1407 public DTMAxisIterator setStartNode(int node) { 1408 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily 1409 if (node == DTMDefaultBase.ROOTNODE) { 1410 node = getDocument(); 1411 } 1412 1413 if (_isRestartable) { 1414 _startNode = node; 1415 _currentNode = (node == DTM.NULL) ? DTM.NULL : NOTPROCESSED; 1416 1417 return resetPosition(); 1418 } 1419 1420 return this; 1421 } 1422 1423 /** 1424 * Get the next node in the iteration. 1425 * 1426 * @return The next node handle in the iteration, or END. 1427 */ next()1428 public int next() { 1429 if (_currentNode != DTM.NULL) { 1430 for (int node = (NOTPROCESSED == _currentNode) 1431 ? _firstch(makeNodeIdentity(_startNode)) 1432 : _nextsib(_currentNode); 1433 node != END; 1434 node = _nextsib(node)) { 1435 int nodeHandle = makeNodeHandle(node); 1436 1437 if (getNSType(nodeHandle) == _nsType) { 1438 _currentNode = node; 1439 1440 return returnNode(nodeHandle); 1441 } 1442 } 1443 } 1444 1445 return END; 1446 } 1447 } // end of NamespaceChildrenIterator 1448 1449 /** 1450 * Iterator that returns attributes within a given namespace for a node. 1451 */ 1452 public final class NamespaceAttributeIterator 1453 extends InternalAxisIteratorBase 1454 { 1455 1456 /** The extended type ID being requested. */ 1457 private final int _nsType; 1458 1459 /** 1460 * Constructor NamespaceAttributeIterator 1461 * 1462 * 1463 * @param nsType The extended type ID being requested. 1464 */ NamespaceAttributeIterator(int nsType)1465 public NamespaceAttributeIterator(int nsType) { 1466 super(); 1467 1468 _nsType = nsType; 1469 } 1470 1471 /** 1472 * Set start to END should 'close' the iterator, 1473 * i.e. subsequent call to next() should return END. 1474 * 1475 * @param node Sets the root of the iteration. 1476 * 1477 * @return A DTMAxisIterator set to the start of the iteration. 1478 */ setStartNode(int node)1479 public DTMAxisIterator setStartNode(int node) { 1480 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily 1481 if (node == DTMDefaultBase.ROOTNODE) { 1482 node = getDocument(); 1483 } 1484 1485 if (_isRestartable) { 1486 int nsType = _nsType; 1487 1488 _startNode = node; 1489 1490 for (node = getFirstAttribute(node); 1491 node != END; 1492 node = getNextAttribute(node)) { 1493 if (getNSType(node) == nsType) { 1494 break; 1495 } 1496 } 1497 1498 _currentNode = node; 1499 return resetPosition(); 1500 } 1501 1502 return this; 1503 } 1504 1505 /** 1506 * Get the next node in the iteration. 1507 * 1508 * @return The next node handle in the iteration, or END. 1509 */ next()1510 public int next() { 1511 int node = _currentNode; 1512 int nsType = _nsType; 1513 int nextNode; 1514 1515 if (node == END) { 1516 return END; 1517 } 1518 1519 for (nextNode = getNextAttribute(node); 1520 nextNode != END; 1521 nextNode = getNextAttribute(nextNode)) { 1522 if (getNSType(nextNode) == nsType) { 1523 break; 1524 } 1525 } 1526 1527 _currentNode = nextNode; 1528 1529 return returnNode(node); 1530 } 1531 } // end of NamespaceAttributeIterator 1532 1533 /** 1534 * Returns an iterator with all descendants of a node that are of 1535 * a given type. 1536 */ getTypedDescendantIterator(int type)1537 public DTMAxisIterator getTypedDescendantIterator(int type) 1538 { 1539 return new TypedDescendantIterator(type); 1540 } 1541 1542 /** 1543 * Returns the nth descendant of a node 1544 */ getNthDescendant(int type, int n, boolean includeself)1545 public DTMAxisIterator getNthDescendant(int type, int n, boolean includeself) 1546 { 1547 return new NthDescendantIterator(n); 1548 } 1549 1550 /** 1551 * Copy the string value of a node directly to an output handler 1552 */ characters(final int node, SerializationHandler handler)1553 public void characters(final int node, SerializationHandler handler) 1554 throws TransletException 1555 { 1556 if (node != DTM.NULL) { 1557 try { 1558 dispatchCharactersEvents(node, handler, false); 1559 } catch (SAXException e) { 1560 throw new TransletException(e); 1561 } 1562 } 1563 } 1564 1565 /** 1566 * Copy a node-set to an output handler 1567 */ copy(DTMAxisIterator nodes, SerializationHandler handler)1568 public void copy(DTMAxisIterator nodes, SerializationHandler handler) 1569 throws TransletException 1570 { 1571 int node; 1572 while ((node = nodes.next()) != DTM.NULL) { 1573 copy(node, handler); 1574 } 1575 } 1576 1577 /** 1578 * Copy the whole tree to an output handler 1579 */ copy(SerializationHandler handler)1580 public void copy(SerializationHandler handler) throws TransletException 1581 { 1582 copy(getDocument(), handler); 1583 } 1584 1585 /** 1586 * Performs a deep copy (ref. XSLs copy-of()) 1587 * 1588 * TODO: Copy namespace declarations. Can't be done until we 1589 * add namespace nodes and keep track of NS prefixes 1590 * TODO: Copy comment nodes 1591 */ copy(final int node, SerializationHandler handler)1592 public void copy(final int node, SerializationHandler handler) 1593 throws TransletException 1594 { 1595 copy(node, handler, false ); 1596 } 1597 1598 copy(final int node, SerializationHandler handler, boolean isChild)1599 private final void copy(final int node, SerializationHandler handler, boolean isChild) 1600 throws TransletException 1601 { 1602 int nodeID = makeNodeIdentity(node); 1603 int eType = _exptype2(nodeID); 1604 int type = _exptype2Type(eType); 1605 1606 try { 1607 switch(type) 1608 { 1609 case DTM.ROOT_NODE: 1610 case DTM.DOCUMENT_NODE: 1611 for(int c = _firstch2(nodeID); c != DTM.NULL; c = _nextsib2(c)) { 1612 copy(makeNodeHandle(c), handler, true); 1613 } 1614 break; 1615 case DTM.PROCESSING_INSTRUCTION_NODE: 1616 copyPI(node, handler); 1617 break; 1618 case DTM.COMMENT_NODE: 1619 handler.comment(getStringValueX(node)); 1620 break; 1621 case DTM.TEXT_NODE: 1622 boolean oldEscapeSetting = false; 1623 boolean escapeBit = false; 1624 1625 if (_dontEscape != null) { 1626 escapeBit = _dontEscape.getBit(getNodeIdent(node)); 1627 if (escapeBit) { 1628 oldEscapeSetting = handler.setEscaping(false); 1629 } 1630 } 1631 1632 copyTextNode(nodeID, handler); 1633 1634 if (escapeBit) { 1635 handler.setEscaping(oldEscapeSetting); 1636 } 1637 break; 1638 case DTM.ATTRIBUTE_NODE: 1639 copyAttribute(nodeID, eType, handler); 1640 break; 1641 case DTM.NAMESPACE_NODE: 1642 handler.namespaceAfterStartElement(getNodeNameX(node), getNodeValue(node)); 1643 break; 1644 default: 1645 if (type == DTM.ELEMENT_NODE) 1646 { 1647 // Start element definition 1648 final String name = copyElement(nodeID, eType, handler); 1649 //if(isChild) => not to copy any namespaces from parents 1650 // else copy all namespaces in scope 1651 copyNS(nodeID, handler,!isChild); 1652 copyAttributes(nodeID, handler); 1653 // Copy element children 1654 for (int c = _firstch2(nodeID); c != DTM.NULL; c = _nextsib2(c)) { 1655 copy(makeNodeHandle(c), handler, true); 1656 } 1657 1658 // Close element definition 1659 handler.endElement(name); 1660 } 1661 // Shallow copy of attribute to output handler 1662 else { 1663 final String uri = getNamespaceName(node); 1664 if (uri.length() != 0) { 1665 final String prefix = getPrefix(node); 1666 handler.namespaceAfterStartElement(prefix, uri); 1667 } 1668 handler.addAttribute(getNodeName(node), getNodeValue(node)); 1669 } 1670 break; 1671 } 1672 } 1673 catch (Exception e) { 1674 throw new TransletException(e); 1675 } 1676 1677 } 1678 /** 1679 * Copies a processing instruction node to an output handler 1680 */ copyPI(final int node, SerializationHandler handler)1681 private void copyPI(final int node, SerializationHandler handler) 1682 throws TransletException 1683 { 1684 final String target = getNodeName(node); 1685 final String value = getStringValueX(node); 1686 1687 try { 1688 handler.processingInstruction(target, value); 1689 } catch (Exception e) { 1690 throw new TransletException(e); 1691 } 1692 } 1693 1694 /** 1695 * Performs a shallow copy (ref. XSLs copy()) 1696 */ shallowCopy(final int node, SerializationHandler handler)1697 public String shallowCopy(final int node, SerializationHandler handler) 1698 throws TransletException 1699 { 1700 int nodeID = makeNodeIdentity(node); 1701 int exptype = _exptype2(nodeID); 1702 int type = _exptype2Type(exptype); 1703 1704 try { 1705 switch(type) 1706 { 1707 case DTM.ELEMENT_NODE: 1708 final String name = copyElement(nodeID, exptype, handler); 1709 copyNS(nodeID, handler, true); 1710 return name; 1711 case DTM.ROOT_NODE: 1712 case DTM.DOCUMENT_NODE: 1713 return EMPTYSTRING; 1714 case DTM.TEXT_NODE: 1715 copyTextNode(nodeID, handler); 1716 return null; 1717 case DTM.PROCESSING_INSTRUCTION_NODE: 1718 copyPI(node, handler); 1719 return null; 1720 case DTM.COMMENT_NODE: 1721 handler.comment(getStringValueX(node)); 1722 return null; 1723 case DTM.NAMESPACE_NODE: 1724 handler.namespaceAfterStartElement(getNodeNameX(node), getNodeValue(node)); 1725 return null; 1726 case DTM.ATTRIBUTE_NODE: 1727 copyAttribute(nodeID, exptype, handler); 1728 return null; 1729 default: 1730 final String uri1 = getNamespaceName(node); 1731 if (uri1.length() != 0) { 1732 final String prefix = getPrefix(node); 1733 handler.namespaceAfterStartElement(prefix, uri1); 1734 } 1735 handler.addAttribute(getNodeName(node), getNodeValue(node)); 1736 return null; 1737 } 1738 } catch (Exception e) { 1739 throw new TransletException(e); 1740 } 1741 } 1742 1743 /** 1744 * Returns a node' defined language for a node (if any) 1745 */ getLanguage(int node)1746 public String getLanguage(int node) 1747 { 1748 int parent = node; 1749 while (DTM.NULL != parent) { 1750 if (DTM.ELEMENT_NODE == getNodeType(parent)) { 1751 int langAttr = getAttributeNode(parent, "http://www.w3.org/XML/1998/namespace", "lang"); 1752 1753 if (DTM.NULL != langAttr) { 1754 return getNodeValue(langAttr); 1755 } 1756 } 1757 1758 parent = getParent(parent); 1759 } 1760 return(null); 1761 } 1762 1763 /** 1764 * Returns an instance of the DOMBuilder inner class 1765 * This class will consume the input document through a SAX2 1766 * interface and populate the tree. 1767 */ getBuilder()1768 public DOMBuilder getBuilder() 1769 { 1770 return this; 1771 } 1772 1773 /** 1774 * Return a SerializationHandler for output handling. 1775 * This method is used by Result Tree Fragments. 1776 */ getOutputDomBuilder()1777 public SerializationHandler getOutputDomBuilder() 1778 { 1779 return new ToXMLSAXHandler(this, "UTF-8"); 1780 } 1781 1782 /** 1783 * Return a instance of a DOM class to be used as an RTF 1784 */ getResultTreeFrag(int initSize, int rtfType)1785 public DOM getResultTreeFrag(int initSize, int rtfType) 1786 { 1787 return getResultTreeFrag(initSize, rtfType, true); 1788 } 1789 1790 /** 1791 * Return a instance of a DOM class to be used as an RTF 1792 * 1793 * @param initSize The initial size of the DOM. 1794 * @param rtfType The type of the RTF 1795 * @param addToManager true if the RTF should be registered with the DTMManager. 1796 * @return The DOM object which represents the RTF. 1797 */ getResultTreeFrag(int initSize, int rtfType, boolean addToManager)1798 public DOM getResultTreeFrag(int initSize, int rtfType, boolean addToManager) 1799 { 1800 if (rtfType == DOM.SIMPLE_RTF) { 1801 if (addToManager) { 1802 int dtmPos = _dtmManager.getFirstFreeDTMID(); 1803 SimpleResultTreeImpl rtf = new SimpleResultTreeImpl(_dtmManager, 1804 dtmPos << DTMManager.IDENT_DTM_NODE_BITS); 1805 _dtmManager.addDTM(rtf, dtmPos, 0); 1806 return rtf; 1807 } 1808 else { 1809 return new SimpleResultTreeImpl(_dtmManager, 0); 1810 } 1811 } 1812 else if (rtfType == DOM.ADAPTIVE_RTF) { 1813 if (addToManager) { 1814 int dtmPos = _dtmManager.getFirstFreeDTMID(); 1815 AdaptiveResultTreeImpl rtf = new AdaptiveResultTreeImpl(_dtmManager, 1816 dtmPos << DTMManager.IDENT_DTM_NODE_BITS, 1817 m_wsfilter, initSize, m_buildIdIndex); 1818 _dtmManager.addDTM(rtf, dtmPos, 0); 1819 return rtf; 1820 1821 } 1822 else { 1823 return new AdaptiveResultTreeImpl(_dtmManager, 0, 1824 m_wsfilter, initSize, m_buildIdIndex); 1825 } 1826 } 1827 else { 1828 return (DOM) _dtmManager.getDTM(null, true, m_wsfilter, 1829 true, false, false, 1830 initSize, m_buildIdIndex); 1831 } 1832 } 1833 1834 /** 1835 * Return the attributes map. 1836 * @return the attributes map. 1837 */ getElementsWithIDs()1838 public Map<String, Integer> getElementsWithIDs() { 1839 return m_idAttributes; 1840 } 1841 1842 /** 1843 * The getUnparsedEntityURI function returns the URI of the unparsed 1844 * entity with the specified name in the same document as the context 1845 * node (see [3.3 Unparsed Entities]). It returns the empty string if 1846 * there is no such entity. 1847 */ getUnparsedEntityURI(String name)1848 public String getUnparsedEntityURI(String name) 1849 { 1850 // Special handling for DOM input 1851 if (_document != null) { 1852 String uri = ""; 1853 DocumentType doctype = _document.getDoctype(); 1854 if (doctype != null) { 1855 NamedNodeMap entities = doctype.getEntities(); 1856 1857 if (entities == null) { 1858 return uri; 1859 } 1860 1861 Entity entity = (Entity) entities.getNamedItem(name); 1862 1863 if (entity == null) { 1864 return uri; 1865 } 1866 1867 String notationName = entity.getNotationName(); 1868 if (notationName != null) { 1869 uri = entity.getSystemId(); 1870 if (uri == null) { 1871 uri = entity.getPublicId(); 1872 } 1873 } 1874 } 1875 return uri; 1876 } 1877 else { 1878 return super.getUnparsedEntityURI(name); 1879 } 1880 } 1881 release()1882 public void release() { 1883 _dtmManager.release(this, true); 1884 } 1885 } 1886