KickJava   Java API By Example, From Geeks To Geeks.

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


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: ElemVariable.java,v 1.26 2004/02/16 20:32:33 minchau Exp $
18  */

19 package org.apache.xalan.templates;
20
21 import javax.xml.transform.TransformerException JavaDoc;
22
23 import org.apache.xalan.transformer.TransformerImpl;
24 import org.apache.xml.utils.QName;
25 import org.apache.xpath.XPath;
26 import org.apache.xpath.XPathContext;
27 import org.apache.xpath.objects.XObject;
28 import org.apache.xpath.objects.XRTreeFrag;
29 import org.apache.xpath.objects.XRTreeFragSelectWrapper;
30 import org.apache.xpath.objects.XString;
31 import org.apache.xalan.res.XSLTErrorResources;
32
33 /**
34  * Implement xsl:variable.
35  * <pre>
36  * <!ELEMENT xsl:variable %template;>
37  * <!ATTLIST xsl:variable
38  * name %qname; #REQUIRED
39  * select %expr; #IMPLIED
40  * >
41  * </pre>
42  * @see <a HREF="http://www.w3.org/TR/xslt#variables">variables in XSLT Specification</a>
43  * @xsl.usage advanced
44  */

45 public class ElemVariable extends ElemTemplateElement
46 {
47
48   /**
49    * Constructor ElemVariable
50    *
51    */

52   public ElemVariable(){}
53
54   /**
55    * This is the index into the stack frame.
56    */

57   protected int m_index;
58   
59   /**
60    * The stack frame size for this variable if it is a global variable
61    * that declares an RTF, which is equal to the maximum number
62    * of variables that can be declared in the variable at one time.
63    */

64   int m_frameSize = -1;
65
66   
67   /**
68    * Sets the relative position of this variable within the stack frame (if local)
69    * or the global area (if global). Note that this should be called only for
70    * global variables since the local position is computed in the compose() method.
71    */

72   public void setIndex(int index)
73   {
74     m_index = index;
75   }
76
77   /**
78    * If this element is not at the top-level, get the relative position of the
79    * variable into the stack frame. If this variable is at the top-level, get
80    * the relative position within the global area.
81    */

82   public int getIndex()
83   {
84     return m_index;
85   }
86
87   /**
88    * The value of the "select" attribute.
89    * @serial
90    */

91   private XPath m_selectPattern;
92
93   /**
94    * Set the "select" attribute.
95    * If the variable-binding element has a select attribute,
96    * then the value of the attribute must be an expression and
97    * the value of the variable is the object that results from
98    * evaluating the expression. In this case, the content
99    * of the variable must be empty.
100    *
101    * @param v Value to set for the "select" attribute.
102    */

103   public void setSelect(XPath v)
104   {
105     m_selectPattern = v;
106   }
107
108   /**
109    * Get the "select" attribute.
110    * If the variable-binding element has a select attribute,
111    * then the value of the attribute must be an expression and
112    * the value of the variable is the object that results from
113    * evaluating the expression. In this case, the content
114    * of the variable must be empty.
115    *
116    * @return Value of the "select" attribute.
117    */

118   public XPath getSelect()
119   {
120     return m_selectPattern;
121   }
122
123   /**
124    * The value of the "name" attribute.
125    * @serial
126    */

127   protected QName m_qname;
128
129   /**
130    * Set the "name" attribute.
131    * Both xsl:variable and xsl:param have a required name
132    * attribute, which specifies the name of the variable. The
133    * value of the name attribute is a QName, which is expanded
134    * as described in [2.4 Qualified Names].
135    * @see <a HREF="http://www.w3.org/TR/xslt#qname">qname in XSLT Specification</a>
136    *
137    * @param v Value to set for the "name" attribute.
138    */

139   public void setName(QName v)
140   {
141     m_qname = v;
142   }
143
144   /**
145    * Get the "name" attribute.
146    * Both xsl:variable and xsl:param have a required name
147    * attribute, which specifies the name of the variable. The
148    * value of the name attribute is a QName, which is expanded
149    * as described in [2.4 Qualified Names].
150    * @see <a HREF="http://www.w3.org/TR/xslt#qname">qname in XSLT Specification</a>
151    *
152    * @return Value of the "name" attribute.
153    */

154   public QName getName()
155   {
156     return m_qname;
157   }
158
159   /**
160    * Tells if this is a top-level variable or param, or not.
161    * @serial
162    */

163   private boolean m_isTopLevel = false;
164
165   /**
166    * Set if this is a top-level variable or param, or not.
167    * @see <a HREF="http://www.w3.org/TR/xslt#top-level-variables">top-level-variables in XSLT Specification</a>
168    *
169    * @param v Boolean indicating whether this is a top-level variable
170    * or param, or not.
171    */

172   public void setIsTopLevel(boolean v)
173   {
174     m_isTopLevel = v;
175   }
176
177   /**
178    * Get if this is a top-level variable or param, or not.
179    * @see <a HREF="http://www.w3.org/TR/xslt#top-level-variables">top-level-variables in XSLT Specification</a>
180    *
181    * @return Boolean indicating whether this is a top-level variable
182    * or param, or not.
183    */

184   public boolean getIsTopLevel()
185   {
186     return m_isTopLevel;
187   }
188
189   /**
190    * Get an integer representation of the element type.
191    *
192    * @return An integer representation of the element, defined in the
193    * Constants class.
194    * @see org.apache.xalan.templates.Constants
195    */

196   public int getXSLToken()
197   {
198     return Constants.ELEMNAME_VARIABLE;
199   }
200
201   /**
202    * Return the node name.
203    *
204    * @return The node name
205    */

206   public String JavaDoc getNodeName()
207   {
208     return Constants.ELEMNAME_VARIABLE_STRING;
209   }
210
211   /**
212    * Copy constructor.
213    *
214    * @param param An element created from an xsl:variable
215    *
216    * @throws TransformerException
217    */

218   public ElemVariable(ElemVariable param) throws TransformerException JavaDoc
219   {
220
221     m_selectPattern = param.m_selectPattern;
222     m_qname = param.m_qname;
223     m_isTopLevel = param.m_isTopLevel;
224
225     // m_value = param.m_value;
226
// m_varContext = param.m_varContext;
227
}
228
229   /**
230    * Execute a variable declaration and push it onto the variable stack.
231    * @see <a HREF="http://www.w3.org/TR/xslt#variables">variables in XSLT Specification</a>
232    *
233    * @param transformer non-null reference to the the current transform-time state.
234    * @param sourceNode non-null reference to the <a HREF="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
235    * @param mode reference, which may be null, to the <a HREF="http://www.w3.org/TR/xslt#modes">current mode</a>.
236    *
237    * @throws TransformerException
238    */

239   public void execute(TransformerImpl transformer) throws TransformerException JavaDoc
240   {
241
242     if (TransformerImpl.S_DEBUG)
243       transformer.getTraceManager().fireTraceEvent(this);
244
245     int sourceNode = transformer.getXPathContext().getCurrentNode();
246   
247     XObject var = getValue(transformer, sourceNode);
248
249     // transformer.getXPathContext().getVarStack().pushVariable(m_qname, var);
250
transformer.getXPathContext().getVarStack().setLocalVariable(m_index, var);
251     
252     if (TransformerImpl.S_DEBUG)
253       transformer.getTraceManager().fireTraceEndEvent(this);
254   }
255
256   /**
257    * Get the XObject representation of the variable.
258    *
259    * @param transformer non-null reference to the the current transform-time state.
260    * @param sourceNode non-null reference to the <a HREF="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
261    *
262    * @return the XObject representation of the variable.
263    *
264    * @throws TransformerException
265    */

266   public XObject getValue(TransformerImpl transformer, int sourceNode)
267           throws TransformerException JavaDoc
268   {
269
270     XObject var;
271     XPathContext xctxt = transformer.getXPathContext();
272
273     xctxt.pushCurrentNode(sourceNode);
274  
275     try
276     {
277       if (null != m_selectPattern)
278       {
279         var = m_selectPattern.execute(xctxt, sourceNode, this);
280
281         var.allowDetachToRelease(false);
282
283         if (TransformerImpl.S_DEBUG)
284           transformer.getTraceManager().fireSelectedEvent(sourceNode, this,
285                   "select", m_selectPattern, var);
286       }
287       else if (null == getFirstChildElem())
288       {
289         var = XString.EMPTYSTRING;
290       }
291       else
292       {
293
294         // Use result tree fragment.
295
// Global variables may be deferred (see XUnresolvedVariable) and hence
296
// need to be assigned to a different set of DTMs than local variables
297
// so they aren't popped off the stack on return from a template.
298
int df;
299
300         // Bugzilla 7118: A variable set via an RTF may create local
301
// variables during that computation. To keep them from overwriting
302
// variables at this level, push a new variable stack.
303
////// PROBLEM: This is provoking a variable-used-before-set
304
////// problem in parameters. Needs more study.
305
try
306         {
307             //////////xctxt.getVarStack().link(0);
308
if(m_parentNode instanceof Stylesheet) // Global variable
309
df = transformer.transformToGlobalRTF(this);
310             else
311                 df = transformer.transformToRTF(this);
312         }
313         finally{
314             //////////////xctxt.getVarStack().unlink();
315
}
316
317         var = new XRTreeFrag(df, xctxt, this);
318       }
319     }
320     finally
321     {
322       xctxt.popCurrentNode();
323     }
324
325     return var;
326   }
327   
328   
329   /**
330    * This function is called after everything else has been
331    * recomposed, and allows the template to set remaining
332    * values that may be based on some other property that
333    * depends on recomposition.
334    */

335   public void compose(StylesheetRoot sroot) throws TransformerException JavaDoc
336   {
337     // See if we can reduce an RTF to a select with a string expression.
338
if(null == m_selectPattern
339        && org.apache.xalan.processor.TransformerFactoryImpl.m_optimize)
340     {
341       XPath newSelect = rewriteChildToExpression(this);
342       if(null != newSelect)
343         m_selectPattern = newSelect;
344     }
345     
346     StylesheetRoot.ComposeState cstate = sroot.getComposeState();
347     
348     // This should be done before addVariableName, so we don't have visibility
349
// to the variable now being defined.
350
java.util.Vector JavaDoc vnames = cstate.getVariableNames();
351     if(null != m_selectPattern)
352       m_selectPattern.fixupVariables(vnames, cstate.getGlobalsSize());
353       
354     // Only add the variable if this is not a global. If it is a global,
355
// it was already added by stylesheet root.
356
if(!(m_parentNode instanceof Stylesheet) && m_qname != null)
357     {
358       m_index = cstate.addVariableName(m_qname) - cstate.getGlobalsSize();
359     }
360     else if (m_parentNode instanceof Stylesheet)
361     {
362         // If this is a global, then we need to treat it as if it's a xsl:template,
363
// and count the number of variables it contains. So we set the count to
364
// zero here.
365
cstate.resetStackFrameSize();
366     }
367     
368     // This has to be done after the addVariableName, so that the variable
369
// pushed won't be immediately popped again in endCompose.
370
super.compose(sroot);
371   }
372   
373   /**
374    * This after the template's children have been composed. We have to get
375    * the count of how many variables have been declared, so we can do a link
376    * and unlink.
377    */

378   public void endCompose(StylesheetRoot sroot) throws TransformerException JavaDoc
379   {
380     super.endCompose(sroot);
381     if(m_parentNode instanceof Stylesheet)
382     {
383         StylesheetRoot.ComposeState cstate = sroot.getComposeState();
384         m_frameSize = cstate.getFrameSize();
385         cstate.resetStackFrameSize();
386     }
387   }
388
389   
390   
391 // /**
392
// * This after the template's children have been composed.
393
// */
394
// public void endCompose() throws TransformerException
395
// {
396
// super.endCompose();
397
// }
398

399
400   /**
401    * If the children of a variable is a single xsl:value-of or text literal,
402    * it is cheaper to evaluate this as an expression, so try and adapt the
403    * child an an expression.
404    *
405    * @param varElem Should be a ElemParam, ElemVariable, or ElemWithParam.
406    *
407    * @return An XPath if rewrite is possible, else null.
408    *
409    * @throws TransformerException
410    */

411   static XPath rewriteChildToExpression(ElemTemplateElement varElem)
412           throws TransformerException JavaDoc
413   {
414
415     ElemTemplateElement t = varElem.getFirstChildElem();
416
417     // Down the line this can be done with multiple string objects using
418
// the concat function.
419
if (null != t && null == t.getNextSiblingElem())
420     {
421       int etype = t.getXSLToken();
422
423       if (Constants.ELEMNAME_VALUEOF == etype)
424       {
425         ElemValueOf valueof = (ElemValueOf) t;
426
427         // %TBD% I'm worried about extended attributes here.
428
if (valueof.getDisableOutputEscaping() == false
429                 && valueof.getDOMBackPointer() == null)
430         {
431           varElem.m_firstChild = null;
432
433           return new XPath(new XRTreeFragSelectWrapper(valueof.getSelect().getExpression()));
434         }
435       }
436       else if (Constants.ELEMNAME_TEXTLITERALRESULT == etype)
437       {
438         ElemTextLiteral lit = (ElemTextLiteral) t;
439
440         if (lit.getDisableOutputEscaping() == false
441                 && lit.getDOMBackPointer() == null)
442         {
443           String JavaDoc str = lit.getNodeValue();
444           XString xstr = new XString(str);
445
446           varElem.m_firstChild = null;
447
448           return new XPath(new XRTreeFragSelectWrapper(xstr));
449         }
450       }
451     }
452
453     return null;
454   }
455
456   /**
457    * This function is called during recomposition to
458    * control how this element is composed.
459    * @param root The root stylesheet for this transformation.
460    */

461   public void recompose(StylesheetRoot root)
462   {
463     root.recomposeVariables(this);
464   }
465   
466   /**
467    * Set the parent as an ElemTemplateElement.
468    *
469    * @param parent This node's parent as an ElemTemplateElement
470    */

471   public void setParentElem(ElemTemplateElement p)
472   {
473     super.setParentElem(p);
474     p.m_hasVariableDecl = true;
475   }
476   
477   /**
478    * Accept a visitor and call the appropriate method
479    * for this class.
480    *
481    * @param visitor The visitor whose appropriate method will be called.
482    * @return true if the children of the object should be visited.
483    */

484   protected boolean accept(XSLTVisitor visitor)
485   {
486     return visitor.visitVariableOrParamDecl(this);
487   }
488
489   
490   /**
491    * Call the children visitors.
492    * @param visitor The visitor whose appropriate method will be called.
493    */

494   protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
495   {
496     if(null != m_selectPattern)
497         m_selectPattern.getExpression().callVisitors(m_selectPattern, visitor);
498     super.callChildVisitors(visitor, callAttrs);
499   }
500   
501   /**
502    * Tell if this is a psuedo variable reference, declared by Xalan instead
503    * of by the user.
504    */

505   public boolean isPsuedoVar()
506   {
507     java.lang.String JavaDoc ns = m_qname.getNamespaceURI();
508     if((null != ns) && ns.equals(RedundentExprEliminator.PSUEDOVARNAMESPACE))
509     {
510         if(m_qname.getLocalName().startsWith("#"))
511             return true;
512     }
513     return false;
514   }
515   
516   /**
517    * Add a child to the child list. If the select attribute
518    * is present, an error will be raised.
519    *
520    * @param elem New element to append to this element's children list
521    *
522    * @return null if the select attribute was present, otherwise the
523    * child just added to the child list
524    */

525   public ElemTemplateElement appendChild(ElemTemplateElement elem)
526   {
527     // cannot have content and select
528
if (m_selectPattern != null)
529     {
530       error(XSLTErrorResources.ER_CANT_HAVE_CONTENT_AND_SELECT,
531           new Object JavaDoc[]{"xsl:" + this.getNodeName()});
532       return null;
533     }
534     return super.appendChild(elem);
535   }
536
537 }
538
Popular Tags