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