KickJava   Java API By Example, From Geeks To Geeks.

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


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: XPath.java,v 1.30 2004/02/17 04:30:02 minchau Exp $
18  */

19 package org.apache.xpath;
20
21 import java.io.Serializable JavaDoc;
22
23 import javax.xml.transform.ErrorListener JavaDoc;
24 import javax.xml.transform.SourceLocator JavaDoc;
25 import javax.xml.transform.TransformerException JavaDoc;
26
27 import org.apache.xalan.res.XSLMessages;
28 import org.apache.xml.dtm.DTM;
29 import org.apache.xml.utils.PrefixResolver;
30 import org.apache.xml.utils.SAXSourceLocator;
31 import org.apache.xpath.compiler.Compiler;
32 import org.apache.xpath.compiler.FunctionTable;
33 import org.apache.xpath.compiler.XPathParser;
34 import org.apache.xpath.functions.Function;
35 import org.apache.xpath.objects.XObject;
36 import org.apache.xpath.res.XPATHErrorResources;
37
38 /**
39  * The XPath class wraps an expression object and provides general services
40  * for execution of that expression.
41  * @xsl.usage advanced
42  */

43 public class XPath implements Serializable JavaDoc, ExpressionOwner
44 {
45
46   /** The top of the expression tree.
47    * @serial */

48   private Expression m_mainExp;
49
50   /**
51    * Get the raw Expression object that this class wraps.
52    *
53    *
54    * @return the raw Expression object, which should not normally be null.
55    */

56   public Expression getExpression()
57   {
58     return m_mainExp;
59   }
60   
61   /**
62    * This function is used to fixup variables from QNames to stack frame
63    * indexes at stylesheet build time.
64    * @param vars List of QNames that correspond to variables. This list
65    * should be searched backwards for the first qualified name that
66    * corresponds to the variable reference qname. The position of the
67    * QName in the vector from the start of the vector will be its position
68    * in the stack frame (but variables above the globalsTop value will need
69    * to be offset to the current stack frame).
70    */

71   public void fixupVariables(java.util.Vector JavaDoc vars, int globalsSize)
72   {
73     m_mainExp.fixupVariables(vars, globalsSize);
74   }
75
76   /**
77    * Set the raw expression object for this object.
78    *
79    *
80    * @param exp the raw Expression object, which should not normally be null.
81    */

82   public void setExpression(Expression exp)
83   {
84     if(null != m_mainExp)
85         exp.exprSetParent(m_mainExp.exprGetParent()); // a bit bogus
86
m_mainExp = exp;
87   }
88
89   /**
90    * Get the SourceLocator on the expression object.
91    *
92    *
93    * @return the SourceLocator on the expression object, which may be null.
94    */

95   public SourceLocator JavaDoc getLocator()
96   {
97     return m_mainExp;
98   }
99
100 // /**
101
// * Set the SourceLocator on the expression object.
102
// *
103
// *
104
// * @param l the SourceLocator on the expression object, which may be null.
105
// */
106
// public void setLocator(SourceLocator l)
107
// {
108
// // Note potential hazards -- l may not be serializable, or may be changed
109
// // after being assigned here.
110
// m_mainExp.setSourceLocator(l);
111
// }
112

113   /** The pattern string, mainly kept around for diagnostic purposes.
114    * @serial */

115   String JavaDoc m_patternString;
116
117   /**
118    * Return the XPath string associated with this object.
119    *
120    *
121    * @return the XPath string associated with this object.
122    */

123   public String JavaDoc getPatternString()
124   {
125     return m_patternString;
126   }
127
128   /** Represents a select type expression. */
129   public static final int SELECT = 0;
130
131   /** Represents a match type expression. */
132   public static final int MATCH = 1;
133
134   /**
135    * Construct an XPath object.
136    *
137    * (Needs review -sc) This method initializes an XPathParser/
138    * Compiler and compiles the expression.
139    * @param exprString The XPath expression.
140    * @param locator The location of the expression, may be null.
141    * @param prefixResolver A prefix resolver to use to resolve prefixes to
142    * namespace URIs.
143    * @param type one of {@link #SELECT} or {@link #MATCH}.
144    * @param errorListener The error listener, or null if default should be used.
145    *
146    * @throws javax.xml.transform.TransformerException if syntax or other error.
147    */

148   public XPath(
149           String JavaDoc exprString, SourceLocator JavaDoc locator, PrefixResolver prefixResolver, int type,
150           ErrorListener JavaDoc errorListener)
151             throws javax.xml.transform.TransformerException JavaDoc
152   {
153     if(null == errorListener)
154       errorListener = new org.apache.xml.utils.DefaultErrorHandler();
155     
156     m_patternString = exprString;
157
158     XPathParser parser = new XPathParser(errorListener, locator);
159     Compiler JavaDoc compiler = new Compiler JavaDoc(errorListener, locator);
160
161     if (SELECT == type)
162       parser.initXPath(compiler, exprString, prefixResolver);
163     else if (MATCH == type)
164       parser.initMatchPattern(compiler, exprString, prefixResolver);
165     else
166       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CANNOT_DEAL_XPATH_TYPE, new Object JavaDoc[]{Integer.toString(type)})); //"Can not deal with XPath type: " + type);
167

