Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/jdom/xpath/JaxenXPath.java


1   /*--
2   
3    $Id: JaxenXPath.java,v 1.19 2004/09/03 07:27:39 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.util.*;
61  
62  import org.jaxen.*;
63  import org.jaxen.jdom.*;
64  import org.jdom.*;
65  
66  
67  /**
68   * A non-public concrete XPath implementation for Jaxen.
69   *
70   * @version $Revision: 1.19 $, $Date: 2004/09/03 07:27:39 $
71   * @author  Laurent Bihanic
72   */
73  class JaxenXPath extends    XPath {             // package protected
74  
75      private static final String CVS_ID =
76      "@(#) $RCSfile: JaxenXPath.java,v $ $Revision: 1.19 $ $Date: 2004/09/03 07:27:39 $ $Name: jdom_1_0 $";
77  
78     /**
79      * The compiled XPath object to select nodes.  This attribute can
80      * not be made final as it needs to be set upon object
81      * deserialization.
82      */
83     private transient JDOMXPath xPath;
84  
85     /**
86      * The current context for XPath expression evaluation.
87      */
88     private           Object    currentContext;
89  
90     /**
91      * Creates a new XPath wrapper object, compiling the specified
92      * XPath expression.
93      *
94      * @param  expr   the XPath expression to wrap.
95      *
96      * @throws JDOMException   if the XPath expression is invalid.
97      */
98     public JaxenXPath(String expr) throws JDOMException {
99        setXPath(expr);
100    }
101 
102    /**
103     * Evaluates the wrapped XPath expression and returns the list
104     * of selected items.
105     *
106     * @param  context   the node to use as context for evaluating
107     *                   the XPath expression.
108     *
109     * @return the list of selected items, which may be of types: {@link Element},
110     *         {@link Attribute}, {@link Text}, {@link CDATA},
111     *         {@link Comment}, {@link ProcessingInstruction}, Boolean,
112     *         Double, or String.
113     *
114     * @throws JDOMException   if the evaluation of the XPath
115     *                         expression on the specified context
116     *                         failed.
117     */
118    public List selectNodes(Object context) throws JDOMException {
119       try {
120          currentContext = context;
121 
122          return xPath.selectNodes(context);
123       }
124       catch (JaxenException ex1) {
125          throw new JDOMException("XPath error while evaluating \"" +
126                         xPath.toString() + "\": " + ex1.getMessage(), ex1);
127       }
128       finally {
129          currentContext = null;
130       }
131    }
132 
133    /**
134     * Evaluates the wrapped XPath expression and returns the first
135     * entry in the list of selected nodes (or atomics).
136     *
137     * @param  context   the node to use as context for evaluating
138     *                   the XPath expression.
139     *
140     * @return the first selected item, which may be of types: {@link Element},
141     *         {@link Attribute}, {@link Text}, {@link CDATA},
142     *         {@link Comment}, {@link ProcessingInstruction}, Boolean,
143     *         Double, String, or <code>null</code> if no item was selected.
144     *
145     * @throws JDOMException   if the evaluation of the XPath
146     *                         expression on the specified context
147     *                         failed.
148     */
149    public Object selectSingleNode(Object context) throws JDOMException {
150       try {
151          currentContext = context;
152 
153          return xPath.selectSingleNode(context);
154       }
155       catch (JaxenException ex1) {
156          throw new JDOMException("XPath error while evaluating \"" +
157                         xPath.toString() + "\": " + ex1.getMessage(), ex1);
158       }
159       finally {
160          currentContext = null;
161       }
162    }
163 
164    /**
165     * Returns the string value of the first node selected by applying
166     * the wrapped XPath expression to the given context.
167     *
168     * @param  context   the element to use as context for evaluating
169     *                   the XPath expression.
170     *
171     * @return the string value of the first node selected by applying
172     *         the wrapped XPath expression to the given context.
173     *
174     * @throws JDOMException   if the XPath expression is invalid or
175     *                         its evaluation on the specified context
176     *                         failed.
177     */
178    public String valueOf(Object context) throws JDOMException {
179       try {
180          currentContext = context;
181 
182          return xPath.stringValueOf(context);
183       }
184       catch (JaxenException ex1) {
185          throw new JDOMException("XPath error while evaluating \"" +
186                         xPath.toString() + "\": " + ex1.getMessage(), ex1);
187       }
188       finally {
189          currentContext = null;
190       }
191    }
192 
193    /**
194     * Returns the number value of the first item selected by applying
195     * the wrapped XPath expression to the given context.
196     *
197     * @param  context   the element to use as context for evaluating
198     *                   the XPath expression.
199     *
200     * @return the number value of the first item selected by applying
201     *         the wrapped XPath expression to the given context,
202     *         <code>null</code> if no node was selected or the
203     *         special value {@link java.lang.Double#NaN}
204     *         (Not-a-Number) if the selected value can not be
205     *         converted into a number value.
206     *
207     * @throws JDOMException   if the XPath expression is invalid or
208     *                         its evaluation on the specified context
209     *                         failed.
210     */
211    public Number numberValueOf(Object context) throws JDOMException {
212       try {
213          currentContext = context;
214 
215          return xPath.numberValueOf(context);
216       }
217       catch (JaxenException ex1) {
218          throw new JDOMException("XPath error while evaluating \"" +
219                         xPath.toString() + "\": " + ex1.getMessage(), ex1);
220       }
221       finally {
222          currentContext = null;
223       }
224    }
225 
226    /**
227     * Defines an XPath variable and sets its value.
228     *
229     * @param  name    the variable name.
230     * @param  value   the variable value.
231     *
232     * @throws IllegalArgumentException   if <code>name</code> is not
233     *                                    a valid XPath variable name
234     *                                    or if the value type is not
235     *                                    supported by the underlying
236     *                                    implementation
237     */
238    public void setVariable(String name, Object value)
239                                         throws IllegalArgumentException {
240       Object o = xPath.getVariableContext();
241       if (o instanceof SimpleVariableContext) {
242            ((SimpleVariableContext)o).setVariableValue(null, name, value);
243       }
244    }
245 
246    /**
247     * Adds a namespace definition to the list of namespaces known of
248     * this XPath expression.
249     * <p>
250     * <strong>Note</strong>: In XPath, there is no such thing as a
251     * 'default namespace'.  The empty prefix <b>always</b> resolves
252     * to the empty namespace URI.</p>
253     *
254     * @param  namespace   the namespace.
255     */
256    public void addNamespace(Namespace namespace) {
257       try {
258          xPath.addNamespace(namespace.getPrefix(), namespace.getURI());
259       }
260       catch (JaxenException ex1) { /* Can't happen here. */ }
261    }
262 
263    /**
264     * Returns the wrapped XPath expression as a string.
265     *
266     * @return the wrapped XPath expression as a string.
267     */
268    public String getXPath() {
269       return (xPath.toString());
270    }
271 
272    /**
273     * Compiles and sets the XPath expression wrapped by this object.
274     *
275     * @param  expr   the XPath expression to wrap.
276     *
277     * @throws JDOMException   if the XPath expression is invalid.
278     */
279    private void setXPath(String expr) throws JDOMException {
280       try {
281          xPath = new JDOMXPath(expr);
282          xPath.setNamespaceContext(new NSContext());
283       }
284       catch (Exception ex1) {
285          throw new JDOMException(
286                         "Invalid XPath expression: \"" + expr + "\"", ex1);
287       }
288    }
289 
290    public String toString() {
291       return (xPath.toString());
292    }
293 
294    public boolean equals(Object o) {
295       if (o instanceof JaxenXPath) {
296          JaxenXPath x = (JaxenXPath)o;
297 
298          return (super.equals(o) &&
299                  xPath.toString().equals(x.xPath.toString()));
300       }
301       return false;
302    }
303 
304    public int hashCode() {
305       return xPath.hashCode();
306    }
307 
308    private class NSContext extends SimpleNamespaceContext {
309       public NSContext() {
310          super();
311       }
312 
313       /**
314        * <i>[Jaxen NamespaceContext interface support]</i> Translates
315        * the provided namespace prefix into the matching bound
316        * namespace URI.
317        *
318        * @param  prefix   the namespace prefix to resolve.
319        *
320        * @return the namespace URI matching the prefix.
321        */
322       public String translateNamespacePrefixToUri(String prefix) {
323          if ((prefix == null) || (prefix.length() == 0)) {
324             return null;
325          }
326 
327          String uri = super.translateNamespacePrefixToUri(prefix);
328          if (uri == null) {
329             Object ctx = currentContext;
330             if (ctx != null) {
331                Element elt = null;
332 
333                // Get closer element node
334                if (ctx instanceof Element) {
335                   elt = (Element)ctx;
336                } else if (ctx instanceof Attribute) {
337                   elt = ((Attribute)ctx).getParent();
338                } else if (ctx instanceof Content) {
339                   elt = ((Content) ctx).getParentElement();
340                } else if (ctx instanceof Document) {
341                   elt = ((Document)ctx).getRootElement();
342                }
343 
344                if (elt != null) {
345                   Namespace ns = elt.getNamespace(prefix);
346                   if (ns != null) {
347                      uri = ns.getURI();
348                   }
349                }
350             }
351          }
352          return uri;
353       }
354    }
355 }
356