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.xalan.templates;
  58. //import org.w3c.dom.*;
  59. import java.util.Vector;
  60. import javax.xml.transform.TransformerException;
  61. import org.apache.xalan.transformer.ResultTreeHandler;
  62. import org.apache.xalan.transformer.StackGuard;
  63. import org.apache.xalan.transformer.TransformerImpl;
  64. import org.apache.xml.dtm.DTM;
  65. import org.apache.xml.dtm.DTMIterator;
  66. import org.apache.xml.utils.QName;
  67. import org.apache.xpath.VariableStack;
  68. import org.apache.xpath.XPath;
  69. import org.apache.xpath.XPathContext;
  70. import org.apache.xpath.objects.XObject;
  71. import org.xml.sax.ContentHandler;
  72. import org.xml.sax.SAXException;
  73. import org.apache.xml.utils.IntStack;
  74. /**
  75. * <meta name="usage" content="advanced"/>
  76. * Implement xsl:apply-templates.
  77. * <pre>
  78. * &!ELEMENT xsl:apply-templates (xsl:sort|xsl:with-param)*>
  79. * &!ATTLIST xsl:apply-templates
  80. * select %expr; "node()"
  81. * mode %qname; #IMPLIED
  82. * &
  83. * </pre>
  84. * @see <a href="http://www.w3.org/TR/xslt#section-Applying-Template-Rules">section-Applying-Template-Rules in XSLT Specification</a>
  85. */
  86. public class ElemApplyTemplates extends ElemCallTemplate
  87. {
  88. /**
  89. * mode %qname; #IMPLIED
  90. * @serial
  91. */
  92. private QName m_mode = null;
  93. /**
  94. * Set the mode attribute for this element.
  95. *
  96. * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
  97. */
  98. public void setMode(QName mode)
  99. {
  100. m_mode = mode;
  101. }
  102. /**
  103. * Get the mode attribute for this element.
  104. *
  105. * @return The mode attribute for this element
  106. */
  107. public QName getMode()
  108. {
  109. return m_mode;
  110. }
  111. /**
  112. * Tells if this belongs to a default template,
  113. * in which case it will act different with
  114. * regard to processing modes.
  115. * @see <a href="http://www.w3.org/TR/xslt#built-in-rule">built-in-rule in XSLT Specification</a>
  116. * @serial
  117. */
  118. private boolean m_isDefaultTemplate = false;
  119. // /**
  120. // * List of namespace/localname IDs, for identification of xsl:with-param to
  121. // * xsl:params. Initialized in the compose() method.
  122. // */
  123. // private int[] m_paramIDs;
  124. /**
  125. * Set if this belongs to a default template,
  126. * in which case it will act different with
  127. * regard to processing modes.
  128. * @see <a href="http://www.w3.org/TR/xslt#built-in-rule">built-in-rule in XSLT Specification</a>
  129. *
  130. * @param b boolean value to set.
  131. */
  132. public void setIsDefaultTemplate(boolean b)
  133. {
  134. m_isDefaultTemplate = b;
  135. }
  136. /**
  137. * Get an int constant identifying the type of element.
  138. * @see org.apache.xalan.templates.Constants
  139. *
  140. * @return Token ID for this element types
  141. */
  142. public int getXSLToken()
  143. {
  144. return Constants.ELEMNAME_APPLY_TEMPLATES;
  145. }
  146. /**
  147. * This function is called after everything else has been
  148. * recomposed, and allows the template to set remaining
  149. * values that may be based on some other property that
  150. * depends on recomposition.
  151. */
  152. public void compose(StylesheetRoot sroot) throws TransformerException
  153. {
  154. super.compose(sroot);
  155. }
  156. /**
  157. * Return the node name.
  158. *
  159. * @return Element name
  160. */
  161. public String getNodeName()
  162. {
  163. return Constants.ELEMNAME_APPLY_TEMPLATES_STRING;
  164. }
  165. /**
  166. * Apply the context node to the matching templates.
  167. * @see <a href="http://www.w3.org/TR/xslt#section-Applying-Template-Rules">section-Applying-Template-Rules in XSLT Specification</a>
  168. *
  169. * @param transformer non-null reference to the the current transform-time state.
  170. * @param sourceNode non-null reference to the <a href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
  171. * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
  172. *
  173. * @throws TransformerException
  174. */
  175. public void execute(TransformerImpl transformer) throws TransformerException
  176. {
  177. transformer.pushCurrentTemplateRuleIsNull(false);
  178. boolean pushMode = false;
  179. try
  180. {
  181. // %REVIEW% Do we need this check??
  182. // if (null != sourceNode)
  183. // {
  184. // boolean needToTurnOffInfiniteLoopCheck = false;
  185. QName mode = transformer.getMode();
  186. if (!m_isDefaultTemplate)
  187. {
  188. if (((null == mode) && (null != m_mode))
  189. || ((null != mode) &&!mode.equals(m_mode)))
  190. {
  191. pushMode = true;
  192. transformer.pushMode(m_mode);
  193. }
  194. }
  195. if (TransformerImpl.S_DEBUG)
  196. transformer.getTraceManager().fireTraceEvent(this);
  197. transformSelectedNodes(transformer);
  198. }
  199. finally
  200. {
  201. if (TransformerImpl.S_DEBUG)
  202. transformer.getTraceManager().fireTraceEndEvent(this);
  203. if (pushMode)
  204. transformer.popMode();
  205. transformer.popCurrentTemplateRuleIsNull();
  206. }
  207. }
  208. /**
  209. * <meta name="usage" content="advanced"/>
  210. * Perform a query if needed, and call transformNode for each child.
  211. *
  212. * @param transformer non-null reference to the the current transform-time state.
  213. * @param template The owning template context.
  214. *
  215. * @throws TransformerException Thrown in a variety of circumstances.
  216. */
  217. public void transformSelectedNodes(TransformerImpl transformer)
  218. throws TransformerException
  219. {
  220. final XPathContext xctxt = transformer.getXPathContext();
  221. final int sourceNode = xctxt.getCurrentNode();
  222. DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
  223. VariableStack vars = xctxt.getVarStack();
  224. int nParams = getParamElemCount();
  225. int thisframe = vars.getStackFrame();
  226. StackGuard guard = transformer.getStackGuard();
  227. boolean check = (guard.getRecursionLimit() > -1) ? true : false;
  228. try
  229. {
  230. final Vector keys = (m_sortElems == null)
  231. ? null
  232. : transformer.processSortKeys(this, sourceNode);
  233. // Sort if we need to.
  234. if (null != keys)
  235. sourceNodes = sortNodes(xctxt, keys, sourceNodes);
  236. if (TransformerImpl.S_DEBUG)
  237. {
  238. transformer.getTraceManager().fireSelectedEvent(sourceNode, this,
  239. "select", new XPath(m_selectExpression),
  240. new org.apache.xpath.objects.XNodeSet(sourceNodes));
  241. }
  242. final ResultTreeHandler rth = transformer.getResultTreeHandler();
  243. ContentHandler chandler = rth.getContentHandler();
  244. final StylesheetRoot sroot = transformer.getStylesheet();
  245. final TemplateList tl = sroot.getTemplateListComposed();
  246. final boolean quiet = transformer.getQuietConflictWarnings();
  247. // Should be able to get this from the iterator but there must be a bug.
  248. DTM dtm = xctxt.getDTM(sourceNode);
  249. int argsFrame = -1;
  250. if(nParams > 0)
  251. {
  252. // This code will create a section on the stack that is all the
  253. // evaluated arguments. These will be copied into the real params
  254. // section of each called template.
  255. argsFrame = vars.link(nParams);
  256. vars.setStackFrame(thisframe);
  257. for (int i = 0; i < nParams; i++)
  258. {
  259. ElemWithParam ewp = m_paramElems[i];
  260. XObject obj = ewp.getValue(transformer, sourceNode);
  261. vars.setLocalVariable(i, obj, argsFrame);
  262. }
  263. vars.setStackFrame(argsFrame);
  264. }
  265. xctxt.pushCurrentNode(DTM.NULL);
  266. IntStack currentNodes = xctxt.getCurrentNodeStack();
  267. xctxt.pushCurrentExpressionNode(DTM.NULL);
  268. IntStack currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
  269. xctxt.pushSAXLocatorNull();
  270. xctxt.pushContextNodeList(sourceNodes);
  271. transformer.pushElemTemplateElement(null);
  272. // pushParams(transformer, xctxt);
  273. int child;
  274. while (DTM.NULL != (child = sourceNodes.nextNode()))
  275. {
  276. currentNodes.setTop(child);
  277. currentExpressionNodes.setTop(child);
  278. if(xctxt.getDTM(child) != dtm)
  279. {
  280. dtm = xctxt.getDTM(child);
  281. }
  282. final int exNodeType = dtm.getExpandedTypeID(child);
  283. final int nodeType = dtm.getNodeType(child);
  284. final QName mode = transformer.getMode();
  285. ElemTemplate template = tl.getTemplateFast(xctxt, child, exNodeType, mode,
  286. -1, quiet, dtm);
  287. // If that didn't locate a node, fall back to a default template rule.
  288. // See http://www.w3.org/TR/xslt#built-in-rule.
  289. if (null == template)
  290. {
  291. switch (nodeType)
  292. {
  293. case DTM.DOCUMENT_FRAGMENT_NODE :
  294. case DTM.ELEMENT_NODE :
  295. template = sroot.getDefaultRule();
  296. // %OPT% direct faster?
  297. break;
  298. case DTM.ATTRIBUTE_NODE :
  299. case DTM.CDATA_SECTION_NODE :
  300. case DTM.TEXT_NODE :
  301. // if(rth.m_elemIsPending || rth.m_docPending)
  302. // rth.flushPending(true);
  303. transformer.pushPairCurrentMatched(sroot.getDefaultTextRule(), child);
  304. transformer.setCurrentElement(sroot.getDefaultTextRule());
  305. // dtm.dispatchCharactersEvents(child, chandler, false);
  306. dtm.dispatchCharactersEvents(child, rth, false);
  307. transformer.popCurrentMatched();
  308. continue;
  309. case DTM.DOCUMENT_NODE :
  310. template = sroot.getDefaultRootRule();
  311. break;
  312. default :
  313. // No default rules for processing instructions and the like.
  314. continue;
  315. }
  316. }
  317. else
  318. {
  319. transformer.setCurrentElement(template);
  320. }
  321. transformer.pushPairCurrentMatched(template, child);
  322. if (check)
  323. guard.checkForInfinateLoop();
  324. int currentFrameBottom; // See comment with unlink, below
  325. if(template.m_frameSize > 0)
  326. {
  327. xctxt.pushRTFContext();
  328. currentFrameBottom = vars.getStackFrame(); // See comment with unlink, below
  329. vars.link(template.m_frameSize);
  330. // You can't do the check for nParams here, otherwise the
  331. // xsl:params might not be nulled.
  332. if(/* nParams > 0 && */ template.m_inArgsSize > 0)
  333. {
  334. int paramIndex = 0;
  335. for (ElemTemplateElement elem = template.getFirstChildElem();
  336. null != elem; elem = elem.getNextSiblingElem())
  337. {
  338. if(Constants.ELEMNAME_PARAMVARIABLE == elem.getXSLToken())
  339. {
  340. ElemParam ep = (ElemParam)elem;
  341. int i;
  342. for (i = 0; i < nParams; i++)
  343. {
  344. ElemWithParam ewp = m_paramElems[i];
  345. if(ewp.m_qnameID == ep.m_qnameID)
  346. {
  347. XObject obj = vars.getLocalVariable(i, argsFrame);
  348. vars.setLocalVariable(paramIndex, obj);
  349. break;
  350. }
  351. }
  352. if(i == nParams)
  353. vars.setLocalVariable(paramIndex, null);
  354. }
  355. else
  356. break;
  357. paramIndex++;
  358. }
  359. }
  360. }
  361. else
  362. currentFrameBottom = 0;
  363. // Fire a trace event for the template.
  364. if (TransformerImpl.S_DEBUG)
  365. transformer.getTraceManager().fireTraceEvent(template);
  366. // And execute the child templates.
  367. // Loop through the children of the template, calling execute on
  368. // each of them.
  369. for (ElemTemplateElement t = template.m_firstChild;
  370. t != null; t = t.m_nextSibling)
  371. {
  372. xctxt.setSAXLocator(t);
  373. try
  374. {
  375. transformer.pushElemTemplateElement(t);
  376. t.execute(transformer);
  377. }
  378. finally
  379. {
  380. transformer.popElemTemplateElement();
  381. }
  382. }
  383. if (TransformerImpl.S_DEBUG)
  384. transformer.getTraceManager().fireTraceEndEvent(template);
  385. if(template.m_frameSize > 0)
  386. {
  387. // See Frank Weiss bug around 03/19/2002 (no Bugzilla report yet).
  388. // While unlink will restore to the proper place, the real position
  389. // may have been changed for xsl:with-param, so that variables
  390. // can be accessed.
  391. // of right now.
  392. // More:
  393. // When we entered this function, the current
  394. // frame buffer (cfb) index in the variable stack may
  395. // have been manually set. If we just call
  396. // unlink(), however, it will restore the cfb to the
  397. // previous link index from the link stack, rather than
  398. // the manually set cfb. So,
  399. // the only safe solution is to restore it back
  400. // to the same position it was on entry, since we're
  401. // really not working in a stack context here. (Bug4218)
  402. vars.unlink(currentFrameBottom);
  403. xctxt.popRTFContext();
  404. }
  405. transformer.popCurrentMatched();
  406. } // end while (DTM.NULL != (child = sourceNodes.nextNode()))
  407. }
  408. catch (SAXException se)
  409. {
  410. transformer.getErrorListener().fatalError(new TransformerException(se));
  411. }
  412. finally
  413. {
  414. if (TransformerImpl.S_DEBUG)
  415. transformer.getTraceManager().fireSelectedEndEvent(sourceNode, this,
  416. "select", new XPath(m_selectExpression),
  417. new org.apache.xpath.objects.XNodeSet(sourceNodes));
  418. // Unlink to the original stack frame
  419. if(nParams > 0)
  420. vars.unlink(thisframe);
  421. xctxt.popSAXLocator();
  422. xctxt.popContextNodeList();
  423. transformer.popElemTemplateElement();
  424. xctxt.popCurrentExpressionNode();
  425. xctxt.popCurrentNode();
  426. sourceNodes.detach();
  427. }
  428. }
  429. }