168     // System.out.println("----------------");
169
Expression expr = compiler.compile(0);
170
171     // System.out.println("expr: "+expr);
172
this.setExpression(expr);
173     
174     if((null != locator) && locator instanceof ExpressionNode)
175     {
176         expr.exprSetParent((ExpressionNode)locator);
177     }
178
179   }
180   
181   /**
182    * Construct an XPath object.
183    *
184    * (Needs review -sc) This method initializes an XPathParser/
185    * Compiler and compiles the expression.
186    * @param exprString The XPath expression.
187    * @param locator The location of the expression, may be null.
188    * @param prefixResolver A prefix resolver to use to resolve prefixes to
189    * namespace URIs.
190    * @param type one of {@link #SELECT} or {@link #MATCH}.
191    *
192    * @throws javax.xml.transform.TransformerException if syntax or other error.
193    */

194   public XPath(
195           String JavaDoc exprString, SourceLocator JavaDoc locator, PrefixResolver prefixResolver, int type)
196             throws javax.xml.transform.TransformerException JavaDoc
197   {
198     this(exprString, locator, prefixResolver, type, null);
199   }
200
201   /**
202    * Construct an XPath object.
203    *
204    * @param expr The Expression object.
205    *
206    * @throws javax.xml.transform.TransformerException if syntax or other error.
207    */

208   public XPath(Expression expr)
209   {
210     this.setExpression(expr);
211   }
212   
213   /**
214    * Given an expression and a context, evaluate the XPath
215    * and return the result.
216    *
217    * @param xctxt The execution context.
218    * @param contextNode The node that "." expresses.
219    * @param namespaceContext The context in which namespaces in the
220    * XPath are supposed to be expanded.
221    *
222    * @return The result of the XPath or null if callbacks are used.
223    * @throws TransformerException thrown if
224    * the error condition is severe enough to halt processing.
225    *
226    * @throws javax.xml.transform.TransformerException
227    * @xsl.usage experimental
228    */

229   public XObject execute(
230           XPathContext xctxt, org.w3c.dom.Node JavaDoc contextNode,
231           PrefixResolver namespaceContext)
232             throws javax.xml.transform.TransformerException JavaDoc
233   {
234     return execute(
235           xctxt, xctxt.getDTMHandleFromNode(contextNode),
236           namespaceContext);
237   }
238   
239
240   /**
241    * Given an expression and a context, evaluate the XPath
242    * and return the result.
243    *
244    * @param xctxt The execution context.
245    * @param contextNode The node that "." expresses.
246    * @param namespaceContext The context in which namespaces in the
247    * XPath are supposed to be expanded.
248    *
249    * @throws TransformerException thrown if the active ProblemListener decides
250    * the error condition is severe enough to halt processing.
251    *
252    * @throws javax.xml.transform.TransformerException
253    * @xsl.usage experimental
254    */

255   public XObject execute(
256           XPathContext xctxt, int contextNode, PrefixResolver namespaceContext)
257             throws javax.xml.transform.TransformerException JavaDoc
258   {
259
260     xctxt.pushNamespaceContext(namespaceContext);
261
262     xctxt.pushCurrentNodeAndExpression(contextNode, contextNode);
263
264     XObject xobj = null;
265
266     try
267     {
268       xobj = m_mainExp.execute(xctxt);
269     }
270     catch (TransformerException JavaDoc te)
271     {
272       te.setLocator(this.getLocator());
273       ErrorListener JavaDoc el = xctxt.getErrorListener();
274       if(null != el) // defensive, should never happen.
275
{
276         el.error(te);
277       }
278       else
279         throw te;
280     }
281     catch (Exception JavaDoc e)
282     {
283       while (e instanceof org.apache.xml.utils.WrappedRuntimeException)
284       {
285         e = ((org.apache.xml.utils.WrappedRuntimeException) e).getException();
286       }
287       // e.printStackTrace();
288

289       String JavaDoc msg = e.getMessage();
290       
291       if (msg == null || msg.length() == 0) {
292            msg = XSLMessages.createXPATHMessage(
293                XPATHErrorResources.ER_XPATH_ERROR, null);
294      
295       }
296       TransformerException JavaDoc te = new TransformerException JavaDoc(msg,
297               getLocator(), e);
298       ErrorListener JavaDoc el = xctxt.getErrorListener();
299       // te.printStackTrace();
300
if(null != el) // defensive, should never happen.
301
{
302         el.fatalError(te);
303       }
304       else
305         throw te;
306     }
307     finally
308     {
309       xctxt.popNamespaceContext();
310
311       xctxt.popCurrentNodeAndExpression();
312     }
313
314     return xobj;
315   }
316   
317   /**
318    * Given an expression and a context, evaluate the XPath
319    * and return the result.
320    *
321    * @param xctxt The execution context.
322    * @param contextNode The node that "." expresses.
323    * @param namespaceContext The context in which namespaces in the
324    * XPath are supposed to be expanded.
325    *
326    * @throws TransformerException thrown if the active ProblemListener decides
327    * the error condition is severe enough to halt processing.
328    *
329    * @throws javax.xml.transform.TransformerException
330    * @xsl.usage experimental
331    */

