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