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