KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > templates > ElemForEach


1 /*
2  * Copyright 1999-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: ElemForEach.java,v 1.38 2004/02/18 15:47:39 minchau Exp $
18  */

19 package org.apache.xalan.templates;
20
21 import java.util.Vector JavaDoc;
22
23 import javax.xml.transform.TransformerException JavaDoc;
24
25 import org.apache.xalan.transformer.NodeSorter;
26 import org.apache.xalan.transformer.TransformerImpl;
27 import org.apache.xml.dtm.DTM;
28 import org.apache.xml.dtm.DTMIterator;
29 import org.apache.xml.dtm.DTMManager;
30 import org.apache.xml.utils.IntStack;
31 import org.apache.xpath.Expression;
32 import org.apache.xpath.ExpressionOwner;
33 import org.apache.xpath.XPath;
34 import org.apache.xpath.XPathContext;
35
36 /**
37  * Implement xsl:for-each.
38  * <pre>
39  * <!ELEMENT xsl:for-each
40  * (#PCDATA
41  * %instructions;
42  * %result-elements;
43  * | xsl:sort)
44  * >
45  *
46  * <!ATTLIST xsl:for-each
47  * select %expr; #REQUIRED
48  * %space-att;
49  * >
50  * </pre>
51  * @see <a HREF="http://www.w3.org/TR/xslt#for-each">for-each in XSLT Specification</a>
52  * @xsl.usage advanced
53  */