332   public boolean bool(
333           XPathContext xctxt, int contextNode, PrefixResolver namespaceContext)
334             throws javax.xml.transform.TransformerException JavaDoc
335   {
336
337     xctxt.pushNamespaceContext(namespaceContext);
338
339     xctxt.pushCurrentNodeAndExpression(contextNode, contextNode);
340
341     try
342     {
343       return m_mainExp.bool(xctxt);
344     }
345     catch (TransformerException JavaDoc te)
346     {
347       te.setLocator(this.getLocator());
348       ErrorListener JavaDoc el = xctxt.getErrorListener();
349       if(null != el) // defensive, should never happen.
350
{
351         el.error(te);
352       }
353       else
354         throw te;
355     }
356     catch (Exception JavaDoc e)
357     {
358       while (e instanceof org.apache.xml.utils.WrappedRuntimeException)
359       {
360         e = ((org.apache.xml.utils.WrappedRuntimeException) e).getException();
361       }
362       // e.printStackTrace();
363

364       String JavaDoc msg = e.getMessage();
365       
366       if (msg == null || msg.length() == 0) {
367            msg = XSLMessages.createXPATHMessage(
368                XPATHErrorResources.ER_XPATH_ERROR, null);
369      
370       }
371       
372       TransformerException JavaDoc te = new TransformerException JavaDoc(msg,
373               getLocator(), e);
374       ErrorListener JavaDoc el = xctxt.getErrorListener();
375       // te.printStackTrace();
376
if(null != el) // defensive, should never happen.
377
{
378         el.fatalError(te);
379       }
380       else
381         throw te;
382     }
383     finally
384     {
385       xctxt.popNamespaceContext();
386
387       xctxt.popCurrentNodeAndExpression();
388     }
389
390     return false;
391   }
392
393   /** Set to true to get diagnostic messages about the result of
394    * match pattern testing. */

395   private static final boolean DEBUG_MATCHES = false;
396
397   /**
398    * Get the match score of the given node.
399    *
400    * @param xctxt XPath runtime context.
401    * @param context The current source tree context node.
402    *
403    * @return score, one of {@link #MATCH_SCORE_NODETEST},
404    * {@link #MATCH_SCORE_NONE}, {@link #MATCH_SCORE_OTHER},
405    * or {@link #MATCH_SCORE_QNAME}.
406    *
407    * @throws javax.xml.transform.TransformerException
408    */

409   public double getMatchScore(XPathContext xctxt, int context)
410           throws javax.xml.transform.TransformerException JavaDoc
411   {
412
413     xctxt.pushCurrentNode(context);
414     xctxt.pushCurrentExpressionNode(context);
415
416     try
417     {
418       XObject score = m_mainExp.execute(xctxt);
419
420       if (DEBUG_MATCHES)
421       {
422         DTM dtm = xctxt.getDTM(context);
423         System.out.println("score: " + score.num() + " for "
424                            + dtm.getNodeName(context) + " for xpath "
425                            + this.getPatternString());
426       }
427
428       return score.num();
429     }
430     finally
431     {
432       xctxt.popCurrentNode();
433       xctxt.popCurrentExpressionNode();
434     }
435
436     // return XPath.MATCH_SCORE_NONE;
437
}
438
439   /**
440    * Install a built-in function.
441    * @param name The unqualified name of the function; not currently used.
442    * @param funcIndex The index of the function in the table.
443    * @param func An Implementation of an XPath Function object.
444    * @return the position of the function in the internal index.
445    */

