1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xml.dtm.ref;
  58. import org.apache.xml.dtm.*;
  59. import org.w3c.dom.*;
  60. import org.xml.sax.*;
  61. import org.xml.sax.ext.LexicalHandler;
  62. import org.apache.xml.utils.NodeConsumer;
  63. import org.apache.xml.utils.XMLString;
  64. /**
  65. * <meta name="usage" content="advanced"/>
  66. * This class does a pre-order walk of the DTM tree, calling a ContentHandler
  67. * interface as it goes. As such, it's more like the Visitor design pattern
  68. * than like the DOM's TreeWalker.
  69. *
  70. * I think normally this class should not be needed, because
  71. * of DTM#dispatchToEvents.
  72. */
  73. public class DTMTreeWalker
  74. {
  75. /** Local reference to a ContentHandler */
  76. private ContentHandler m_contentHandler = null;
  77. /** DomHelper for this TreeWalker */
  78. protected DTM m_dtm;
  79. /**
  80. * Set the DTM to be traversed.
  81. *
  82. * @param dtm The Document Table Model to be used.
  83. */
  84. public void setDTM(DTM dtm)
  85. {
  86. m_dtm = dtm;
  87. }
  88. /**
  89. * Get the ContentHandler used for the tree walk.
  90. *
  91. * @return the ContentHandler used for the tree walk
  92. */
  93. public ContentHandler getcontentHandler()
  94. {
  95. return m_contentHandler;
  96. }
  97. /**
  98. * Set the ContentHandler used for the tree walk.
  99. *
  100. * @param ch the ContentHandler to be the result of the tree walk.
  101. */
  102. public void setcontentHandler(ContentHandler ch)
  103. {
  104. m_contentHandler = ch;
  105. }
  106. /**
  107. * Constructor.
  108. * @param contentHandler The implemention of the
  109. * contentHandler operation (toXMLString, digest, ...)
  110. */
  111. public DTMTreeWalker()
  112. {
  113. }
  114. /**
  115. * Constructor.
  116. * @param contentHandler The implemention of the
  117. * contentHandler operation (toXMLString, digest, ...)
  118. */
  119. public DTMTreeWalker(ContentHandler contentHandler, DTM dtm)
  120. {
  121. this.m_contentHandler = contentHandler;
  122. m_dtm = dtm;
  123. }
  124. /** Perform a non-recursive pre-order/post-order traversal,
  125. * operating as a Visitor. startNode (preorder) and endNode
  126. * (postorder) are invoked for each node as we traverse over them,
  127. * with the result that the node is written out to m_contentHandler.
  128. *
  129. * @param pos Node in the tree at which to start (and end) traversal --
  130. * in other words, the root of the subtree to traverse over.
  131. *
  132. * @throws TransformerException */
  133. public void traverse(int pos) throws org.xml.sax.SAXException
  134. {
  135. // %REVIEW% Why isn't this just traverse(pos,pos)?
  136. int top = pos; // Remember the root of this subtree
  137. while (DTM.NULL != pos)
  138. {
  139. startNode(pos);
  140. int nextNode = m_dtm.getFirstChild(pos);
  141. while (DTM.NULL == nextNode)
  142. {
  143. endNode(pos);
  144. if (top == pos)
  145. break;
  146. nextNode = m_dtm.getNextSibling(pos);
  147. if (DTM.NULL == nextNode)
  148. {
  149. pos = m_dtm.getParent(pos);
  150. if ((DTM.NULL == pos) || (top == pos))
  151. {
  152. // %REVIEW% This condition isn't tested in traverse(pos,top)
  153. // -- bug?
  154. if (DTM.NULL != pos)
  155. endNode(pos);
  156. nextNode = DTM.NULL;
  157. break;
  158. }
  159. }
  160. }
  161. pos = nextNode;
  162. }
  163. }
  164. /** Perform a non-recursive pre-order/post-order traversal,
  165. * operating as a Visitor. startNode (preorder) and endNode
  166. * (postorder) are invoked for each node as we traverse over them,
  167. * with the result that the node is written out to m_contentHandler.
  168. *
  169. * @param pos Node in the tree where to start traversal
  170. * @param top Node in the tree where to end traversal.
  171. * If top==DTM.NULL, run through end of document.
  172. *
  173. * @throws TransformerException
  174. */
  175. public void traverse(int pos, int top) throws org.xml.sax.SAXException
  176. {
  177. // %OPT% Can we simplify the loop conditionals by adding:
  178. // if(top==DTM.NULL) top=0
  179. // -- or by simply ignoring this case and relying on the fact that
  180. // pos will never equal DTM.NULL until we're ready to exit?
  181. while (DTM.NULL != pos)
  182. {
  183. startNode(pos);
  184. int nextNode = m_dtm.getFirstChild(pos);
  185. while (DTM.NULL == nextNode)
  186. {
  187. endNode(pos);
  188. if ((DTM.NULL != top) && top == pos)
  189. break;
  190. nextNode = m_dtm.getNextSibling(pos);
  191. if (DTM.NULL == nextNode)
  192. {
  193. pos = m_dtm.getParent(pos);
  194. if ((DTM.NULL == pos) || ((DTM.NULL != top) && (top == pos)))
  195. {
  196. nextNode = DTM.NULL;
  197. break;
  198. }
  199. }
  200. }
  201. pos = nextNode;
  202. }
  203. }
  204. /** Flag indicating whether following text to be processed is raw text */
  205. boolean nextIsRaw = false;
  206. /**
  207. * Optimized dispatch of characters.
  208. */
  209. private final void dispatachChars(int node)
  210. throws org.xml.sax.SAXException
  211. {
  212. m_dtm.dispatchCharactersEvents(node, m_contentHandler, false);
  213. }
  214. /**
  215. * Start processing given node
  216. *
  217. *
  218. * @param node Node to process
  219. *
  220. * @throws org.xml.sax.SAXException
  221. */
  222. protected void startNode(int node) throws org.xml.sax.SAXException
  223. {
  224. if (m_contentHandler instanceof NodeConsumer)
  225. {
  226. // %TBD%
  227. // ((NodeConsumer) m_contentHandler).setOriginatingNode(node);
  228. }
  229. switch (m_dtm.getNodeType(node))
  230. {
  231. case DTM.COMMENT_NODE :
  232. {
  233. XMLString data = m_dtm.getStringValue(node);
  234. if (m_contentHandler instanceof LexicalHandler)
  235. {
  236. LexicalHandler lh = ((LexicalHandler) this.m_contentHandler);
  237. data.dispatchAsComment(lh);
  238. }
  239. }
  240. break;
  241. case DTM.DOCUMENT_FRAGMENT_NODE :
  242. // ??;
  243. break;
  244. case DTM.DOCUMENT_NODE :
  245. this.m_contentHandler.startDocument();
  246. break;
  247. case DTM.ELEMENT_NODE :
  248. DTM dtm = m_dtm;
  249. for (int nsn = dtm.getFirstNamespaceNode(node, true); DTM.NULL != nsn;
  250. nsn = dtm.getNextNamespaceNode(node, nsn, true))
  251. {
  252. // String prefix = dtm.getPrefix(nsn);
  253. String prefix = dtm.getNodeNameX(nsn);
  254. this.m_contentHandler.startPrefixMapping(prefix, dtm.getNodeValue(nsn));
  255. }
  256. // System.out.println("m_dh.getNamespaceOfNode(node): "+m_dh.getNamespaceOfNode(node));
  257. // System.out.println("m_dh.getLocalNameOfNode(node): "+m_dh.getLocalNameOfNode(node));
  258. String ns = dtm.getNamespaceURI(node);
  259. if(null == ns)
  260. ns = "";
  261. // %OPT% !!
  262. org.xml.sax.helpers.AttributesImpl attrs =
  263. new org.xml.sax.helpers.AttributesImpl();
  264. for (int i = dtm.getFirstAttribute(node);
  265. i != DTM.NULL;
  266. i = dtm.getNextAttribute(i))
  267. {
  268. attrs.addAttribute(dtm.getNamespaceURI(i),
  269. dtm.getLocalName(i),
  270. dtm.getNodeName(i),
  271. "CDATA",
  272. dtm.getNodeValue(i));
  273. }
  274. this.m_contentHandler.startElement(ns,
  275. m_dtm.getLocalName(node),
  276. m_dtm.getNodeName(node),
  277. attrs);
  278. break;
  279. case DTM.PROCESSING_INSTRUCTION_NODE :
  280. {
  281. String name = m_dtm.getNodeName(node);
  282. // String data = pi.getData();
  283. if (name.equals("xslt-next-is-raw"))
  284. {
  285. nextIsRaw = true;
  286. }
  287. else
  288. {
  289. this.m_contentHandler.processingInstruction(name,
  290. m_dtm.getNodeValue(node));
  291. }
  292. }
  293. break;
  294. case DTM.CDATA_SECTION_NODE :
  295. {
  296. boolean isLexH = (m_contentHandler instanceof LexicalHandler);
  297. LexicalHandler lh = isLexH
  298. ? ((LexicalHandler) this.m_contentHandler) : null;
  299. if (isLexH)
  300. {
  301. lh.startCDATA();
  302. }
  303. dispatachChars(node);
  304. {
  305. if (isLexH)
  306. {
  307. lh.endCDATA();
  308. }
  309. }
  310. }
  311. break;
  312. case DTM.TEXT_NODE :
  313. {
  314. if (nextIsRaw)
  315. {
  316. nextIsRaw = false;
  317. m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, "");
  318. dispatachChars(node);
  319. m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING, "");
  320. }
  321. else
  322. {
  323. dispatachChars(node);
  324. }
  325. }
  326. break;
  327. case DTM.ENTITY_REFERENCE_NODE :
  328. {
  329. if (m_contentHandler instanceof LexicalHandler)
  330. {
  331. ((LexicalHandler) this.m_contentHandler).startEntity(
  332. m_dtm.getNodeName(node));
  333. }
  334. else
  335. {
  336. // warning("Can not output entity to a pure SAX ContentHandler");
  337. }
  338. }
  339. break;
  340. default :
  341. }
  342. }
  343. /**
  344. * End processing of given node
  345. *
  346. *
  347. * @param node Node we just finished processing
  348. *
  349. * @throws org.xml.sax.SAXException
  350. */
  351. protected void endNode(int node) throws org.xml.sax.SAXException
  352. {
  353. switch (m_dtm.getNodeType(node))
  354. {
  355. case DTM.DOCUMENT_NODE :
  356. this.m_contentHandler.endDocument();
  357. break;
  358. case DTM.ELEMENT_NODE :
  359. String ns = m_dtm.getNamespaceURI(node);
  360. if(null == ns)
  361. ns = "";
  362. this.m_contentHandler.endElement(ns,
  363. m_dtm.getLocalName(node),
  364. m_dtm.getNodeName(node));
  365. for (int nsn = m_dtm.getFirstNamespaceNode(node, true); DTM.NULL != nsn;
  366. nsn = m_dtm.getNextNamespaceNode(node, nsn, true))
  367. {
  368. // String prefix = m_dtm.getPrefix(nsn);
  369. String prefix = m_dtm.getNodeNameX(nsn);
  370. this.m_contentHandler.endPrefixMapping(prefix);
  371. }
  372. break;
  373. case DTM.CDATA_SECTION_NODE :
  374. break;
  375. case DTM.ENTITY_REFERENCE_NODE :
  376. {
  377. if (m_contentHandler instanceof LexicalHandler)
  378. {
  379. LexicalHandler lh = ((LexicalHandler) this.m_contentHandler);
  380. lh.endEntity(m_dtm.getNodeName(node));
  381. }
  382. }
  383. break;
  384. default :
  385. }
  386. }
  387. } //TreeWalker