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      */
 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      */
 158     public String getDocumentURI() {
 159         String baseURI = getDocumentBaseURI();
 160         return (baseURI != null) ? baseURI : "rtf" + _documentURIIndex++;
 161     }
 162 
 163     public String getDocumentURI(int node) {
 164         return getDocumentURI();
 165     }
 166 
 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      */
 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      */
 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      */
 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      */
 220     public int getSize() {
 221         return getNumberOfNodes();
 222     }
 223 
 224     /**
 225      * Part of the DOM interface - no function here.
 226      */
 227     public void setFilter(StripFilter filter) {
 228     }
 229 
 230 
 231     /**
 232      * Returns true if node1 comes before node2 in document order
 233      */
 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      */
 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      */
 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      */
 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      */
 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          */
 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         */
 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 
 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 
 370         public boolean isReverse()
 371         {
 372             return _isReverse;
 373         }
 374 
 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 
 392         public void setRestartable(boolean isRestartable)
 393         {
 394             _isRestartable = isRestartable;
 395             _source.setRestartable(isRestartable);
 396         }
 397 
 398         public DTMAxisIterator reset()
 399         {
 400             _source.reset();
 401             return resetPosition();
 402         }
 403 
 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 
 421         public DTMAxisIterator setStartNode(int node)
 422         {
 423             if (_isRestartable) {
 424                 _source.setStartNode(_startNode = node);
 425                 return resetPosition();
 426             }
 427             return this;
 428         }
 429 
 430         public void setMark()
 431         {
 432             _source.setMark();
 433         }
 434 
 435         public void gotoMark()
 436         {
 437             _source.gotoMark();
 438         }
 439     } // end NodeValueIterator
 440 
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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     */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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 
 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      */
 992     public void comment(char[] ch, int start, int length)
 993         throws SAXException
 994     {
 995         super.comment(ch, start, length);
 996         handleTextEscaping();
 997     }
 998 
 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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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          */
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          */
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          */
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          */
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          */
1363         public boolean isReverse() {
1364             return m_baseIterator.isReverse();
1365         }
1366 
1367         public void setMark() {
1368             m_baseIterator.setMark();
1369         }
1370 
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          */
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          */
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          */
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          */
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          */
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          */
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      */
1537     public DTMAxisIterator getTypedDescendantIterator(int type)
1538     {
1539         return new TypedDescendantIterator(type);
1540     }
1541 
1542     /**
1543      * Returns the nth descendant of a node
1544      */
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      */
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      */
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      */
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      */
1592     public void copy(final int node, SerializationHandler handler)
1593         throws TransletException
1594     {
1595         copy(node, handler, false );
1596     }
1597 
1598 
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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 
1882     public void release() {
1883         _dtmManager.release(this, true);
1884     }
1885 }