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. package com.sun.org.apache.xpath.internal.operations;
  17. import javax.xml.transform.TransformerException;
  18. import com.sun.org.apache.xalan.internal.res.XSLMessages;
  19. import com.sun.org.apache.xml.internal.utils.QName;
  20. import com.sun.org.apache.xpath.internal.Expression;
  21. import com.sun.org.apache.xpath.internal.ExpressionOwner;
  22. import com.sun.org.apache.xpath.internal.XPath;
  23. import com.sun.org.apache.xpath.internal.XPathContext;
  24. import com.sun.org.apache.xpath.internal.XPathVisitor;
  25. import com.sun.org.apache.xpath.internal.axes.PathComponent;
  26. import com.sun.org.apache.xpath.internal.axes.WalkerFactory;
  27. import com.sun.org.apache.xpath.internal.objects.XNodeSet;
  28. import com.sun.org.apache.xpath.internal.objects.XObject;
  29. import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  30. /**
  31. * The variable reference expression executer.
  32. */
  33. public class Variable extends Expression implements PathComponent
  34. {
  35. /** Tell if fixupVariables was called.
  36. * @serial */
  37. private boolean m_fixUpWasCalled = false;
  38. /** The qualified name of the variable.
  39. * @serial */
  40. protected QName m_qname;
  41. /**
  42. * The index of the variable, which is either an absolute index to a
  43. * global, or, if higher than the globals area, must be adjusted by adding
  44. * the offset to the current stack frame.
  45. */
  46. protected int m_index;
  47. /**
  48. * Set the index for the variable into the stack. For advanced use only. You
  49. * must know what you are doing to use this.
  50. *
  51. * @param index a global or local index.
  52. */
  53. public void setIndex(int index)
  54. {
  55. m_index = index;
  56. }
  57. /**
  58. * Set the index for the variable into the stack. For advanced use only.
  59. *
  60. * @return index a global or local index.
  61. */
  62. public int getIndex()
  63. {
  64. return m_index;
  65. }
  66. /**
  67. * Set whether or not this is a global reference. For advanced use only.
  68. *
  69. * @param isGlobal true if this should be a global variable reference.
  70. */
  71. public void setIsGlobal(boolean isGlobal)
  72. {
  73. m_isGlobal = isGlobal;
  74. }
  75. /**
  76. * Set the index for the variable into the stack. For advanced use only.
  77. *
  78. * @return true if this should be a global variable reference.
  79. */
  80. public boolean getGlobal()
  81. {
  82. return m_isGlobal;
  83. }
  84. protected boolean m_isGlobal = false;
  85. /**
  86. * This function is used to fixup variables from QNames to stack frame
  87. * indexes at stylesheet build time.
  88. * @param vars List of QNames that correspond to variables. This list
  89. * should be searched backwards for the first qualified name that
  90. * corresponds to the variable reference qname. The position of the
  91. * QName in the vector from the start of the vector will be its position
  92. * in the stack frame (but variables above the globalsTop value will need
  93. * to be offset to the current stack frame).
  94. */
  95. public void fixupVariables(java.util.Vector vars, int globalsSize)
  96. {
  97. m_fixUpWasCalled = true;
  98. int sz = vars.size();
  99. for (int i = vars.size()-1; i >= 0; i--)
  100. {
  101. QName qn = (QName)vars.elementAt(i);
  102. // System.out.println("qn: "+qn);
  103. if(qn.equals(m_qname))
  104. {
  105. if(i < globalsSize)
  106. {
  107. m_isGlobal = true;
  108. m_index = i;
  109. }
  110. else
  111. {
  112. m_index = i-globalsSize;
  113. }
  114. return;
  115. }
  116. }
  117. java.lang.String msg = XSLMessages.createXPATHMessage(XPATHErrorResources.ER_COULD_NOT_FIND_VAR,
  118. new Object[]{m_qname.toString()});
  119. TransformerException te = new TransformerException(msg, this);
  120. throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(te);
  121. }
  122. /**
  123. * Set the qualified name of the variable.
  124. *
  125. * @param qname Must be a non-null reference to a qualified name.
  126. */
  127. public void setQName(QName qname)
  128. {
  129. m_qname = qname;
  130. }
  131. /**
  132. * Get the qualified name of the variable.
  133. *
  134. * @return A non-null reference to a qualified name.
  135. */
  136. public QName getQName()
  137. {
  138. return m_qname;
  139. }
  140. /**
  141. * Execute an expression in the XPath runtime context, and return the
  142. * result of the expression.
  143. *
  144. *
  145. * @param xctxt The XPath runtime context.
  146. *
  147. * @return The result of the expression in the form of a <code>XObject</code>.
  148. *
  149. * @throws javax.xml.transform.TransformerException if a runtime exception
  150. * occurs.
  151. */
  152. public XObject execute(XPathContext xctxt)
  153. throws javax.xml.transform.TransformerException
  154. {
  155. return execute(xctxt, false);
  156. }
  157. /**
  158. * Dereference the variable, and return the reference value. Note that lazy
  159. * evaluation will occur. If a variable within scope is not found, a warning
  160. * will be sent to the error listener, and an empty nodeset will be returned.
  161. *
  162. *
  163. * @param xctxt The runtime execution context.
  164. *
  165. * @return The evaluated variable, or an empty nodeset if not found.
  166. *
  167. * @throws javax.xml.transform.TransformerException
  168. */
  169. public XObject execute(XPathContext xctxt, boolean destructiveOK) throws javax.xml.transform.TransformerException
  170. {
  171. com.sun.org.apache.xml.internal.utils.PrefixResolver xprefixResolver = xctxt.getNamespaceContext();
  172. XObject result;
  173. // Is the variable fetched always the same?
  174. // XObject result = xctxt.getVariable(m_qname);
  175. if(m_fixUpWasCalled)
  176. {
  177. if(m_isGlobal)
  178. result = xctxt.getVarStack().getGlobalVariable(xctxt, m_index, destructiveOK);
  179. else
  180. result = xctxt.getVarStack().getLocalVariable(xctxt, m_index, destructiveOK);
  181. } else {
  182. result = xctxt.getVarStack().getVariableOrParam(xctxt,m_qname);
  183. }
  184. if (null == result)
  185. {
  186. // This should now never happen...
  187. warn(xctxt, XPATHErrorResources.WG_ILLEGAL_VARIABLE_REFERENCE,
  188. new Object[]{ m_qname.getLocalPart() }); //"VariableReference given for variable out "+
  189. // (new RuntimeException()).printStackTrace();
  190. // error(xctxt, XPATHErrorResources.ER_COULDNOT_GET_VAR_NAMED,
  191. // new Object[]{ m_qname.getLocalPart() }); //"Could not get variable named "+varName);
  192. result = new XNodeSet(xctxt.getDTMManager());
  193. }
  194. return result;
  195. // }
  196. // else
  197. // {
  198. // // Hack city... big time. This is needed to evaluate xpaths from extensions,
  199. // // pending some bright light going off in my head. Some sort of callback?
  200. // synchronized(this)
  201. // {
  202. // com.sun.org.apache.xalan.internal.templates.ElemVariable vvar= getElemVariable();
  203. // if(null != vvar)
  204. // {
  205. // m_index = vvar.getIndex();
  206. // m_isGlobal = vvar.getIsTopLevel();
  207. // m_fixUpWasCalled = true;
  208. // return execute(xctxt);
  209. // }
  210. // }
  211. // throw new javax.xml.transform.TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VAR_NOT_RESOLVABLE, new Object[]{m_qname.toString()})); //"Variable not resolvable: "+m_qname);
  212. // }
  213. }
  214. /**
  215. * Get the XSLT ElemVariable that this sub-expression references. In order for
  216. * this to work, the SourceLocator must be the owning ElemTemplateElement.
  217. * @return The dereference to the ElemVariable, or null if not found.
  218. */
  219. /*
  220. public com.sun.org.apache.xalan.internal.templates.ElemVariable getElemVariable()
  221. {
  222. // Get the current ElemTemplateElement, and then walk backwards in
  223. // document order, searching
  224. // for an xsl:param element or xsl:variable element that matches our
  225. // qname. If we reach the top level, use the StylesheetRoot's composed
  226. // list of top level variables and parameters.
  227. com.sun.org.apache.xpath.internal.ExpressionNode owner = getExpressionOwner();
  228. if (null != owner && owner instanceof com.sun.org.apache.xalan.internal.templates.ElemTemplateElement)
  229. {
  230. com.sun.org.apache.xalan.internal.templates.ElemVariable vvar;
  231. com.sun.org.apache.xalan.internal.templates.ElemTemplateElement prev =
  232. (com.sun.org.apache.xalan.internal.templates.ElemTemplateElement) owner;
  233. if (!(prev instanceof com.sun.org.apache.xalan.internal.templates.Stylesheet))
  234. {
  235. while ( !(prev.getParentNode() instanceof com.sun.org.apache.xalan.internal.templates.Stylesheet) )
  236. {
  237. com.sun.org.apache.xalan.internal.templates.ElemTemplateElement savedprev = prev;
  238. while (null != (prev = prev.getPreviousSiblingElem()))
  239. {
  240. if(prev instanceof com.sun.org.apache.xalan.internal.templates.ElemVariable)
  241. {
  242. vvar = (com.sun.org.apache.xalan.internal.templates.ElemVariable) prev;
  243. if (vvar.getName().equals(m_qname))
  244. {
  245. return vvar;
  246. }
  247. }
  248. }
  249. prev = savedprev.getParentElem();
  250. }
  251. }
  252. vvar = prev.getStylesheetRoot().getVariableOrParamComposed(m_qname);
  253. if (null != vvar)
  254. {
  255. return vvar;
  256. }
  257. }
  258. return null;
  259. }
  260. */
  261. /**
  262. * Tell if this expression returns a stable number that will not change during
  263. * iterations within the expression. This is used to determine if a proximity
  264. * position predicate can indicate that no more searching has to occur.
  265. *
  266. *
  267. * @return true if the expression represents a stable number.
  268. */
  269. public boolean isStableNumber()
  270. {
  271. return true;
  272. }
  273. /**
  274. * Get the analysis bits for this walker, as defined in the WalkerFactory.
  275. * @return One of WalkerFactory#BIT_DESCENDANT, etc.
  276. */
  277. public int getAnalysisBits()
  278. {
  279. // <<<<<<< TIGER SPECIFIC CHANGE >>>>>>>>>
  280. // As we are not supporting Xalan interpretive we are taking away the functionality
  281. // dependent on XSLT interpretive Transformer. Only way supported is to use XSLTC
  282. // and the execution path needed for supporting standard XPath API defined by
  283. // JAXP 1.3 .
  284. return WalkerFactory.BIT_FILTER;
  285. }
  286. /**
  287. * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
  288. */
  289. public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
  290. {
  291. visitor.visitVariableRef(owner, this);
  292. }
  293. /**
  294. * @see Expression#deepEquals(Expression)
  295. */
  296. public boolean deepEquals(Expression expr)
  297. {
  298. if(!isSameClass(expr))
  299. return false;
  300. if(!m_qname.equals(((Variable)expr).m_qname))
  301. return false;
  302. // We have to make sure that the qname really references
  303. // the same variable element.
  304. // <<<<<<< TIGER SPECIFIC CHANGE >>>>>>>>>
  305. // As we are not supporting Xalan interpretive we are taking away the functionality
  306. // dependent on XSLT interpretive Transformer. Only way supported is to use XSLTC
  307. // and the execution path needed for supporting standard XPath API defined by
  308. // JAXP 1.3 .
  309. return true;
  310. }
  311. static final java.lang.String PSUEDOVARNAMESPACE = "http://xml.apache.org/xalan/psuedovar";
  312. /**
  313. * Tell if this is a psuedo variable reference, declared by Xalan instead
  314. * of by the user.
  315. */
  316. public boolean isPsuedoVarRef()
  317. {
  318. java.lang.String ns = m_qname.getNamespaceURI();
  319. if((null != ns) && ns.equals(PSUEDOVARNAMESPACE))
  320. {
  321. if(m_qname.getLocalName().startsWith("#"))
  322. return true;
  323. }
  324. return false;
  325. }
  326. }