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