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: Expression.java,v 1.23 2004/02/17 04:30:02 minchau Exp $
  18. */
  19. package com.sun.org.apache.xpath.internal;
  20. import javax.xml.transform.ErrorListener;
  21. import javax.xml.transform.TransformerException;
  22. import com.sun.org.apache.xalan.internal.res.XSLMessages;
  23. import com.sun.org.apache.xml.internal.dtm.DTM;
  24. import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  25. import com.sun.org.apache.xml.internal.utils.XMLString;
  26. import com.sun.org.apache.xpath.internal.objects.XNodeSet;
  27. import com.sun.org.apache.xpath.internal.objects.XObject;
  28. import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  29. import org.xml.sax.ContentHandler;
  30. /**
  31. * This abstract class serves as the base for all expression objects. An
  32. * Expression can be executed to return a {@link com.sun.org.apache.xpath.internal.objects.XObject},
  33. * normally has a location within a document or DOM, can send error and warning
  34. * events, and normally do not hold state and are meant to be immutable once
  35. * construction has completed. An exception to the immutibility rule is iterators
  36. * and walkers, which must be cloned in order to be used -- the original must
  37. * still be immutable.
  38. */
  39. public abstract class Expression implements java.io.Serializable, ExpressionNode, XPathVisitable
  40. {
  41. /**
  42. * The location where this expression was built from. Need for diagnostic
  43. * messages. May be null.
  44. * @serial
  45. */
  46. private ExpressionNode m_parent;
  47. /**
  48. * Tell if this expression or it's subexpressions can traverse outside
  49. * the current subtree.
  50. *
  51. * @return true if traversal outside the context node's subtree can occur.
  52. */
  53. public boolean canTraverseOutsideSubtree()
  54. {
  55. return false;
  56. }
  57. // /**
  58. // * Set the location where this expression was built from.
  59. // *
  60. // *
  61. // * @param locator the location where this expression was built from, may be
  62. // * null.
  63. // */
  64. // public void setSourceLocator(SourceLocator locator)
  65. // {
  66. // m_slocator = locator;
  67. // }
  68. /**
  69. * Execute an expression in the XPath runtime context, and return the
  70. * result of the expression.
  71. *
  72. *
  73. * @param xctxt The XPath runtime context.
  74. * @param currentNode The currentNode.
  75. *
  76. * @return The result of the expression in the form of a <code>XObject</code>.
  77. *
  78. * @throws javax.xml.transform.TransformerException if a runtime exception
  79. * occurs.
  80. */
  81. public XObject execute(XPathContext xctxt, int currentNode)
  82. throws javax.xml.transform.TransformerException
  83. {
  84. // For now, the current node is already pushed.
  85. return execute(xctxt);
  86. }
  87. /**
  88. * Execute an expression in the XPath runtime context, and return the
  89. * result of the expression.
  90. *
  91. *
  92. * @param xctxt The XPath runtime context.
  93. * @param currentNode The currentNode.
  94. * @param dtm The DTM of the current node.
  95. * @param expType The expanded type ID of the current node.
  96. *
  97. * @return The result of the expression in the form of a <code>XObject</code>.
  98. *
  99. * @throws javax.xml.transform.TransformerException if a runtime exception
  100. * occurs.
  101. */
  102. public XObject execute(
  103. XPathContext xctxt, int currentNode, DTM dtm, int expType)
  104. throws javax.xml.transform.TransformerException
  105. {
  106. // For now, the current node is already pushed.
  107. return execute(xctxt);
  108. }
  109. /**
  110. * Execute an expression in the XPath runtime context, and return the
  111. * result of the expression.
  112. *
  113. *
  114. * @param xctxt The XPath runtime context.
  115. *
  116. * @return The result of the expression in the form of a <code>XObject</code>.
  117. *
  118. * @throws javax.xml.transform.TransformerException if a runtime exception
  119. * occurs.
  120. */
  121. public abstract XObject execute(XPathContext xctxt)
  122. throws javax.xml.transform.TransformerException;
  123. /**
  124. * Execute an expression in the XPath runtime context, and return the
  125. * result of the expression, but tell that a "safe" object doesn't have
  126. * to be returned. The default implementation just calls execute(xctxt).
  127. *
  128. *
  129. * @param xctxt The XPath runtime context.
  130. * @param destructiveOK true if a "safe" object doesn't need to be returned.
  131. *
  132. * @return The result of the expression in the form of a <code>XObject</code>.
  133. *
  134. * @throws javax.xml.transform.TransformerException if a runtime exception
  135. * occurs.
  136. */
  137. public XObject execute(XPathContext xctxt, boolean destructiveOK)
  138. throws javax.xml.transform.TransformerException
  139. {
  140. return execute(xctxt);
  141. }
  142. /**
  143. * Evaluate expression to a number.
  144. *
  145. *
  146. * @param xctxt The XPath runtime context.
  147. * @return The expression evaluated as a double.
  148. *
  149. * @throws javax.xml.transform.TransformerException
  150. */
  151. public double num(XPathContext xctxt)
  152. throws javax.xml.transform.TransformerException
  153. {
  154. return execute(xctxt).num();
  155. }
  156. /**
  157. * Evaluate expression to a boolean.
  158. *
  159. *
  160. * @param xctxt The XPath runtime context.
  161. * @return false
  162. *
  163. * @throws javax.xml.transform.TransformerException
  164. */
  165. public boolean bool(XPathContext xctxt)
  166. throws javax.xml.transform.TransformerException
  167. {
  168. return execute(xctxt).bool();
  169. }
  170. /**
  171. * Cast result object to a string.
  172. *
  173. *
  174. * @param xctxt The XPath runtime context.
  175. * @return The string this wraps or the empty string if null
  176. *
  177. * @throws javax.xml.transform.TransformerException
  178. */
  179. public XMLString xstr(XPathContext xctxt)
  180. throws javax.xml.transform.TransformerException
  181. {
  182. return execute(xctxt).xstr();
  183. }
  184. /**
  185. * Tell if the expression is a nodeset expression. In other words, tell
  186. * if you can execute {@link asNode() asNode} without an exception.
  187. * @return true if the expression can be represented as a nodeset.
  188. */
  189. public boolean isNodesetExpr()
  190. {
  191. return false;
  192. }
  193. /**
  194. * Return the first node out of the nodeset, if this expression is
  195. * a nodeset expression.
  196. * @param xctxt The XPath runtime context.
  197. * @return the first node out of the nodeset, or DTM.NULL.
  198. *
  199. * @throws javax.xml.transform.TransformerException
  200. */
  201. public int asNode(XPathContext xctxt)
  202. throws javax.xml.transform.TransformerException
  203. {
  204. DTMIterator iter = execute(xctxt).iter();
  205. return iter.nextNode();
  206. }
  207. /**
  208. * Given an select expression and a context, evaluate the XPath
  209. * and return the resulting iterator.
  210. *
  211. * @param xctxt The execution context.
  212. * @param contextNode The node that "." expresses.
  213. *
  214. *
  215. * @return A valid DTMIterator.
  216. * @throws TransformerException thrown if the active ProblemListener decides
  217. * the error condition is severe enough to halt processing.
  218. *
  219. * @throws javax.xml.transform.TransformerException
  220. * @xsl.usage experimental
  221. */
  222. public DTMIterator asIterator(XPathContext xctxt, int contextNode)
  223. throws javax.xml.transform.TransformerException
  224. {
  225. try
  226. {
  227. xctxt.pushCurrentNodeAndExpression(contextNode, contextNode);
  228. return execute(xctxt).iter();
  229. }
  230. finally
  231. {
  232. xctxt.popCurrentNodeAndExpression();
  233. }
  234. }
  235. /**
  236. * Given an select expression and a context, evaluate the XPath
  237. * and return the resulting iterator, but do not clone.
  238. *
  239. * @param xctxt The execution context.
  240. * @param contextNode The node that "." expresses.
  241. *
  242. *
  243. * @return A valid DTMIterator.
  244. * @throws TransformerException thrown if the active ProblemListener decides
  245. * the error condition is severe enough to halt processing.
  246. *
  247. * @throws javax.xml.transform.TransformerException
  248. * @xsl.usage experimental
  249. */
  250. public DTMIterator asIteratorRaw(XPathContext xctxt, int contextNode)
  251. throws javax.xml.transform.TransformerException
  252. {
  253. try
  254. {
  255. xctxt.pushCurrentNodeAndExpression(contextNode, contextNode);
  256. XNodeSet nodeset = (XNodeSet)execute(xctxt);
  257. return nodeset.iterRaw();
  258. }
  259. finally
  260. {
  261. xctxt.popCurrentNodeAndExpression();
  262. }
  263. }
  264. /**
  265. * Execute an expression in the XPath runtime context, and return the
  266. * result of the expression.
  267. *
  268. *
  269. * @param xctxt The XPath runtime context.
  270. * NEEDSDOC @param handler
  271. *
  272. * @return The result of the expression in the form of a <code>XObject</code>.
  273. *
  274. * @throws javax.xml.transform.TransformerException if a runtime exception
  275. * occurs.
  276. * @throws org.xml.sax.SAXException
  277. */
  278. public void executeCharsToContentHandler(
  279. XPathContext xctxt, ContentHandler handler)
  280. throws javax.xml.transform.TransformerException,
  281. org.xml.sax.SAXException
  282. {
  283. XObject obj = execute(xctxt);
  284. obj.dispatchCharactersEvents(handler);
  285. obj.detach();
  286. }
  287. /**
  288. * Tell if this expression returns a stable number that will not change during
  289. * iterations within the expression. This is used to determine if a proximity
  290. * position predicate can indicate that no more searching has to occur.
  291. *
  292. *
  293. * @return true if the expression represents a stable number.
  294. */
  295. public boolean isStableNumber()
  296. {
  297. return false;
  298. }
  299. /**
  300. * This function is used to fixup variables from QNames to stack frame
  301. * indexes at stylesheet build time.
  302. * @param vars List of QNames that correspond to variables. This list
  303. * should be searched backwards for the first qualified name that
  304. * corresponds to the variable reference qname. The position of the
  305. * QName in the vector from the start of the vector will be its position
  306. * in the stack frame (but variables above the globalsTop value will need
  307. * to be offset to the current stack frame).
  308. * NEEDSDOC @param globalsSize
  309. */
  310. public abstract void fixupVariables(java.util.Vector vars, int globalsSize);
  311. /**
  312. * Compare this object with another object and see
  313. * if they are equal, include the sub heararchy.
  314. *
  315. * @param expr Another expression object.
  316. * @return true if this objects class and the expr
  317. * object's class are the same, and the data contained
  318. * within both objects are considered equal.
  319. */
  320. public abstract boolean deepEquals(Expression expr);
  321. /**
  322. * This is a utility method to tell if the passed in
  323. * class is the same class as this. It is to be used by
  324. * the deepEquals method. I'm bottlenecking it here
  325. * because I'm not totally confident that comparing the
  326. * class objects is the best way to do this.
  327. * @return true of the passed in class is the exact same
  328. * class as this class.
  329. */
  330. protected final boolean isSameClass(Expression expr)
  331. {
  332. if(null == expr)
  333. return false;
  334. return (getClass() == expr.getClass());
  335. }
  336. /**
  337. * Warn the user of an problem.
  338. *
  339. * @param xctxt The XPath runtime context.
  340. * @param msg An error msgkey that corresponds to one of the conststants found
  341. * in {@link com.sun.org.apache.xpath.internal.res.XPATHErrorResources}, which is
  342. * a key for a format string.
  343. * @param args An array of arguments represented in the format string, which
  344. * may be null.
  345. *
  346. * @throws TransformerException if the current ErrorListoner determines to
  347. * throw an exception.
  348. *
  349. * @throws javax.xml.transform.TransformerException
  350. */
  351. public void warn(XPathContext xctxt, String msg, Object[] args)
  352. throws javax.xml.transform.TransformerException
  353. {
  354. java.lang.String fmsg = XSLMessages.createXPATHWarning(msg, args);
  355. if (null != xctxt)
  356. {
  357. ErrorListener eh = xctxt.getErrorListener();
  358. // TO DO: Need to get stylesheet Locator from here.
  359. eh.warning(new TransformerException(fmsg, xctxt.getSAXLocator()));
  360. }
  361. }
  362. /**
  363. * Tell the user of an assertion error, and probably throw an
  364. * exception.
  365. *
  366. * @param b If false, a runtime exception will be thrown.
  367. * @param msg The assertion message, which should be informative.
  368. *
  369. * @throws RuntimeException if the b argument is false.
  370. *
  371. * @throws javax.xml.transform.TransformerException
  372. */
  373. public void assertion(boolean b, java.lang.String msg)
  374. {
  375. if (!b)
  376. {
  377. java.lang.String fMsg = XSLMessages.createXPATHMessage(
  378. XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
  379. new Object[]{ msg });
  380. throw new RuntimeException(fMsg);
  381. }
  382. }
  383. /**
  384. * Tell the user of an error, and probably throw an
  385. * exception.
  386. *
  387. * @param xctxt The XPath runtime context.
  388. * @param msg An error msgkey that corresponds to one of the constants found
  389. * in {@link com.sun.org.apache.xpath.internal.res.XPATHErrorResources}, which is
  390. * a key for a format string.
  391. * @param args An array of arguments represented in the format string, which
  392. * may be null.
  393. *
  394. * @throws TransformerException if the current ErrorListoner determines to
  395. * throw an exception.
  396. *
  397. * @throws javax.xml.transform.TransformerException
  398. */
  399. public void error(XPathContext xctxt, String msg, Object[] args)
  400. throws javax.xml.transform.TransformerException
  401. {
  402. java.lang.String fmsg = XSLMessages.createXPATHMessage(msg, args);
  403. if (null != xctxt)
  404. {
  405. ErrorListener eh = xctxt.getErrorListener();
  406. TransformerException te = new TransformerException(fmsg, this);
  407. eh.fatalError(te);
  408. }
  409. }
  410. /**
  411. * Get the first non-Expression parent of this node.
  412. * @return null or first ancestor that is not an Expression.
  413. */
  414. public ExpressionNode getExpressionOwner()
  415. {
  416. ExpressionNode parent = exprGetParent();
  417. while((null != parent) && (parent instanceof Expression))
  418. parent = parent.exprGetParent();
  419. return parent;
  420. }
  421. //=============== ExpressionNode methods ================
  422. /** This pair of methods are used to inform the node of its
  423. parent. */
  424. public void exprSetParent(ExpressionNode n)
  425. {
  426. assertion(n != this, "Can not parent an expression to itself!");
  427. m_parent = n;
  428. }
  429. public ExpressionNode exprGetParent()
  430. {
  431. return m_parent;
  432. }
  433. /** This method tells the node to add its argument to the node's
  434. list of children. */
  435. public void exprAddChild(ExpressionNode n, int i)
  436. {
  437. assertion(false, "exprAddChild method not implemented!");
  438. }
  439. /** This method returns a child node. The children are numbered
  440. from zero, left to right. */
  441. public ExpressionNode exprGetChild(int i)
  442. {
  443. return null;
  444. }
  445. /** Return the number of children the node has. */
  446. public int exprGetNumChildren()
  447. {
  448. return 0;
  449. }
  450. //=============== SourceLocator methods ================
  451. /**
  452. * Return the public identifier for the current document event.
  453. *
  454. * <p>The return value is the public identifier of the document
  455. * entity or of the external parsed entity in which the markup that
  456. * triggered the event appears.</p>
  457. *
  458. * @return A string containing the public identifier, or
  459. * null if none is available.
  460. * @see #getSystemId
  461. */
  462. public String getPublicId()
  463. {
  464. if(null == m_parent)
  465. return null;
  466. return m_parent.getPublicId();
  467. }
  468. /**
  469. * Return the system identifier for the current document event.
  470. *
  471. * <p>The return value is the system identifier of the document
  472. * entity or of the external parsed entity in which the markup that
  473. * triggered the event appears.</p>
  474. *
  475. * <p>If the system identifier is a URL, the parser must resolve it
  476. * fully before passing it to the application.</p>
  477. *
  478. * @return A string containing the system identifier, or null
  479. * if none is available.
  480. * @see #getPublicId
  481. */
  482. public String getSystemId()
  483. {
  484. if(null == m_parent)
  485. return null;
  486. return m_parent.getSystemId();
  487. }
  488. /**
  489. * Return the line number where the current document event ends.
  490. *
  491. * <p><strong>Warning:</strong> The return value from the method
  492. * is intended only as an approximation for the sake of error
  493. * reporting; it is not intended to provide sufficient information
  494. * to edit the character content of the original XML document.</p>
  495. *
  496. * <p>The return value is an approximation of the line number
  497. * in the document entity or external parsed entity where the
  498. * markup that triggered the event appears.</p>
  499. *
  500. * @return The line number, or -1 if none is available.
  501. * @see #getColumnNumber
  502. */
  503. public int getLineNumber()
  504. {
  505. if(null == m_parent)
  506. return 0;
  507. return m_parent.getLineNumber();
  508. }
  509. /**
  510. * Return the character position where the current document event ends.
  511. *
  512. * <p><strong>Warning:</strong> The return value from the method
  513. * is intended only as an approximation for the sake of error
  514. * reporting; it is not intended to provide sufficient information
  515. * to edit the character content of the original XML document.</p>
  516. *
  517. * <p>The return value is an approximation of the column number
  518. * in the document entity or external parsed entity where the
  519. * markup that triggered the event appears.</p>
  520. *
  521. * @return The column number, or -1 if none is available.
  522. * @see #getLineNumber
  523. */
  524. public int getColumnNumber()
  525. {
  526. if(null == m_parent)
  527. return 0;
  528. return m_parent.getColumnNumber();
  529. }
  530. }