54 public class ElemForEach extends ElemTemplateElement implements ExpressionOwner
55 {
56   /** Set true to request some basic status reports */
57   static final boolean DEBUG = false;
58   
59   /**
60    * This is set by an "xalan-doc-cache-off" pi, or the old "xalan:doc-cache-off" pi.
61    * The old form of the PI only works for XML parsers that are not namespace aware.
62    * It tells the engine that
63    * documents created in the location paths executed by this element
64    * will not be reparsed. It's set by StylesheetHandler during
65    * construction. Note that this feature applies _only_ to xsl:for-each
66    * elements in its current incarnation; a more general cache management
67    * solution is desperately needed.
68    */

69   public boolean m_doc_cache_off=false;
70   
71   /**
72    * Construct a element representing xsl:for-each.
73    */

74   public ElemForEach(){}
75
76   /**
77    * The "select" expression.
78    * @serial
79    */

80   protected Expression m_selectExpression = null;
81   
82   
83   /**
84    * Used to fix bug#16889
85    * Store XPath away for later processing.
86    */

87   protected XPath m_xpath = null;
88
89   /**
90    * Set the "select" attribute.
91    *
92    * @param xpath The XPath expression for the "select" attribute.
93    */

94   public void setSelect(XPath xpath)
95   {
96     m_selectExpression = xpath.getExpression();
97     
98     // The following line is part of the codes added to fix bug#16889
99
// Store xpath which will be needed when firing Selected Event
100
m_xpath = xpath;
101   }
102
103   /**
104    * Get the "select" attribute.
105    *
106    * @return The XPath expression for the "select" attribute.
107    */

108   public Expression getSelect()
109   {
110     return m_selectExpression;
111   }
112
113   /**
114    * This function is called after everything else has been
115    * recomposed, and allows the template to set remaining
116    * values that may be based on some other property that
117    * depends on recomposition.
118    *
119    * NEEDSDOC @param sroot
120    *
121    * @throws TransformerException
122    */

123   public void compose(StylesheetRoot sroot) throws TransformerException JavaDoc
124   {
125
126     super.compose(sroot);
127
128     int length = getSortElemCount();
129
130     for (int i = 0; i < length; i++)
131     {
132       getSortElem(i).compose(sroot);
133     }
134
135     java.util.Vector JavaDoc vnames = sroot.getComposeState().getVariableNames();
136
137     if (null != m_selectExpression)
138       m_selectExpression.fixupVariables(
139         vnames, sroot.getComposeState().getGlobalsSize());
140     else
141     {
142       m_selectExpression =
143         getStylesheetRoot().m_selectDefault.getExpression();
144     }
145   }
146   
147   /**
148    * This after the template's children have been composed.
149    */

150   public void endCompose(StylesheetRoot sroot) throws TransformerException JavaDoc
151   {
152     int length = getSortElemCount();
153
154     for (int i = 0; i < length; i++)
155     {
156       getSortElem(i).endCompose(sroot);
157     }
158     
159     super.endCompose(sroot);
160   }
161
162
163   // /**
164
// * This function is called after everything else has been
165
// * recomposed, and allows the template to set remaining
166
// * values that may be based on some other property that
167
// * depends on recomposition.
168
// *
169
// * @throws TransformerException
170
// */
171
// public void compose() throws TransformerException
172
// {
173
//
174
// if (null == m_selectExpression)
175
// {
176
// m_selectExpression =
177
// getStylesheetRoot().m_selectDefault.getExpression();
178
// }
179
// }
180

181   /**
182    * Vector containing the xsl:sort elements associated with this element.
183    * @serial
184    */

185   protected Vector JavaDoc m_sortElems = null;
186
187   /**
188    * Get the count xsl:sort elements associated with this element.
189    * @return The number of xsl:sort elements.
190    */

191   public int getSortElemCount()
192   {
193     return (m_sortElems == null) ? 0 : m_sortElems.size();
194   }
195
196   /**
197    * Get a xsl:sort element associated with this element.
198    *
199    * @param i Index of xsl:sort element to get
200    *
201    * @return xsl:sort element at given index
202    */

203   public ElemSort getSortElem(int i)
204   {
205     return (ElemSort) m_sortElems.elementAt(i);
206   }
207
208   /**
209    * Set a xsl:sort element associated with this element.
210    *
211    * @param sortElem xsl:sort element to set
212    */

213   public void setSortElem(ElemSort sortElem)
214   {
215
216     if (null == m_sortElems)
217       m_sortElems = new Vector JavaDoc();
218
219     m_sortElems.addElement(sortElem);
220   }
221
222   /**
223    * Get an int constant identifying the type of element.
224    * @see org.apache.xalan.templates.Constants
225    *
226    * @return The token ID for this element
227    */

228   public int getXSLToken()
229   {
230     return Constants.ELEMNAME_FOREACH;
231   }
232
233   /**
234    * Return the node name.
235    *
236    * @return The element's name
237    */

238   public String JavaDoc getNodeName()
239   {
240     return Constants.ELEMNAME_FOREACH_STRING;
241   }
242
243   /**
244    * Execute the xsl:for-each transformation
245    *
246    * @param transformer non-null reference to the the current transform-time state.
247    *
248    * @throws TransformerException
249    */

250   public void execute(TransformerImpl transformer) throws TransformerException JavaDoc
251   {
252
253     transformer.pushCurrentTemplateRuleIsNull(true);
254     if (TransformerImpl.S_DEBUG)
255       transformer.getTraceManager().fireTraceEvent(this);//trigger for-each element event
256

257     try
258     {
259       transformSelectedNodes(transformer);
260     }
261     finally
262     {
263       if (TransformerImpl.S_DEBUG)
264         transformer.getTraceManager().fireTraceEndEvent(this);
265       transformer.popCurrentTemplateRuleIsNull();
266     }
267   }
268
269   /**
270    * Get template element associated with this
271    *
272    *
273    * @return template element associated with this (itself)
274    */

275   protected ElemTemplateElement getTemplateMatch()
276   {
277     return this;
278   }
279
280   /**
281    * Sort given nodes
282    *
283    *
284    * @param xctxt The XPath runtime state for the sort.
285    * @param keys Vector of sort keyx
286    * @param sourceNodes Iterator of nodes to sort
287    *
288    * @return iterator of sorted nodes
289    *
290    * @throws TransformerException
291    */

292   public DTMIterator sortNodes(
293           XPathContext xctxt, Vector JavaDoc keys, DTMIterator sourceNodes)
294             throws TransformerException JavaDoc
295   {
296
297     NodeSorter sorter = new NodeSorter(xctxt);
298     sourceNodes.setShouldCacheNodes(true);
299     sourceNodes.runTo(-1);
300     xctxt.pushContextNodeList(sourceNodes);
301
302     try
303     {
304       sorter.sort(sourceNodes, keys, xctxt);
305       sourceNodes.setCurrentPos(0);
306     }
307     finally
308     {
309       xctxt.popContextNodeList();
310     }
311
312     return sourceNodes;
313   }
314
315   /**
316    * Perform a query if needed, and call transformNode for each child.
317    *
318    * @param transformer non-null reference to the the current transform-time state.
319    * @param template The owning template context.
320    *
321    * @throws TransformerException Thrown in a variety of circumstances.
322    * @xsl.usage advanced
323    */

324   public void transformSelectedNodes(TransformerImpl transformer)
325           throws TransformerException JavaDoc
326   {
327
328     final XPathContext xctxt = transformer.getXPathContext();
329     final int sourceNode = xctxt.getCurrentNode();
330     DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt,
331             sourceNode);
332
333     try
334     {
335
336       final Vector JavaDoc keys = (m_sortElems == null)
337               ? null
338               : transformer.processSortKeys(this, sourceNode);
339
340       // Sort if we need to.
341
if (null != keys)
342         sourceNodes = sortNodes(xctxt, keys, sourceNodes);
343
344     if (TransformerImpl.S_DEBUG)
345     {
346
347         // The original code, which is broken for bug#16889,
348
// which fails to get the original select expression in the select event.
349
/* transformer.getTraceManager().fireSelectedEvent(
350          * sourceNode,
351          * this,
352          * "select",
353          * new XPath(m_selectExpression),
354          * new org.apache.xpath.objects.XNodeSet(sourceNodes));
355          */

356
357         // The following code fixes bug#16889
358
// Solution: Store away XPath in setSelect(Xath), and use it here.
359
// Pass m_xath, which the current node is associated with, onto the TraceManager.
360

361         Expression expr = m_xpath.getExpression();
362         org.apache.xpath.objects.XObject xObject = expr.execute(xctxt);
363         int current = xctxt.getCurrentNode();
364         transformer.getTraceManager().fireSelectedEvent(
365             current,
366             this,
367             "select",
368             m_xpath,
369             xObject);
370     }
371
372
373
374       xctxt.pushCurrentNode(DTM.NULL);
375
376       IntStack currentNodes = xctxt.getCurrentNodeStack();
377
378       xctxt.pushCurrentExpressionNode(DTM.NULL);
379
380       IntStack currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
381
382       xctxt.pushSAXLocatorNull();
383       xctxt.pushContextNodeList(sourceNodes);
384       transformer.pushElemTemplateElement(null);
385
386       // pushParams(transformer, xctxt);
387
// Should be able to get this from the iterator but there must be a bug.
388
DTM dtm = xctxt.getDTM(sourceNode);
389       int docID = sourceNode & DTMManager.IDENT_DTM_DEFAULT;
390       int child;
391
392       while (DTM.NULL != (child = sourceNodes.nextNode()))
393       {
394         currentNodes.setTop(child);
395         currentExpressionNodes.setTop(child);
396
397         if ((child & DTMManager.IDENT_DTM_DEFAULT) != docID)
398         {
399           dtm = xctxt.getDTM(child);
400           docID = child & DTMManager.IDENT_DTM_DEFAULT;
401         }
402
403         //final int exNodeType = dtm.getExpandedTypeID(child);
404
final int nodeType = dtm.getNodeType(child);
405
406         // Fire a trace event for the template.
407
if (TransformerImpl.S_DEBUG)
408         {
409            transformer.getTraceManager().fireTraceEvent(this);
410         }
411
412         // And execute the child templates.
413
// Loop through the children of the template, calling execute on
414
// each of them.
415
for (ElemTemplateElement t = this.m_firstChild; t != null;
416              t = t.m_nextSibling)
417         {
418           xctxt.setSAXLocator(t);
419           transformer.setCurrentElement(t);
420           t.execute(transformer);
421         }
422         
423         if (TransformerImpl.S_DEBUG)
424         {
425          // We need to make sure an old current element is not
426
// on the stack. See TransformerImpl#getElementCallstack.
427
transformer.setCurrentElement(null);
428           transformer.getTraceManager().fireTraceEndEvent(this);
429         }
430
431
432         // KLUGE: Implement <?xalan:doc_cache_off?>
433
// ASSUMPTION: This will be set only when the XPath was indeed
434
// a call to the Document() function. Calling it in other
435
// situations is likely to fry Xalan.
436
//
437
// %REVIEW% We need a MUCH cleaner solution -- one that will
438
// handle cleaning up after document() and getDTM() in other
439
// contexts. The whole SourceTreeManager mechanism should probably
440
// be moved into DTMManager rather than being explicitly invoked in
441
// FuncDocument and here.
442
if(m_doc_cache_off)
443         {
444           if(DEBUG)
445             System.out.println("JJK***** CACHE RELEASE *****\n"+
446                        "\tdtm="+dtm.getDocumentBaseURI());
447         // NOTE: This will work because this is _NOT_ a shared DTM, and thus has
448
// only a single Document node. If it could ever be an RTF or other
449
// shared DTM, this would require substantial rework.
450
xctxt.getSourceTreeManager().removeDocumentFromCache(dtm.getDocument());
451           xctxt.release(dtm,false);
452         }
453       }
454     }
455     finally
456     {
457       if (TransformerImpl.S_DEBUG)
458         transformer.getTraceManager().fireSelectedEndEvent(sourceNode, this,
459                 "select", new XPath(m_selectExpression),
460                 new org.apache.xpath.objects.XNodeSet(sourceNodes));
461
462       xctxt.popSAXLocator();
463       xctxt.popContextNodeList();
464       transformer.popElemTemplateElement();
465       xctxt.popCurrentExpressionNode();
466       xctxt.popCurrentNode();
467       sourceNodes.detach();
468     }
469   }
470
471   /**
472    * Add a child to the child list.
473    * <!ELEMENT xsl:apply-templates (xsl:sort|xsl:with-param)*>
474    * <!ATTLIST xsl:apply-templates
475    * select %expr; "node()"
476    * mode %qname; #IMPLIED
477    * >
478    *
479    * @param newChild Child to add to child list
480    *
481    * @return Child just added to child list
482    */

