KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*--
2
3  $Id: XPath.java,v 1.16 2004/11/03 05:17:17 jhunter Exp $
4
5  Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
6  All rights 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 disclaimer that follows
17     these conditions in the documentation and/or other materials
18     provided with the distribution.
19
20  3. The name "JDOM" must not be used to endorse or promote products
21     derived from this software without prior written permission. For
22     written permission, please contact <request_AT_jdom_DOT_org>.
23
24  4. Products derived from this software may not be called "JDOM", nor
25     may "JDOM" appear in their name, without prior written permission
26     from the JDOM Project Management <request_AT_jdom_DOT_org>.
27
28  In addition, we request (but do not require) that you include in the
29  end-user documentation provided with the redistribution and/or in the
30  software itself an acknowledgement equivalent to the following:
31      "This product includes software developed by the
32       JDOM Project (http://www.jdom.org/)."
33  Alternatively, the acknowledgment may be graphical using the logos
34  available at http://www.jdom.org/images/logos.
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 JDOM AUTHORS OR THE PROJECT
40  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  This software consists of voluntary contributions made by many
50  individuals on behalf of the JDOM Project and was originally
51  created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
52  Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
53  on the JDOM Project, please see <http://www.jdom.org/>.
54
55  */

56
57 package org.jdom.xpath;
58
59
60 import java.io.*;
61 import java.lang.reflect.*;
62 import java.util.*;
63
64 import org.jdom.*;
65
66
67 /**
68  * A utility class for performing XPath calls on JDOM nodes, with a factory
69  * interface for obtaining a first XPath instance. Users operate against this
70  * class while XPath vendors can plug-in implementations underneath. Users
71  * can choose an implementation using either {@link #setXPathClass} or
72  * the system property "org.jdom.xpath.class".
73  *
74  * @version $Revision: 1.16 $, $Date: 2004/11/03 05:17:17 $
75  * @author Laurent Bihanic
76  */

77 public abstract class XPath implements Serializable {
78
79     private static final String JavaDoc CVS_ID =
80     "@(#) $RCSfile: XPath.java,v $ $Revision: 1.16 $ $Date: 2004/11/03 05:17:17 $ $Name: $";
81
82    /**
83     * The name of the system property from which to retrieve the
84     * name of the implementation class to use.
85     * <p>
86     * The property name is:
87     * "<code>org.jdom.xpath.class</code>".</p>
88     */

89    private final static String JavaDoc XPATH_CLASS_PROPERTY = "org.jdom.xpath.class";
90
91    /**
92     * The default implementation class to use if none was configured.
93     */

94    private final static String JavaDoc DEFAULT_XPATH_CLASS =
95                                                 "org.jdom.xpath.JaxenXPath";
96
97    /**
98     * The string passable to the JAXP 1.3 XPathFactory isObjectModelSupported()
99     * method to query an XPath engine regarding its support for JDOM. Defined
100     * to be the well-known URI "http://jdom.org/jaxp/xpath/jdom".
101     */

102    public final static String JavaDoc JDOM_OBJECT_MODEL_URI =
103      "http://jdom.org/jaxp/xpath/jdom";
104
105    /**
106     * The constructor to instanciate a new XPath concrete
107     * implementation.
108     *
109     * @see #newInstance
110     */

111    private static Constructor constructor = null;
112
113    /**
114     * Creates a new XPath wrapper object, compiling the specified
115     * XPath expression.
116     *
117     * @param path the XPath expression to wrap.
118     *
119     * @throws JDOMException if the XPath expression is invalid.
120     */

121    public static XPath newInstance(String JavaDoc path) throws JDOMException {
122       try {
123          if (constructor == null) {
124             // First call => Determine implementation.
125
String JavaDoc className;
126             try {
127                className = System.getProperty(XPATH_CLASS_PROPERTY,
128                                               DEFAULT_XPATH_CLASS);
129             }
130             catch (SecurityException JavaDoc ex1) {
131                // Access to system property denied. => Use default impl.
132
className = DEFAULT_XPATH_CLASS;
133             }
134             setXPathClass(Class.forName(className));
135          }
136          // Allocate and return new implementation instance.
137
return (XPath)constructor.newInstance(new Object JavaDoc[] { path });
138       }
139       catch (JDOMException ex1) {
140          throw ex1;
141       }
142       catch (InvocationTargetException ex2) {
143          // Constructor threw an error on invocation.
144
Throwable JavaDoc t = ex2.getTargetException();
145
146          throw (t instanceof JDOMException)? (JDOMException)t:
147                                         new JDOMException(t.toString(), t);
148       }
149       catch (Exception JavaDoc ex3) {
150          // Any reflection error (probably due to a configuration mistake).
151
throw new JDOMException(ex3.toString(), ex3);
152       }
153    }
154
155    /**
156     * Sets the concrete XPath subclass to use when allocating XPath
157     * instances.
158     *
159     * @param aClass the concrete subclass of XPath.
160     *
161     * @throws IllegalArgumentException if <code>aClass</code> is
162     * <code>null</code>.
163     * @throws JDOMException if <code>aClass</code> is
164     * not a concrete subclass
165     * of XPath.
166     */

167    public static void setXPathClass(Class JavaDoc aClass) throws JDOMException {
168       if (aClass == null) {
169          throw new IllegalArgumentException JavaDoc("aClass");
170       }
171
172       try {
173          if ((XPath.class.isAssignableFrom(aClass)) &&
174              (Modifier.isAbstract(aClass.getModifiers()) == false)) {
175             // Concrete subclass of XPath => Get constructor
176
constructor = aClass.getConstructor(new Class JavaDoc[] { String JavaDoc.class });
177          }
178          else {
179             throw new JDOMException(aClass.getName() +
180                         " is not a concrete JDOM XPath implementation");
181          }
182       }
183       catch (JDOMException ex1) {
184          throw ex1;
185       }
186       catch (Exception JavaDoc ex2) {
187          // Any reflection error (probably due to a configuration mistake).
188
throw new JDOMException(ex2.toString(), ex2);
189       }
190    }
191
192     /**
193      * Evaluates the wrapped XPath expression and returns the list
194      * of selected items.
195      *
196      * @param context the node to use as context for evaluating
197      * the XPath expression.
198      *
199      * @return the list of selected items, which may be of types: {@link Element},
200      * {@link Attribute}, {@link Text}, {@link CDATA},
201      * {@link Comment}, {@link ProcessingInstruction}, Boolean,
202      * Double, or String.
203      *
204      * @throws JDOMException if the evaluation of the XPath
205      * expression on the specified context
206      * failed.
207      */

208    abstract public List selectNodes(Object JavaDoc context) throws JDOMException;
209
210     /**
211      * Evaluates the wrapped XPath expression and returns the first
212      * entry in the list of selected nodes (or atomics).
213      *
214      * @param context the node to use as context for evaluating
215      * the XPath expression.
216      *
217      * @return the first selected item, which may be of types: {@link Element},
218      * {@link Attribute}, {@link Text}, {@link CDATA},
219      * {@link Comment}, {@link ProcessingInstruction}, Boolean,
220      * Double, String, or <code>null</code> if no item was selected.
221      *
222      * @throws JDOMException if the evaluation of the XPath
223      * expression on the specified context
224      * failed.
225      */

226    abstract public Object JavaDoc selectSingleNode(Object JavaDoc context) throws JDOMException;
227
228    /**
229     * Returns the string value of the first node selected by applying
230     * the wrapped XPath expression to the given context.
231     *
232     * @param context the element to use as context for evaluating
233     * the XPath expression.
234     *
235     * @return the string value of the first node selected by applying
236     * the wrapped XPath expression to the given context.
237     *
238     * @throws JDOMException if the XPath expression is invalid or
239     * its evaluation on the specified context
240     * failed.
241     */

242    abstract public String JavaDoc valueOf(Object JavaDoc context) throws JDOMException;
243
244    /**
245     * Returns the number value of the first node selected by applying
246     * the wrapped XPath expression to the given context.
247     *
248     * @param context the element to use as context for evaluating
249     * the XPath expression.
250     *
251     * @return the number value of the first node selected by applying
252     * the wrapped XPath expression to the given context,
253     * <code>null</code> if no node was selected or the
254     * special value {@link java.lang.Double#NaN}
255     * (Not-a-Number) if the selected value can not be
256     * converted into a number value.
257     *
258     * @throws JDOMException if the XPath expression is invalid or
259     * its evaluation on the specified context
260     * failed.
261     */

262    abstract public Number JavaDoc numberValueOf(Object JavaDoc context) throws JDOMException;
263
264    /**
265     * Defines an XPath variable and sets its value.
266     *
267     * @param name the variable name.
268     * @param value the variable value.
269     *
270     * @throws IllegalArgumentException if <code>name</code> is not
271     * a valid XPath variable name
272     * or if the value type is not
273     * supported by the underlying
274     * implementation
275     */

276    abstract public void setVariable(String JavaDoc name, Object JavaDoc value);
277
278    /**
279     * Adds a namespace definition to the list of namespaces known of
280     * this XPath expression.
281     * <p>
282     * <strong>Note</strong>: In XPath, there is no such thing as a
283     * 'default namespace'. The empty prefix <b>always</b> resolves
284     * to the empty namespace URI.</p>
285     *
286     * @param namespace the namespace.
287     */

288    abstract public void addNamespace(Namespace namespace);
289
290    /**
291     * Adds a namespace definition (prefix and URI) to the list of
292     * namespaces known of this XPath expression.
293     * <p>
294     * <strong>Note</strong>: In XPath, there is no such thing as a
295     * 'default namespace'. The empty prefix <b>always</b> resolves
296     * to the empty namespace URI.</p>
297     *
298     * @param prefix the namespace prefix.
299     * @param uri the namespace URI.
300     *
301     * @throws IllegalNameException if the prefix or uri are null or
302     * empty strings or if they contain
303     * illegal characters.
304     */

305    public void addNamespace(String JavaDoc prefix, String JavaDoc uri) {
306       addNamespace(Namespace.getNamespace(prefix, uri));
307    }
308
309    /**
310     * Returns the wrapped XPath expression as a string.
311     *
312     * @return the wrapped XPath expression as a string.
313     */

314    abstract public String JavaDoc getXPath();
315
316
317    /**
318     * Evaluates an XPath expression and returns the list of selected
319     * items.
320     * <p>
321     * <strong>Note</strong>: This method should not be used when the
322     * same XPath expression needs to be applied several times (on the
323     * same or different contexts) as it requires the expression to be
324     * compiled before being evaluated. In such cases,
325     * {@link #newInstance allocating} an XPath wrapper instance and
326     * {@link #selectNodes(java.lang.Object) evaluating} it several
327     * times is way more efficient.
328     * </p>
329     *
330     * @param context the node to use as context for evaluating
331     * the XPath expression.
332     * @param path the XPath expression to evaluate.
333     *
334     * @return the list of selected items, which may be of types: {@link Element},
335     * {@link Attribute}, {@link Text}, {@link CDATA},
336     * {@link Comment}, {@link ProcessingInstruction}, Boolean,
337     * Double, or String.
338     *
339     * @throws JDOMException if the XPath expression is invalid or
340     * its evaluation on the specified context
341     * failed.
342     */

343    public static List selectNodes(Object JavaDoc context, String JavaDoc path)
344                                                         throws JDOMException {
345       return newInstance(path).selectNodes(context);
346    }
347
348    /**
349     * Evaluates the wrapped XPath expression and returns the first
350     * entry in the list of selected nodes (or atomics).
351     * <p>
352     * <strong>Note</strong>: This method should not be used when the
353     * same XPath expression needs to be applied several times (on the
354     * same or different contexts) as it requires the expression to be
355     * compiled before being evaluated. In such cases,
356     * {@link #newInstance allocating} an XPath wrapper instance and
357     * {@link #selectSingleNode(java.lang.Object) evaluating} it
358     * several times is way more efficient.
359     * </p>
360     *
361     * @param context the element to use as context for evaluating
362     * the XPath expression.
363     * @param path the XPath expression to evaluate.
364     *
365     * @return the first selected item, which may be of types: {@link Element},
366     * {@link Attribute}, {@link Text}, {@link CDATA},
367     * {@link Comment}, {@link ProcessingInstruction}, Boolean,
368     * Double, String, or <code>null</code> if no item was selected.
369     *
370     * @throws JDOMException if the XPath expression is invalid or
371     * its evaluation on the specified context
372     * failed.
373     */

374    public static Object JavaDoc selectSingleNode(Object JavaDoc context, String JavaDoc path)
375                                                         throws JDOMException {
376       return newInstance(path).selectSingleNode(context);
377    }
378
379
380    //-------------------------------------------------------------------------
381
// Serialization support
382
//-------------------------------------------------------------------------
383

384    /**
385     * <i>[Serialization support]</i> Returns the alternative object
386     * to write to the stream when serializing this object. This
387     * method returns an instance of a dedicated nested class to
388     * serialize XPath expressions independently of the concrete
389     * implementation being used.
390     * <p>
391     * <strong>Note</strong>: Subclasses are not allowed to override
392     * this method to ensure valid serialization of all
393     * implementations.</p>
394     *
395     * @return an XPathString instance configured with the wrapped
396     * XPath expression.
397     *
398     * @throws ObjectStreamException never.
399     */

400    protected final Object JavaDoc writeReplace() throws ObjectStreamException {
401       return new XPathString(this.getXPath());
402    }
403
404    /**
405     * The XPathString is dedicated to serialize instances of
406     * XPath subclasses in a implementation-independent manner.
407     * <p>
408     * XPathString ensures that only string data are serialized. Upon
409     * deserialization, XPathString relies on XPath factory method to
410     * to create instances of the concrete XPath wrapper currently
411     * configured.</p>
412     */

413    private final static class XPathString implements Serializable {
414       /**
415        * The XPath expression as a string.
416        */

417       private String JavaDoc xPath = null;
418
419       /**
420        * Creates a new XPathString instance from the specified
421        * XPath expression.
422        *
423        * @param xpath the XPath expression.
424        */

425       public XPathString(String JavaDoc xpath) {
426          super();
427
428          this.xPath = xpath;
429       }
430
431       /**
432        * <i>[Serialization support]</i> Resolves the read XPathString
433        * objects into XPath implementations.
434        *
435        * @return an instance of a concrete implementation of
436        * XPath.
437        *
438        * @throws ObjectStreamException if no XPath could be built
439        * from the read object.
440        */

441       private Object JavaDoc readResolve() throws ObjectStreamException {
442          try {
443             return XPath.newInstance(this.xPath);
444          }
445          catch (JDOMException ex1) {
446             throw new InvalidObjectException(
447                         "Can't create XPath object for expression \"" +
448                         this.xPath + "\": " + ex1.toString());
449          }
450       }
451    }
452 }
453
454
Popular Tags