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