483   public ElemTemplateElement appendChild(ElemTemplateElement newChild)
484   {
485
486     int type = ((ElemTemplateElement) newChild).getXSLToken();
487
488     if (Constants.ELEMNAME_SORT == type)
489     {
490       setSortElem((ElemSort) newChild);
491
492       return newChild;
493     }
494     else
495       return super.appendChild(newChild);
496   }
497   
498   /**
499    * Call the children visitors.
500    * @param visitor The visitor whose appropriate method will be called.
501    */

502   public void callChildVisitors(XSLTVisitor visitor, boolean callAttributes)
503   {
504     if(callAttributes && (null != m_selectExpression))
505         m_selectExpression.callVisitors(this, visitor);
506         
507     int length = getSortElemCount();
508
509     for (int i = 0; i < length; i++)
510     {
511       getSortElem(i).callVisitors(visitor);
512     }
513
514     super.callChildVisitors(visitor, callAttributes);
515   }
516
517   /**
518    * @see ExpressionOwner#getExpression()
519    */

520   public Expression getExpression()
521   {
522     return m_selectExpression;
523   }
524
525   /**
526    * @see ExpressionOwner#setExpression(Expression)
527    */

528   public void setExpression(Expression exp)
529   {
530     exp.exprSetParent(this);
531     m_selectExpression = exp;
532   }
533
534 }
535
Popular Tags