446   public void installFunction(String JavaDoc name, int funcIndex, Function func)
447   {
448     FunctionTable.installFunction(func, funcIndex);
449   }
450
451   /**
452    * Warn the user of an problem.
453    *
454    * @param xctxt The XPath runtime context.
455    * @param sourceNode Not used.
456    * @param msg An error msgkey that corresponds to one of the constants found
457    * in {@link org.apache.xpath.res.XPATHErrorResources}, which is
458    * a key for a format string.
459    * @param args An array of arguments represented in the format string, which
460    * may be null.
461    *
462    * @throws TransformerException if the current ErrorListoner determines to
463    * throw an exception.
464    */

465   public void warn(
466           XPathContext xctxt, int sourceNode, String JavaDoc msg, Object JavaDoc[] args)
467             throws javax.xml.transform.TransformerException JavaDoc
468   {
469
470     String JavaDoc fmsg = XSLMessages.createXPATHWarning(msg, args);
471     ErrorListener JavaDoc ehandler = xctxt.getErrorListener();
472
473     if (null != ehandler)
474     {
475
476       // TO DO: Need to get stylesheet Locator from here.
477
ehandler.warning(new TransformerException JavaDoc(fmsg, (SAXSourceLocator)xctxt.getSAXLocator()));
478     }
479   }
480
481   /**
482    * Tell the user of an assertion error, and probably throw an
483    * exception.
484    *
485    * @param b If false, a runtime exception will be thrown.
486    * @param msg The assertion message, which should be informative.
487    *
488    * @throws RuntimeException if the b argument is false.
489    */

490   public void assertion(boolean b, String JavaDoc msg)
491   {
492
493     if (!b)
494     {
495       String JavaDoc fMsg = XSLMessages.createXPATHMessage(
496         XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
497         new Object JavaDoc[]{ msg });
498
499       throw new RuntimeException JavaDoc(fMsg);
500     }
501   }
502
503   /**
504    * Tell the user of an error, and probably throw an
505    * exception.
506    *
507    * @param xctxt The XPath runtime context.
508    * @param sourceNode Not used.
509    * @param msg An error msgkey that corresponds to one of the constants found
510    * in {@link org.apache.xpath.res.XPATHErrorResources}, which is
511    * a key for a format string.
512    * @param args An array of arguments represented in the format string, which
513    * may be null.
514    *
515    * @throws TransformerException if the current ErrorListoner determines to
516    * throw an exception.
517    */

518   public void error(
519           XPathContext xctxt, int sourceNode, String JavaDoc msg, Object JavaDoc[] args)
520             throws javax.xml.transform.TransformerException JavaDoc
521   {
522
523     String JavaDoc fmsg = XSLMessages.createXPATHMessage(msg, args);
524     ErrorListener JavaDoc ehandler = xctxt.getErrorListener();
525
526     if (null != ehandler)
527     {
528       ehandler.fatalError(new TransformerException JavaDoc(fmsg,
529                               (SAXSourceLocator)xctxt.getSAXLocator()));
530     }
531     else
532     {
533       SourceLocator JavaDoc slocator = xctxt.getSAXLocator();
534       System.out.println(fmsg + "; file " + slocator.getSystemId()
535                          + "; line " + slocator.getLineNumber() + "; column "
536                          + slocator.getColumnNumber());
537     }
538   }
539   
540   /**
541    * This will traverse the heararchy, calling the visitor for
542    * each member. If the called visitor method returns
543    * false, the subtree should not be called.
544    *
545    * @param owner The owner of the visitor, where that path may be
546    * rewritten if needed.
547    * @param visitor The visitor whose appropriate method will be called.
548    */

549   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
550   {
551     m_mainExp.callVisitors(this, visitor);
552   }
553
554   /**
555    * The match score if no match is made.
556    * @xsl.usage advanced
557    */

558   public static final double MATCH_SCORE_NONE = Double.NEGATIVE_INFINITY;
559
560   /**
561    * The match score if the pattern has the form
562    * of a QName optionally preceded by an @ character.
563    * @xsl.usage advanced
564    */

565   public static final double MATCH_SCORE_QNAME = 0.0;
566
567   /**
568    * The match score if the pattern pattern has the form NCName:*.
569    * @xsl.usage advanced
570    */

571   public static final double MATCH_SCORE_NSWILD = -0.25;
572
573   /**
574    * The match score if the pattern consists of just a NodeTest.
575    * @xsl.usage advanced
576    */

577   public static final double MATCH_SCORE_NODETEST = -0.5;
578
579   /**
580    * The match score if the pattern consists of something
581    * other than just a NodeTest or just a qname.
582    * @xsl.usage advanced
583    */

584   public static final double MATCH_SCORE_OTHER = 0.5;
585 }
586
Popular Tags