OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / org / apache / xpath / operations / Variable.java
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
346   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
347   {
348         visitor.visitVariableRef(owner, this);
349   }
350   /**
351    * @see Expression#deepEquals(Expression)
352    */
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    */
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 }