• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id: Variable.java 468655 2006-10-28 07:12:06Z minchau $
20  */
21 package org.apache.xpath.operations;
22 
23 import javax.xml.transform.TransformerException;
24 
25 import org.apache.xalan.res.XSLMessages;
26 import org.apache.xml.utils.QName;
27 import org.apache.xpath.Expression;
28 import org.apache.xpath.ExpressionOwner;
29 import org.apache.xpath.XPath;
30 import org.apache.xpath.XPathContext;
31 import org.apache.xpath.XPathVisitor;
32 import org.apache.xpath.axes.PathComponent;
33 import org.apache.xpath.axes.WalkerFactory;
34 import org.apache.xpath.objects.XNodeSet;
35 import org.apache.xpath.objects.XObject;
36 import org.apache.xpath.res.XPATHErrorResources;
37 
38 
39 /**
40  * The variable reference expression executer.
41  */
42 public class Variable extends Expression implements PathComponent
43 {
44     static final long serialVersionUID = -4334975375609297049L;
45   /** Tell if fixupVariables was called.
46    *  @serial   */
47   private boolean m_fixUpWasCalled = false;
48 
49   /** The qualified name of the variable.
50    *  @serial   */
51   protected QName m_qname;
52 
53   /**
54    * The index of the variable, which is either an absolute index to a
55    * global, or, if higher than the globals area, must be adjusted by adding
56    * the offset to the current stack frame.
57    */
58   protected int m_index;
59 
60   /**
61    * Set the index for the variable into the stack.  For advanced use only. You
62    * must know what you are doing to use this.
63    *
64    * @param index a global or local index.
65    */
setIndex(int index)66   public void setIndex(int index)
67   {
68   	m_index = index;
69   }
70 
71   /**
72    * Set the index for the variable into the stack.  For advanced use only.
73    *
74    * @return index a global or local index.
75    */
getIndex()76   public int getIndex()
77   {
78   	return m_index;
79   }
80 
81   /**
82    * Set whether or not this is a global reference.  For advanced use only.
83    *
84    * @param isGlobal true if this should be a global variable reference.
85    */
setIsGlobal(boolean isGlobal)86   public void setIsGlobal(boolean isGlobal)
87   {
88   	m_isGlobal = isGlobal;
89   }
90 
91   /**
92    * Set the index for the variable into the stack.  For advanced use only.
93    *
94    * @return true if this should be a global variable reference.
95    */
getGlobal()96   public boolean getGlobal()
97   {
98   	return m_isGlobal;
99   }
100 
101 
102 
103 
104 
105   protected boolean m_isGlobal = false;
106 
107   /**
108    * This function is used to fixup variables from QNames to stack frame
109    * indexes at stylesheet build time.
110    * @param vars List of QNames that correspond to variables.  This list
111    * should be searched backwards for the first qualified name that
112    * corresponds to the variable reference qname.  The position of the
113    * QName in the vector from the start of the vector will be its position
114    * in the stack frame (but variables above the globalsTop value will need
115    * to be offset to the current stack frame).
116    */
fixupVariables(java.util.Vector vars, int globalsSize)117   public void fixupVariables(java.util.Vector vars, int globalsSize)
118   {
119     m_fixUpWasCalled = true;
120     int sz = vars.size();
121 
122     for (int i = vars.size()-1; i >= 0; i--)
123     {
124       QName qn = (QName)vars.elementAt(i);
125       // System.out.println("qn: "+qn);
126       if(qn.equals(m_qname))
127       {
128 
129         if(i < globalsSize)
130         {
131           m_isGlobal = true;
132           m_index = i;
133         }
134         else
135         {
136           m_index = i-globalsSize;
137         }
138 
139         return;
140       }
141     }
142 
143     java.lang.String msg = XSLMessages.createXPATHMessage(XPATHErrorResources.ER_COULD_NOT_FIND_VAR,
144                                              new Object[]{m_qname.toString()});
145 
146     TransformerException te = new TransformerException(msg, this);
147 
148     throw new org.apache.xml.utils.WrappedRuntimeException(te);
149 
150   }
151 
152 
153   /**
154    * Set the qualified name of the variable.
155    *
156    * @param qname Must be a non-null reference to a qualified name.
157    */
setQName(QName qname)158   public void setQName(QName qname)
159   {
160     m_qname = qname;
161   }
162 
163   /**
164    * Get the qualified name of the variable.
165    *
166    * @return A non-null reference to a qualified name.
167    */
getQName()168   public QName getQName()
169   {
170     return m_qname;
171   }
172 
173   /**
174    * Execute an expression in the XPath runtime context, and return the
175    * result of the expression.
176    *
177    *
178    * @param xctxt The XPath runtime context.
179    *
180    * @return The result of the expression in the form of a <code>XObject</code>.
181    *
182    * @throws javax.xml.transform.TransformerException if a runtime exception
183    *         occurs.
184    */
execute(XPathContext xctxt)185   public XObject execute(XPathContext xctxt)
186     throws javax.xml.transform.TransformerException
187   {
188   	return execute(xctxt, false);
189   }
190 
191 
192   /**
193    * Dereference the variable, and return the reference value.  Note that lazy
194    * evaluation will occur.  If a variable within scope is not found, a warning
195    * will be sent to the error listener, and an empty nodeset will be returned.
196    *
197    *
198    * @param xctxt The runtime execution context.
199    *
200    * @return The evaluated variable, or an empty nodeset if not found.
201    *
202    * @throws javax.xml.transform.TransformerException
203    */
execute(XPathContext xctxt, boolean destructiveOK)204   public XObject execute(XPathContext xctxt, boolean destructiveOK) throws javax.xml.transform.TransformerException
205   {
206     org.apache.xml.utils.PrefixResolver xprefixResolver = xctxt.getNamespaceContext();
207 
208     XObject result;
209     // Is the variable fetched always the same?
210     // XObject result = xctxt.getVariable(m_qname);
211     if(m_fixUpWasCalled)
212     {
213       if(m_isGlobal)
214         result = xctxt.getVarStack().getGlobalVariable(xctxt, m_index, destructiveOK);
215       else
216         result = xctxt.getVarStack().getLocalVariable(xctxt, m_index, destructiveOK);
217     }
218     else {
219     	result = xctxt.getVarStack().getVariableOrParam(xctxt,m_qname);
220     }
221 
222       if (null == result)
223       {
224         // This should now never happen...
225         warn(xctxt, XPATHErrorResources.WG_ILLEGAL_VARIABLE_REFERENCE,
226              new Object[]{ m_qname.getLocalPart() });  //"VariableReference given for variable out "+
227   //      (new RuntimeException()).printStackTrace();
228   //      error(xctxt, XPATHErrorResources.ER_COULDNOT_GET_VAR_NAMED,
229   //            new Object[]{ m_qname.getLocalPart() });  //"Could not get variable named "+varName);
230 
231         result = new XNodeSet(xctxt.getDTMManager());
232       }
233 
234       return result;
235 //    }
236 //    else
237 //    {
238 //      // Hack city... big time.  This is needed to evaluate xpaths from extensions,
239 //      // pending some bright light going off in my head.  Some sort of callback?
240 //      synchronized(this)
241 //      {
242 //      	org.apache.xalan.templates.ElemVariable vvar= getElemVariable();
243 //      	if(null != vvar)
244 //      	{
245 //          m_index = vvar.getIndex();
246 //          m_isGlobal = vvar.getIsTopLevel();
247 //          m_fixUpWasCalled = true;
248 //          return execute(xctxt);
249 //      	}
250 //      }
251 //      throw new javax.xml.transform.TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VAR_NOT_RESOLVABLE, new Object[]{m_qname.toString()})); //"Variable not resolvable: "+m_qname);
252 //    }
253   }
254 
255   /**
256    * Get the XSLT ElemVariable that this sub-expression references.  In order for
257    * this to work, the SourceLocator must be the owning ElemTemplateElement.
258    * @return The dereference to the ElemVariable, or null if not found.
259    */
getElemVariable()260   public org.apache.xalan.templates.ElemVariable getElemVariable()
261   {
262 
263     // Get the current ElemTemplateElement, and then walk backwards in
264     // document order, searching
265     // for an xsl:param element or xsl:variable element that matches our
266     // qname.  If we reach the top level, use the StylesheetRoot's composed
267     // list of top level variables and parameters.
268 
269     org.apache.xalan.templates.ElemVariable vvar = null;
270     org.apache.xpath.ExpressionNode owner = getExpressionOwner();
271 
272     if (null != owner && owner instanceof org.apache.xalan.templates.ElemTemplateElement)
273     {
274 
275       org.apache.xalan.templates.ElemTemplateElement prev =
276         (org.apache.xalan.templates.ElemTemplateElement) owner;
277 
278       if (!(prev instanceof org.apache.xalan.templates.Stylesheet))
279       {
280         while ( prev != null && !(prev.getParentNode() instanceof org.apache.xalan.templates.Stylesheet) )
281         {
282           org.apache.xalan.templates.ElemTemplateElement savedprev = prev;
283 
284           while (null != (prev = prev.getPreviousSiblingElem()))
285           {
286             if(prev instanceof org.apache.xalan.templates.ElemVariable)
287             {
288               vvar = (org.apache.xalan.templates.ElemVariable) prev;
289 
290               if (vvar.getName().equals(m_qname))
291               {
292                 return vvar;
293               }
294               vvar = null;
295             }
296           }
297           prev = savedprev.getParentElem();
298         }
299       }
300       if (prev != null)
301         vvar = prev.getStylesheetRoot().getVariableOrParamComposed(m_qname);
302     }
303     return vvar;
304 
305   }
306 
307   /**
308    * Tell if this expression returns a stable number that will not change during
309    * iterations within the expression.  This is used to determine if a proximity
310    * position predicate can indicate that no more searching has to occur.
311    *
312    *
313    * @return true if the expression represents a stable number.
314    */
isStableNumber()315   public boolean isStableNumber()
316   {
317     return true;
318   }
319 
320   /**
321    * Get the analysis bits for this walker, as defined in the WalkerFactory.
322    * @return One of WalkerFactory#BIT_DESCENDANT, etc.
323    */
getAnalysisBits()324   public int getAnalysisBits()
325   {
326   	org.apache.xalan.templates.ElemVariable vvar = getElemVariable();
327   	if(null != vvar)
328   	{
329   		XPath xpath = vvar.getSelect();
330   		if(null != xpath)
331   		{
332 	  		Expression expr = xpath.getExpression();
333 	  		if(null != expr && expr instanceof PathComponent)
334 	  		{
335 	  			return ((PathComponent)expr).getAnalysisBits();
336 	  		}
337   		}
338   	}
339     return WalkerFactory.BIT_FILTER;
340   }
341 
342 
343   /**
344    * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
345    */
callVisitors(ExpressionOwner owner, XPathVisitor visitor)346   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
347   {
348   	visitor.visitVariableRef(owner, this);
349   }
350   /**
351    * @see Expression#deepEquals(Expression)
352    */
deepEquals(Expression expr)353   public boolean deepEquals(Expression expr)
354   {
355   	if(!isSameClass(expr))
356   		return false;
357 
358   	if(!m_qname.equals(((Variable)expr).m_qname))
359   		return false;
360 
361   	// We have to make sure that the qname really references
362   	// the same variable element.
363     if(getElemVariable() != ((Variable)expr).getElemVariable())
364     	return false;
365 
366   	return true;
367   }
368 
369   static final java.lang.String PSUEDOVARNAMESPACE = "http://xml.apache.org/xalan/psuedovar";
370 
371   /**
372    * Tell if this is a psuedo variable reference, declared by Xalan instead
373    * of by the user.
374    */
isPsuedoVarRef()375   public boolean isPsuedoVarRef()
376   {
377   	java.lang.String ns = m_qname.getNamespaceURI();
378   	if((null != ns) && ns.equals(PSUEDOVARNAMESPACE))
379   	{
380   		if(m_qname.getLocalName().startsWith("#"))
381   			return true;
382   	}
383   	return false;
384   }
385 
386 
387 }
388