SAXImpl.java revision 1188:86157a0bf14f
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
21package com.sun.org.apache.xalan.internal.xsltc.dom;
22
23import com.sun.org.apache.xalan.internal.xsltc.DOM;
24import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
25import com.sun.org.apache.xalan.internal.xsltc.StripFilter;
26import com.sun.org.apache.xalan.internal.xsltc.TransletException;
27import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
28import com.sun.org.apache.xml.internal.dtm.Axis;
29import com.sun.org.apache.xml.internal.dtm.DTM;
30import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
31import com.sun.org.apache.xml.internal.dtm.DTMManager;
32import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
33import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIterNodeList;
34import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
35import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeProxy;
36import com.sun.org.apache.xml.internal.dtm.ref.EmptyIterator;
37import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM2;
38import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
39import com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler;
40import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
41import com.sun.org.apache.xml.internal.utils.XMLStringFactory;
42import java.util.HashMap;
43import java.util.Map;
44import javax.xml.transform.Source;
45import javax.xml.transform.dom.DOMSource;
46import org.w3c.dom.Document;
47import org.w3c.dom.DocumentType;
48import org.w3c.dom.Entity;
49import org.w3c.dom.NamedNodeMap;
50import org.w3c.dom.Node;
51import org.w3c.dom.NodeList;
52import org.xml.sax.Attributes;
53import 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 */
72public 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(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(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(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, 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 = 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}
1883