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