KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xpath > Expression


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 org.apache.xpath;
20
21 import javax.xml.transform.ErrorListener JavaDoc;
22 import javax.xml.transform.TransformerException JavaDoc;
23
24 import org.apache.xalan.res.XSLMessages;
25 import org.apache.xml.dtm.DTM;
26 import org.apache.xml.dtm.DTMIterator;
27 import org.apache.xml.utils.XMLString;
28 import org.apache.xpath.objects.XNodeSet;
29 import org.apache.xpath.objects.XObject;
30 import org.apache.xpath.res.XPATHErrorResources;
31
32 import org.xml.sax.ContentHandler JavaDoc;
33
34 /**
35  * This abstract class serves as the base for all expression objects. An
36  * Expression can be executed to return a {@link org.apache.xpath.objects.XObject},
37  * normally has a location within a document or DOM, can send error and warning
38  * events, and normally do not hold state and are meant to be immutable once
39  * construction has completed. An exception to the immutibility rule is iterators
40  * and walkers, which must be cloned in order to be used -- the original must
41  * still be immutable.
42  */

43 public abstract class Expression implements java.io.Serializable JavaDoc, ExpressionNode, XPathVisitable
44 {
45
46   /**
47    * The location where this expression was built from. Need for diagnostic
48    * messages. May be null.
49    * @serial
50    */

51   private ExpressionNode m_parent;
52
53   /**
54    * Tell if this expression or it's subexpressions can traverse outside
55    * the current subtree.
56    *
57    * @return true if traversal outside the context node's subtree can occur.
58    */

59   public boolean canTraverseOutsideSubtree()
60   {
61     return false;
62   }
63   
64 // /**
65
// * Set the location where this expression was built from.
66
// *
67
// *
68
// * @param locator the location where this expression was built from, may be
69
// * null.
70
// */
71
// public void setSourceLocator(SourceLocator locator)
72
// {
73
// m_slocator = locator;
74
// }
75

76   /**
77    * Execute an expression in the XPath runtime context, and return the
78    * result of the expression.
79    *
80    *
81    * @param xctxt The XPath runtime context.
82    * @param currentNode The currentNode.
83    *
84    * @return The result of the expression in the form of a <code>XObject</code>.
85    *
86    * @throws javax.xml.transform.TransformerException if a runtime exception
87    * occurs.
88    */

89   public XObject execute(XPathContext xctxt, int currentNode)
90           throws javax.xml.transform.TransformerException JavaDoc
91   {
92
93     // For now, the current node is already pushed.
94
return execute(xctxt);
95   }
96
97   /**
98    * Execute an expression in the XPath runtime context, and return the
99    * result of the expression.
100    *
101    *
102    * @param xctxt The XPath runtime context.
103    * @param currentNode The currentNode.
104    * @param dtm The DTM of the current node.
105    * @param expType The expanded type ID of the current node.
106    *
107    * @return The result of the expression in the form of a <code>XObject</code>.
108    *
109    * @throws javax.xml.transform.TransformerException if a runtime exception
110    * occurs.
111    */

112   public XObject execute(
113           XPathContext xctxt, int currentNode, DTM dtm, int expType)
114             throws javax.xml.transform.TransformerException JavaDoc
115   {
116
117     // For now, the current node is already pushed.
118
return execute(xctxt);
119   }
120
121   /**
122    * Execute an expression in the XPath runtime context, and return the
123    * result of the expression.
124    *
125    *
126    * @param xctxt The XPath runtime context.
127    *
128    * @return The result of the expression in the form of a <code>XObject</code>.
129    *
130    * @throws javax.xml.transform.TransformerException if a runtime exception
131    * occurs.
132    */

133   public abstract XObject execute(XPathContext xctxt)
134     throws javax.xml.transform.TransformerException JavaDoc;
135
136   /**
137    * Execute an expression in the XPath runtime context, and return the
138    * result of the expression, but tell that a "safe" object doesn't have
139    * to be returned. The default implementation just calls execute(xctxt).
140    *
141    *
142    * @param xctxt The XPath runtime context.
143    * @param destructiveOK true if a "safe" object doesn't need to be returned.
144    *
145    * @return The result of the expression in the form of a <code>XObject</code>.
146    *
147    * @throws javax.xml.transform.TransformerException if a runtime exception
148    * occurs.
149    */

150   public XObject execute(XPathContext xctxt, boolean destructiveOK)
151     throws javax.xml.transform.TransformerException JavaDoc
152   {
153     return execute(xctxt);
154   }
155
156
157   /**
158    * Evaluate expression to a number.
159    *
160    *
161    * @param xctxt The XPath runtime context.
162    * @return The expression evaluated as a double.
163    *
164    * @throws javax.xml.transform.TransformerException
165    */

166   public double num(XPathContext xctxt)
167           throws javax.xml.transform.TransformerException JavaDoc
168   {
169     return execute(xctxt).num();
170   }
171
172   /**
173    * Evaluate expression to a boolean.
174    *
175    *
176    * @param xctxt The XPath runtime context.
177    * @return false
178    *
179    * @throws javax.xml.transform.TransformerException
180    */

181   public boolean bool(XPathContext xctxt)
182           throws javax.xml.transform.TransformerException JavaDoc
183   {
184     return execute(xctxt).bool();
185   }
186
187   /**
188    * Cast result object to a string.
189    *
190    *
191    * @param xctxt The XPath runtime context.
192    * @return The string this wraps or the empty string if null
193    *
194    * @throws javax.xml.transform.TransformerException
195    */

196   public XMLString xstr(XPathContext xctxt)
197           throws javax.xml.transform.TransformerException JavaDoc
198   {
199     return execute(xctxt).xstr();
200   }
201
202   /**
203    * Tell if the expression is a nodeset expression. In other words, tell
204    * if you can execute {@link asNode() asNode} without an exception.
205    * @return true if the expression can be represented as a nodeset.
206    */

207   public boolean isNodesetExpr()
208   {
209     return false;
210   }
211
212   /**
213    * Return the first node out of the nodeset, if this expression is
214    * a nodeset expression.
215    * @param xctxt The XPath runtime context.
216    * @return the first node out of the nodeset, or DTM.NULL.
217    *
218    * @throws javax.xml.transform.TransformerException
219    */

220   public int asNode(XPathContext xctxt)
221           throws javax.xml.transform.TransformerException JavaDoc
222   {
223     DTMIterator iter = execute(xctxt).iter();
224     return iter.nextNode();
225   }
226
227   /**
228    * Given an select expression and a context, evaluate the XPath
229    * and return the resulting iterator.
230    *
231    * @param xctxt The execution context.
232    * @param contextNode The node that "." expresses.
233    *
234    *
235    * @return A valid DTMIterator.
236    * @throws TransformerException thrown if the active ProblemListener decides
237    * the error condition is severe enough to halt processing.
238    *
239    * @throws javax.xml.transform.TransformerException
240    * @xsl.usage experimental
241    */

242   public DTMIterator asIterator(XPathContext xctxt, int contextNode)
243           throws javax.xml.transform.TransformerException JavaDoc
244   {
245
246     try
247     {
248       xctxt.pushCurrentNodeAndExpression(contextNode, contextNode);
249
250       return execute(xctxt).iter();
251     }
252     finally
253     {
254       xctxt.popCurrentNodeAndExpression();
255     }
256   }
257   
258   /**
259    * Given an select expression and a context, evaluate the XPath
260    * and return the resulting iterator, but do not clone.
261    *
262    * @param xctxt The execution context.
263    * @param contextNode The node that "." expresses.
264    *
265    *
266    * @return A valid DTMIterator.
267    * @throws TransformerException thrown if the active ProblemListener decides
268    * the error condition is severe enough to halt processing.
269    *
270    * @throws javax.xml.transform.TransformerException
271    * @xsl.usage experimental
272    */

273   public DTMIterator asIteratorRaw(XPathContext xctxt, int contextNode)
274           throws javax.xml.transform.TransformerException JavaDoc
275   {
276
277     try
278     {
279       xctxt.pushCurrentNodeAndExpression(contextNode, contextNode);
280
281       XNodeSet nodeset = (XNodeSet)execute(xctxt);
282       return nodeset.iterRaw();
283     }
284     finally
285     {
286       xctxt.popCurrentNodeAndExpression();
287     }
288   }
289
290
291   /**
292    * Execute an expression in the XPath runtime context, and return the
293    * result of the expression.
294    *
295    *
296    * @param xctxt The XPath runtime context.
297    * NEEDSDOC @param handler
298    *
299    * @return The result of the expression in the form of a <code>XObject</code>.
300    *
301    * @throws javax.xml.transform.TransformerException if a runtime exception
302    * occurs.
303    * @throws org.xml.sax.SAXException
304    */

305   public void executeCharsToContentHandler(
306           XPathContext xctxt, ContentHandler JavaDoc handler)
307             throws javax.xml.transform.TransformerException JavaDoc,
308                    org.xml.sax.SAXException JavaDoc
309   {
310
311     XObject obj = execute(xctxt);
312
313     obj.dispatchCharactersEvents(handler);
314     obj.detach();
315   }
316
317   /**
318    * Tell if this expression returns a stable number that will not change during
319    * iterations within the expression. This is used to determine if a proximity
320    * position predicate can indicate that no more searching has to occur.
321    *
322    *
323    * @return true if the expression represents a stable number.
324    */

325   public boolean isStableNumber()
326   {
327     return false;
328   }
329
330   /**
331    * This function is used to fixup variables from QNames to stack frame
332    * indexes at stylesheet build time.
333    * @param vars List of QNames that correspond to variables. This list
334    * should be searched backwards for the first qualified name that
335    * corresponds to the variable reference qname. The position of the
336    * QName in the vector from the start of the vector will be its position
337    * in the stack frame (but variables above the globalsTop value will need
338    * to be offset to the current stack frame).
339    * NEEDSDOC @param globalsSize
340    */

341   public abstract void fixupVariables(java.util.Vector JavaDoc vars, int globalsSize);
342   
343   /**
344    * Compare this object with another object and see
345    * if they are equal, include the sub heararchy.
346    *
347    * @param expr Another expression object.
348    * @return true if this objects class and the expr
349    * object's class are the same, and the data contained
350    * within both objects are considered equal.
351    */

352   public abstract boolean deepEquals(Expression expr);
353   
354   /**
355    * This is a utility method to tell if the passed in
356    * class is the same class as this. It is to be used by
357    * the deepEquals method. I'm bottlenecking it here
358    * because I'm not totally confident that comparing the
359    * class objects is the best way to do this.
360    * @return true of the passed in class is the exact same
361    * class as this class.
362    */

363   protected final boolean isSameClass(Expression expr)
364   {
365     if(null == expr)
366       return false;
367       
368     return (getClass() == expr.getClass());
369   }
370
371   /**
372    * Warn the user of an problem.
373    *
374    * @param xctxt The XPath runtime context.
375    * @param msg An error msgkey that corresponds to one of the conststants found
376    * in {@link org.apache.xpath.res.XPATHErrorResources}, which is
377    * a key for a format string.
378    * @param args An array of arguments represented in the format string, which
379    * may be null.
380    *
381    * @throws TransformerException if the current ErrorListoner determines to
382    * throw an exception.
383    *
384    * @throws javax.xml.transform.TransformerException
385    */

386   public void warn(XPathContext xctxt, String JavaDoc msg, Object JavaDoc[] args)
387           throws javax.xml.transform.TransformerException JavaDoc
388   {
389
390     java.lang.String JavaDoc fmsg = XSLMessages.createXPATHWarning(msg, args);
391
392     if (null != xctxt)
393     {
394       ErrorListener JavaDoc eh = xctxt.getErrorListener();
395
396       // TO DO: Need to get stylesheet Locator from here.
397
eh.warning(new TransformerException JavaDoc(fmsg, xctxt.getSAXLocator()));
398     }
399   }
400
401   /**
402    * Tell the user of an assertion error, and probably throw an
403    * exception.
404    *
405    * @param b If false, a runtime exception will be thrown.
406    * @param msg The assertion message, which should be informative.
407    *
408    * @throws RuntimeException if the b argument is false.
409    *
410    * @throws javax.xml.transform.TransformerException
411    */

412   public void assertion(boolean b, java.lang.String JavaDoc msg)
413   {
414
415     if (!b)
416     {
417       java.lang.String JavaDoc fMsg = XSLMessages.createXPATHMessage(
418         XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
419         new Object JavaDoc[]{ msg });
420
421       throw new RuntimeException JavaDoc(fMsg);
422     }
423   }
424
425   /**
426    * Tell the user of an error, and probably throw an
427    * exception.
428    *
429    * @param xctxt The XPath runtime context.
430    * @param msg An error msgkey that corresponds to one of the constants found
431    * in {@link org.apache.xpath.res.XPATHErrorResources}, which is
432    * a key for a format string.
433    * @param args An array of arguments represented in the format string, which
434    * may be null.
435    *
436    * @throws TransformerException if the current ErrorListoner determines to
437    * throw an exception.
438    *
439    * @throws javax.xml.transform.TransformerException
440    */

441   public void error(XPathContext xctxt, String JavaDoc msg, Object JavaDoc[] args)
442           throws javax.xml.transform.TransformerException JavaDoc
443   {
444
445     java.lang.String JavaDoc fmsg = XSLMessages.createXPATHMessage(msg, args);
446
447     if (null != xctxt)
448     {
449       ErrorListener JavaDoc eh = xctxt.getErrorListener();
450       TransformerException JavaDoc te = new TransformerException JavaDoc(fmsg, this);
451
452       eh.fatalError(te);
453     }
454   }
455   
456   /**
457    * Get the first non-Expression parent of this node.
458    * @return null or first ancestor that is not an Expression.
459    */

460   public ExpressionNode getExpressionOwner()
461   {
462     ExpressionNode parent = exprGetParent();
463     while((null != parent) && (parent instanceof Expression))
464         parent = parent.exprGetParent();
465     return parent;
466   }
467   
468   //=============== ExpressionNode methods ================
469

470   /** This pair of methods are used to inform the node of its
471     parent. */

472   public void exprSetParent(ExpressionNode n)
473   {
474     assertion(n != this, "Can not parent an expression to itself!");
475     m_parent = n;
476   }
477   
478   public ExpressionNode exprGetParent()
479   {
480     return m_parent;
481   }
482
483   /** This method tells the node to add its argument to the node's
484     list of children. */

485   public void exprAddChild(ExpressionNode n, int i)
486   {
487     assertion(false, "exprAddChild method not implemented!");
488   }
489
490   /** This method returns a child node. The children are numbered
491      from zero, left to right. */

492   public ExpressionNode exprGetChild(int i)
493   {
494     return null;
495   }
496
497   /** Return the number of children the node has. */
498   public int exprGetNumChildren()
499   {
500     return 0;
501   }
502   
503   //=============== SourceLocator methods ================
504

505   /**
506    * Return the public identifier for the current document event.
507    *
508    * <p>The return value is the public identifier of the document
509    * entity or of the external parsed entity in which the markup that
510    * triggered the event appears.</p>
511    *
512    * @return A string containing the public identifier, or
513    * null if none is available.
514    * @see #getSystemId
515    */

516   public String JavaDoc getPublicId()
517   {
518     if(null == m_parent)
519       return null;
520     return m_parent.getPublicId();
521   }
522
523   /**
524    * Return the system identifier for the current document event.
525    *
526    * <p>The return value is the system identifier of the document
527    * entity or of the external parsed entity in which the markup that
528    * triggered the event appears.</p>
529    *
530    * <p>If the system identifier is a URL, the parser must resolve it
531    * fully before passing it to the application.</p>
532    *
533    * @return A string containing the system identifier, or null
534    * if none is available.
535    * @see #getPublicId
536    */

537   public String JavaDoc getSystemId()
538   {
539     if(null == m_parent)
540       return null;
541     return m_parent.getSystemId();
542   }
543
544   /**
545    * Return the line number where the current document event ends.
546    *
547    * <p><strong>Warning:</strong> The return value from the method
548    * is intended only as an approximation for the sake of error
549    * reporting; it is not intended to provide sufficient information
550    * to edit the character content of the original XML document.</p>
551    *
552    * <p>The return value is an approximation of the line number
553    * in the document entity or external parsed entity where the
554    * markup that triggered the event appears.</p>
555    *
556    * @return The line number, or -1 if none is available.
557    * @see #getColumnNumber
558    */

559   public int getLineNumber()
560   {
561     if(null == m_parent)
562       return 0;
563     return m_parent.getLineNumber();
564   }
565
566   /**
567    * Return the character position where the current document event ends.
568    *
569    * <p><strong>Warning:</strong> The return value from the method
570    * is intended only as an approximation for the sake of error
571    * reporting; it is not intended to provide sufficient information
572    * to edit the character content of the original XML document.</p>
573    *
574    * <p>The return value is an approximation of the column number
575    * in the document entity or external parsed entity where the
576    * markup that triggered the event appears.</p>
577    *
578    * @return The column number, or -1 if none is available.
579    * @see #getLineNumber
580    */

581   public int getColumnNumber()
582   {
583     if(null == m_parent)
584       return 0;
585     return m_parent.getColumnNumber();
586   }
587 }
588
Popular Tags