##### Coverage Report - org.jaxen.BaseXPath

Classes in this File | Line Coverage | Branch Coverage | Complexity
BaseXPath |
99% |
100% |
| 1.8148148148148149;1.815

1 |  |
     /*
2 |  |
      * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/BaseXPath.java,v 1.48 2005/09/24 23:05:15 elharo Exp $
3 |  |
      * $Revision: 1.48 $
4 |  |
      * $Date: 2005/09/24 23:05:15 $
5 |  |
      *
6 |  |
      * ====================================================================
7 |  |
      *
8 |  |
      * Copyright (C) 2000-2002 bob mcwhirter & James Strachan.
9 |  |
      * All rights reserved.
10 |  |
      *
11 |  |
      * Redistribution and use in source and binary forms, with or without
12 |  |
      * modification, are permitted provided that the following conditions
13 |  |
      * are met:
14 |  |
      *
15 |  |
      * 1. Redistributions of source code must retain the above copyright
16 |  |
      *    notice, this list of conditions, and the following disclaimer.
17 |  |
      *
18 |  |
      * 2. Redistributions in binary form must reproduce the above copyright
19 |  |
      *    notice, this list of conditions, and the disclaimer that follows
20 |  |
      *    these conditions in the documentation and/or other materials
21 |  |
      *    provided with the distribution.
22 |  |
      *
23 |  |
      * 3. The name "Jaxen" must not be used to endorse or promote products
24 |  |
      *    derived from this software without prior written permission.  For
25 |  |
      *    written permission, please contact license@jaxen.org.
26 |  |
      *
27 |  |
      * 4. Products derived from this software may not be called "Jaxen", nor
28 |  |
      *    may "Jaxen" appear in their name, without prior written permission
29 |  |
      *    from the Jaxen Project Management (pm@jaxen.org).
30 |  |
      *
31 |  |
      * In addition, we request (but do not require) that you include in the
32 |  |
      * end-user documentation provided with the redistribution and/or in the
33 |  |
      * software itself an acknowledgement equivalent to the following:
34 |  |
      *     "This product includes software developed by the
35 |  |
      *      Jaxen Project <http://www.jaxen.org/>."
36 |  |
      * Alternatively, the acknowledgment may be graphical using the logos
37 |  |
      * available at http://www.jaxen.org/
38 |  |
      *
39 |  |
      * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
40 |  |
      * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
41 |  |
      * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
42 |  |
      * DISCLAIMED.  IN NO EVENT SHALL THE Jaxen AUTHORS OR THE PROJECT
43 |  |
      * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 |  |
      * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
45 |  |
      * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
46 |  |
      * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
47 |  |
      * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
48 |  |
      * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
49 |  |
      * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 |  |
      * SUCH DAMAGE.
51 |  |
      *
52 |  |
      * ====================================================================
53 |  |
      * This software consists of voluntary contributions made by many
54 |  |
      * individuals on behalf of the Jaxen Project and was originally
55 |  |
      * created by bob mcwhirter <bob@werken.com> and
56 |  |
      * James Strachan <jstrachan@apache.org>.  For more information on the
57 |  |
      * Jaxen Project, please see <http://www.jaxen.org/>.
58 |  |
      *
59 |  |
      * $Id: BaseXPath.java,v 1.48 2005/09/24 23:05:15 elharo Exp $
60 |  |
      */
61 |  |
62 |  |
63 |  |
     package org.jaxen;
64 |  |
65 |  |
     import java.io.Serializable;
66 |  |
     import java.util.List;
67 |  |
68 |  |
     import org.jaxen.expr.Expr;
69 |  |
     import org.jaxen.expr.XPathExpr;
70 |  |
     import org.jaxen.function.BooleanFunction;
71 |  |
     import org.jaxen.function.NumberFunction;
72 |  |
     import org.jaxen.function.StringFunction;
73 |  |
     import org.jaxen.saxpath.SAXPathException;
74 |  |
     import org.jaxen.saxpath.XPathReader;
75 |  |
     import org.jaxen.saxpath.helpers.XPathReaderFactory;
76 |  |
     import org.jaxen.util.SingletonList;
77 |  |
78 |  |
     /** Base functionality for all concrete, implementation-specific XPaths.
79 |  |
      *
80 |  |
      *  <p>
81 |  |
      *  This class provides generic functionality for further-defined
82 |  |
      *  implementation-specific XPaths.
83 |  |
      *  </p>
84 |  |
      *
85 |  |
      *  <p>
86 |  |
      *  If you want to adapt the Jaxen engine so that it can traverse your own
87 |  |
      *  object model, then this is a good base class to derive from.
88 |  |
      *  Typically you only really need to provide your own
89 |  |
      *  {@link org.jaxen.Navigator} implementation.
90 |  |
      *  </p>
91 |  |
      *
92 |  |
      *  @see org.jaxen.dom4j.Dom4jXPath XPath for dom4j
93 |  |
      *  @see org.jaxen.jdom.JDOMXPath   XPath for JDOM
94 |  |
      *  @see org.jaxen.dom.DOMXPath     XPath for W3C DOM
95 |  |
      *
96 |  |
      *  @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
97 |  |
      *  @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
98 |  |
      */
99 |  |
     public class BaseXPath implements XPath, Serializable
100 |  |
     {
101 |  |
         /** Original expression text. */
102 |  |
         private String exprText;
103 |  |
104 |  |
         /** the parsed form of the XPath expression */
105 |  |
         private XPathExpr xpath;
106 |  |
107 |  |
         /** the support information and function, namespace and variable contexts */
108 |  |
         private ContextSupport support;
109 |  |
110 |  |
         /** the implementation-specific Navigator for retrieving XML nodes **/
111 |  |
         private Navigator navigator;
112 |  |
113 |  |
         /** Construct given an XPath expression string.
114 |  |
          *
115 |  |
          *  @param xpathExpr the XPath expression
116 |  |
          *
117 |  |
          *  @throws JaxenException if there is a syntax error while
118 |  |
          *          parsing the expression
119 |  |
          */
120 |  |
         protected BaseXPath(String xpathExpr) throws JaxenException
121 | 10578 |
         {
122 |  |
             try
123 |  |
             {
124 | 10578 |
                 XPathReader reader = XPathReaderFactory.createReader();
125 | 10572 |
                 JaxenHandler handler = new JaxenHandler();
126 | 10572 |
                 reader.setXPathHandler( handler );
127 | 10572 |
                 reader.parse( xpathExpr );
128 | 10356 |
                 this.xpath = handler.getXPathExpr();
129 |  |
             }
130 | 216 |
             catch (org.jaxen.saxpath.XPathSyntaxException e)
131 |  |
             {
132 | 216 |
                 throw new org.jaxen.XPathSyntaxException( e );
133 |  |
             }
134 | 6 |
             catch (SAXPathException e)
135 |  |
             {
136 | 6 |
                 throw new JaxenException( e );
137 | 10356 |
             }
138 |  |
139 | 10356 |
             this.exprText = xpathExpr;
140 | 10356 |
         }
141 |  |
142 |  |
         /** Construct given an XPath expression string.
143 |  |
          *
144 |  |
          *  @param xpathExpr the XPath expression
145 |  |
          *
146 |  |
          *  @param navigator the XML navigator to use
147 |  |
          *
148 |  |
          *  @throws JaxenException if there is a syntax error while
149 |  |
          *          parsing the expression
150 |  |
          */
151 |  |
         public BaseXPath(String xpathExpr, Navigator navigator) throws JaxenException
152 |  |
         {
153 | 3510 |
             this( xpathExpr );
154 | 3480 |
             this.navigator = navigator;
155 | 3480 |
         }
156 |  |
157 |  |
         /** Evaluate this XPath against a given context.
158 |  |
          *  The context of evaluation may be any object type
159 |  |
          *  the navigator recognizes as a node.
160 |  |
          *  The return value is either a <code>String</code>,
161 |  |
          *  <code>Double</code>, <code>Boolean</code>, or <code>List</code>
162 |  |
          *  of nodes.
163 |  |
          *
164 |  |
          *  <p>
165 |  |
          *  When using this method, one must be careful to
166 |  |
          *  test the class of the returned object.  If the returned
167 |  |
          *  object is a list, then the items in this
168 |  |
          *  list will be the actual <code>Document</code>,
169 |  |
          *  <code>Element</code>, <code>Attribute</code>, etc. objects
170 |  |
          *  as defined by the concrete XML object-model implementation,
171 |  |
          *  directly from the context document.  This method <strong>does
172 |  |
          *  not return <em>copies</em> of anything</strong>, but merely
173 |  |
          *  returns references to objects within the source document.
174 |  |
          *  </p>
175 |  |
          *
176 |  |
          * @param context the node, node-set or Context object for evaluation.
177 |  |
          *      This value can be null.
178 |  |
          *
179 |  |
          * @return the result of evaluating the XPath expression
180 |  |
          *          against the supplied context
181 |  |
          * @throws JaxenException if an XPath error occurs during expression evaluation
182 |  |
          * @throws ClassCastException if the context is not a node
183 |  |
          */
184 |  |
         public Object evaluate(Object context) throws JaxenException
185 |  |
         {
186 | 4644 |
             List answer = selectNodes(context);
187 |  |
188 | 4584 |
             if ( answer != null
189 |  |
                  &&
190 |  |
                  answer.size() == 1 )
191 |  |
             {
192 | 4566 |
                 Object first = answer.get(0);
193 |  |
194 | 4566 |
                 if ( first instanceof String
195 |  |
                      ||
196 |  |
                      first instanceof Number
197 |  |
                      ||
198 |  |
                      first instanceof Boolean )
199 |  |
                 {
200 | 3762 |
                     return first;
201 |  |
                 }
202 |  |
             }
203 | 822 |
             return answer;
204 |  |
         }
205 |  |
206 |  |
         /** Select all nodes that are selected by this XPath
207 |  |
          *  expression. If multiple nodes match, multiple nodes
208 |  |
          *  will be returned. Nodes will be returned
209 |  |
          *  in document-order, as defined by the XPath
210 |  |
          *  specification. If the expression selects a non-node-set
211 |  |
          *  (i.e. a number, boolean, or string) then a List
212 |  |
          *  containing just that one object is returned.
213 |  |
          *  </p>
214 |  |
          *
215 |  |
          * @param node the node, node-set or Context object for evaluation.
216 |  |
          *     This value can be null.
217 |  |
          *
218 |  |
          * @return the node-set of all items selected
219 |  |
          *          by this XPath expression
220 |  |
          * @throws JaxenException if an XPath error occurs during expression evaluation
221 |  |
          *
222 |  |
          * @see #selectNodesForContext
223 |  |
          */
224 |  |
         public List selectNodes(Object node) throws JaxenException
225 |  |
         {
226 | 10236 |
             Context context = getContext( node );
227 | 10236 |
             return selectNodesForContext( context );
228 |  |
         }
229 |  |
230 |  |
         /** Select only the first node selected by this XPath
231 |  |
          *  expression.  If multiple nodes match, only one node will be
232 |  |
          *  returned. The selected node will be the first
233 |  |
          *  selected node in document-order, as defined by the XPath
234 |  |
          *  specification.
235 |  |
          *  </p>
236 |  |
          *
237 |  |
          * @param node the node, node-set or Context object for evaluation.
238 |  |
          *     This value can be null.
239 |  |
          *
240 |  |
          * @return the node-set of all items selected
241 |  |
          *          by this XPath expression
242 |  |
          * @throws JaxenException if an XPath error occurs during expression evaluation
243 |  |
          *
244 |  |
          * @see #selectNodes
245 |  |
          */
246 |  |
         public Object selectSingleNode(Object node) throws JaxenException
247 |  |
         {
248 | 12 |
             List results = selectNodes( node );
249 |  |
250 | 12 |
             if ( results.isEmpty() )
251 |  |
             {
252 | 6 |
                 return null;
253 |  |
             }
254 |  |
255 | 6 |
             return results.get( 0 );
256 |  |
         }
257 |  |
258 |  |
         /**
259 |  |
          * Returns the XPath string-value of the argument node.
260 |  |
          *
261 |  |
          * @param node the node whose value to take
262 |  |
          * @return the XPath string value of this node
263 |  |
          * @throws JaxenException if an XPath error occurs during expression evaluation
264 |  |
          * @deprecated replaced by {@link #stringValueOf}
265 |  |
          */
266 |  |
         public String valueOf(Object node) throws JaxenException
267 |  |
         {
268 | 0 |
             return stringValueOf( node );
269 |  |
         }
270 |  |
271 |  |
         /** Retrieves the string-value of the result of
272 |  |
          *  evaluating this XPath expression when evaluated
273 |  |
          *  against the specified context.
274 |  |
          *
275 |  |
          *  <p>
276 |  |
          *  The string-value of the expression is determined per
277 |  |
          *  the <code>string(..)</code> core function defined
278 |  |
          *  in the XPath specification.  This means that an expression
279 |  |
          *  that selects zero nodes will return the empty string,
280 |  |
          *  while an expression that selects one-or-more nodes will
281 |  |
          *  return the string-value of the first node.
282 |  |
          *  </p>
283 |  |
          *
284 |  |
          * @param node the node, node-set or Context object for evaluation. This value can be null.
285 |  |
          *
286 |  |
          * @return the string-value of the result of evaluating this expression with the specified context node
287 |  |
          * @throws JaxenException if an XPath error occurs during expression evaluation
288 |  |
          */
289 |  |
         public String stringValueOf(Object node) throws JaxenException
290 |  |
         {
291 | 18 |
             Context context = getContext( node );
292 |  |
293 | 18 |
             Object result = selectSingleNodeForContext( context );
294 |  |
295 | 18 |
             if ( result == null )
296 |  |
             {
297 | 6 |
                 return "";
298 |  |
             }
299 |  |
300 | 12 |
             return StringFunction.evaluate( result,
301 |  |
                                             context.getNavigator() );
302 |  |
         }
303 |  |
304 |  |
         /** Retrieve a boolean-value interpretation of this XPath
305 |  |
          *  expression when evaluated against a given context.
306 |  |
          *
307 |  |
          *  <p>
308 |  |
          *  The boolean-value of the expression is determined per
309 |  |
          *  the <code>boolean(..)</code> function defined
310 |  |
          *  in the XPath specification.  This means that an expression
311 |  |
          *  that selects zero nodes will return <code>false</code>,
312 |  |
          *  while an expression that selects one or more nodes will
313 |  |
          *  return <code>true</code>.
314 |  |
          *  </p>
315 |  |
          *
316 |  |
          * @param node the node, node-set or Context object for evaluation. This value can be null.
317 |  |
          *
318 |  |
          * @return the boolean-value of the result of evaluating this expression with the specified context node
319 |  |
          * @throws JaxenException if an XPath error occurs during expression evaluation
320 |  |
          */
321 |  |
         public boolean booleanValueOf(Object node) throws JaxenException
322 |  |
         {
323 | 24 |
             Context context = getContext( node );
324 | 24 |
             List result = selectNodesForContext( context );
325 | 24 |
             if ( result == null ) return false;
326 | 24 |
             return BooleanFunction.evaluate( result, context.getNavigator() ).booleanValue();
327 |  |
         }
328 |  |
329 |  |
         /** Retrieve a number-value interpretation of this XPath
330 |  |
          *  expression when evaluated against a given context.
331 |  |
          *
332 |  |
          *  <p>
333 |  |
          *  The number-value of the expression is determined per
334 |  |
          *  the <code>number(..)</code> core function as defined
335 |  |
          *  in the XPath specification. This means that if this
336 |  |
          *  expression selects multiple nodes, the number-value
337 |  |
          *  of the first node is returned.
338 |  |
          *  </p>
339 |  |
          *
340 |  |
          * @param node the node, node-set or Context object for evaluation. This value can be null.
341 |  |
          *
342 |  |
          * @return a <code>Double</code> indicating the numeric value of
343 |  |
          *      evaluating this expression against the specified context
344 |  |
          * @throws JaxenException if an XPath error occurs during expression evaluation
345 |  |
          */
346 |  |
         public Number numberValueOf(Object node) throws JaxenException
347 |  |
         {
348 | 18 |
             Context context = getContext( node );
349 | 18 |
             Object result = selectSingleNodeForContext( context );
350 | 18 |
             return NumberFunction.evaluate( result,
351 |  |
                                             context.getNavigator() );
352 |  |
         }
353 |  |
354 |  |
         // Helpers
355 |  |
356 |  |
         /** Add a namespace prefix-to-URI mapping for this XPath
357 |  |
          *  expression.
358 |  |
          *
359 |  |
          *  <p>
360 |  |
          *  Namespace prefix-to-URI mappings in an XPath are independent
361 |  |
          *  of those used within any document.  Only the mapping explicitly
362 |  |
          *  added to this XPath will be available for resolving the
363 |  |
          *  XPath expression.
364 |  |
          *  </p>
365 |  |
          *
366 |  |
          *  <p>
367 |  |
          *  This is a convenience method for adding mappings to the
368 |  |
          *  default {@link NamespaceContext} in place for this XPath.
369 |  |
          *  If you have installed a custom <code>NamespaceContext</code>
370 |  |
          *  that is not a <code>SimpleNamespaceContext</code>,
371 |  |
          *  then this method will throw a <code>JaxenException</code>.
372 |  |
          *  </p>
373 |  |
          *
374 |  |
          *  @param prefix the namespace prefix
375 |  |
          *  @param uri the namespace URI
376 |  |
          *
377 |  |
          *  @throws JaxenException if the <code>NamespaceContext</code>
378 |  |
          *          used by this XPath is not a <code>SimpleNamespaceContext</code>
379 |  |
          */
380 |  |
         public void addNamespace(String prefix,
381 |  |
                                  String uri) throws JaxenException
382 |  |
         {
383 | 18 |
             NamespaceContext nsContext = getNamespaceContext();
384 | 18 |
             if ( nsContext instanceof SimpleNamespaceContext )
385 |  |
             {
386 | 12 |
                 ((SimpleNamespaceContext)nsContext).addNamespace( prefix,
387 |  |
                                                                   uri );
388 | 12 |
                 return;
389 |  |
             }
390 |  |
391 | 6 |
             throw new JaxenException("Operation not permitted while using a non-simple namespace context.");
392 |  |
         }
393 |  |
394 |  |
395 |  |
         // ------------------------------------------------------------
396 |  |
         // ------------------------------------------------------------
397 |  |
         //     Properties
398 |  |
         // ------------------------------------------------------------
399 |  |
         // ------------------------------------------------------------
400 |  |
401 |  |
402 |  |
         /** Set a <code>NamespaceContext</code> for use with this
403 |  |
          *  XPath expression.
404 |  |
          *
405 |  |
          *  <p>
406 |  |
          *  A <code>NamespaceContext</code> is responsible for translating
407 |  |
          *  namespace prefixes within the expression into namespace URIs.
408 |  |
          *  </p>
409 |  |
          *
410 |  |
          *  @param namespaceContext the <code>NamespaceContext</code> to
411 |  |
          *         install for this expression
412 |  |
          *
413 |  |
          *  @see NamespaceContext
414 |  |
          *  @see NamespaceContext#translateNamespacePrefixToUri
415 |  |
          */
416 |  |
         public void setNamespaceContext(NamespaceContext namespaceContext)
417 |  |
         {
418 | 192 |
             getContextSupport().setNamespaceContext(namespaceContext);
419 | 192 |
         }
420 |  |
421 |  |
         /** Set a <code>FunctionContext</code> for use with this XPath
422 |  |
          *  expression.
423 |  |
          *
424 |  |
          *  <p>
425 |  |
          *  A <code>FunctionContext</code> is responsible for resolving
426 |  |
          *  all function calls used within the expression.
427 |  |
          *  </p>
428 |  |
          *
429 |  |
          *  @param functionContext the <code>FunctionContext</code> to
430 |  |
          *         install for this expression
431 |  |
          *
432 |  |
          *  @see FunctionContext
433 |  |
          *  @see FunctionContext#getFunction
434 |  |
          */
435 |  |
         public void setFunctionContext(FunctionContext functionContext)
436 |  |
         {
437 | 174 |
             getContextSupport().setFunctionContext(functionContext);
438 | 174 |
         }
439 |  |
440 |  |
         /** Set a <code>VariableContext</code> for use with this XPath
441 |  |
          *  expression.
442 |  |
          *
443 |  |
          *  <p>
444 |  |
          *  A <code>VariableContext</code> is responsible for resolving
445 |  |
          *  all variables referenced within the expression.
446 |  |
          *  </p>
447 |  |
          *
448 |  |
          *  @param variableContext The <code>VariableContext</code> to
449 |  |
          *         install for this expression
450 |  |
          *
451 |  |
          *  @see VariableContext
452 |  |
          *  @see VariableContext#getVariableValue
453 |  |
          */
454 |  |
         public void setVariableContext(VariableContext variableContext)
455 |  |
         {
456 | 168 |
             getContextSupport().setVariableContext(variableContext);
457 | 168 |
         }
458 |  |
459 |  |
         /** Retrieve the <code>NamespaceContext</code> used by this XPath
460 |  |
          *  expression.
461 |  |
          *
462 |  |
          *  <p>
463 |  |
          *  A <code>NamespaceContext</code> is responsible for mapping
464 |  |
          *  prefixes used within the expression to namespace URIs.
465 |  |
          *  </p>
466 |  |
          *
467 |  |
          *  <p>
468 |  |
          *  If this XPath expression has not previously had a <code>NamespaceContext</code>
469 |  |
          *  installed, a new default <code>NamespaceContext</code> will be created,
470 |  |
          *  installed and returned.
471 |  |
          *  </p>
472 |  |
          *
473 |  |
          *  @return the <code>NamespaceContext</code> used by this expression
474 |  |
          *
475 |  |
          *  @see NamespaceContext
476 |  |
          */
477 |  |
         public NamespaceContext getNamespaceContext()
478 |  |
         {
479 | 24 |
             return getContextSupport().getNamespaceContext();
480 |  |
         }
481 |  |
482 |  |
         /** Retrieve the <code>FunctionContext</code> used by this XPath
483 |  |
          *  expression.
484 |  |
          *
485 |  |
          *  <p>
486 |  |
          *  A <code>FunctionContext</code> is responsible for resolving
487 |  |
          *  all function calls used within the expression.
488 |  |
          *  </p>
489 |  |
          *
490 |  |
          *  <p>
491 |  |
          *  If this XPath expression has not previously had a <code>FunctionContext</code>
492 |  |
          *  installed, a new default <code>FunctionContext</code> will be created,
493 |  |
          *  installed and returned.
494 |  |
          *  </p>
495 |  |
          *
496 |  |
          *  @return the <code>FunctionContext</code> used by this expression
497 |  |
          *
498 |  |
          *  @see FunctionContext
499 |  |
          */
500 |  |
         public FunctionContext getFunctionContext()
501 |  |
         {
502 | 12 |
             return getContextSupport().getFunctionContext();
503 |  |
         }
504 |  |
505 |  |
         /** Retrieve the <code>VariableContext</code> used by this XPath
506 |  |
          *  expression.
507 |  |
          *
508 |  |
          *  <p>
509 |  |
          *  A <code>VariableContext</code> is responsible for resolving
510 |  |
          *  all variables referenced within the expression.
511 |  |
          *  </p>
512 |  |
          *
513 |  |
          *  <p>
514 |  |
          *  If this XPath expression has not previously had a <code>VariableContext</code>
515 |  |
          *  installed, a new default <code>VariableContext</code> will be created,
516 |  |
          *  installed and returned.
517 |  |
          *  </p>
518 |  |
          *
519 |  |
          *  @return the <code>VariableContext</code> used by this expression
520 |  |
          *
521 |  |
          *  @see VariableContext
522 |  |
          */
523 |  |
         public VariableContext getVariableContext()
524 |  |
         {
525 | 6 |
             return getContextSupport().getVariableContext();
526 |  |
         }
527 |  |
528 |  |
529 |  |
         /** Retrieve the root expression of the internal
530 |  |
          *  compiled form of this XPath expression.
531 |  |
          *
532 |  |
          *  <p>
533 |  |
          *  Internally, Jaxen maintains a form of Abstract Syntax
534 |  |
          *  Tree (AST) to represent the structure of the XPath expression.
535 |  |
          *  This is normally not required during normal consumer-grade
536 |  |
          *  usage of Jaxen.  This method is provided for hard-core users
537 |  |
          *  who wish to manipulate or inspect a tree-based version of
538 |  |
          *  the expression.
539 |  |
          *  </p>
540 |  |
          *
541 |  |
          *  @return the root of the AST of this expression
542 |  |
          */
543 |  |
         public Expr getRootExpr()
544 |  |
         {
545 | 6 |
             return xpath.getRootExpr();
546 |  |
         }
547 |  |
548 |  |
         /** Return the original expression text.
549 |  |
          *
550 |  |
          *  @return the normalized XPath expression string
551 |  |
          */
552 |  |
         public String toString()
553 |  |
         {
554 | 1488 |
             return this.exprText;
555 |  |
         }
556 |  |
557 |  |
         /** Returns a string representation of the parse tree.
558 |  |
          *
559 |  |
          *  @return a string representation of the parse tree.
560 |  |
          */
561 |  |
         public String debug()
562 |  |
         {
563 | 6 |
             return this.xpath.toString();
564 |  |
         }
565 |  |
566 |  |
         // ------------------------------------------------------------
567 |  |
         // ------------------------------------------------------------
568 |  |
         //     Implementation methods
569 |  |
         // ------------------------------------------------------------
570 |  |
         // ------------------------------------------------------------
571 |  |
572 |  |
573 |  |
         /** Create a {@link Context} wrapper for the provided
574 |  |
          *  implementation-specific object.
575 |  |
          *
576 |  |
          *  @param node the implementation-specific object
577 |  |
          *         to be used as the context
578 |  |
          *
579 |  |
          *  @return a <code>Context</code> wrapper around the object
580 |  |
          */
581 |  |
         protected Context getContext(Object node)
582 |  |
         {
583 | 10296 |
             if ( node instanceof Context )
584 |  |
             {
585 | 7032 |
                 return (Context) node;
586 |  |
             }
587 |  |
588 | 3264 |
             Context fullContext = new Context( getContextSupport() );
589 |  |
590 | 3264 |
             if ( node instanceof List )
591 |  |
             {
592 | 6 |
                 fullContext.setNodeSet( (List) node );
593 |  |
             }
594 |  |
             else
595 |  |
             {
596 | 3258 |
                 List list = new SingletonList(node);
597 | 3258 |
                 fullContext.setNodeSet( list );
598 |  |
             }
599 |  |
600 | 3264 |
             return fullContext;
601 |  |
         }
602 |  |
603 |  |
         /** Retrieve the {@link ContextSupport} aggregation of
604 |  |
          *  <code>NamespaceContext</code>, <code>FunctionContext</code>,
605 |  |
          *  <code>VariableContext</code>, and {@link Navigator}.
606 |  |
          *
607 |  |
          *  @return aggregate <code>ContextSupport</code> for this
608 |  |
          *          XPath expression
609 |  |
          */
610 |  |
         protected ContextSupport getContextSupport()
611 |  |
         {
612 | 3840 |
             if ( support == null )
613 |  |
             {
614 | 3450 |
                 support = new ContextSupport(
615 |  |
                     createNamespaceContext(),
616 |  |
                     createFunctionContext(),
617 |  |
                     createVariableContext(),
618 |  |
                     getNavigator()
619 |  |
                 );
620 |  |
             }
621 |  |
622 | 3840 |
             return support;
623 |  |
         }
624 |  |
625 |  |
         /** Retrieve the XML object-model-specific {@link Navigator}
626 |  |
          *  for us in evaluating this XPath expression.
627 |  |
          *
628 |  |
          *  @return the implementation-specific <code>Navigator</code>
629 |  |
          */
630 |  |
         public Navigator getNavigator()
631 |  |
         {
632 | 3456 |
             return navigator;
633 |  |
         }
634 |  |
635 |  |
636 |  |
637 |  |
         // ------------------------------------------------------------
638 |  |
         // ------------------------------------------------------------
639 |  |
         //     Factory methods for default contexts
640 |  |
         // ------------------------------------------------------------
641 |  |
         // ------------------------------------------------------------
642 |  |
643 |  |
         /** Create a default <code>FunctionContext</code>.
644 |  |
          *
645 |  |
          *  @return a default <code>FunctionContext</code>
646 |  |
          */
647 |  |
         protected FunctionContext createFunctionContext()
648 |  |
         {
649 | 3450 |
             return XPathFunctionContext.getInstance();
650 |  |
         }
651 |  |
652 |  |
         /** Create a default <code>NamespaceContext</code>.
653 |  |
          *
654 |  |
          *  @return a default <code>NamespaceContext</code> instance
655 |  |
          */
656 |  |
         protected NamespaceContext createNamespaceContext()
657 |  |
         {
658 | 3450 |
             return new SimpleNamespaceContext();
659 |  |
         }
660 |  |
661 |  |
         /** Create a default <code>VariableContext</code>.
662 |  |
          *
663 |  |
          *  @return a default <code>VariableContext</code> instance
664 |  |
          */
665 |  |
         protected VariableContext createVariableContext()
666 |  |
         {
667 | 3450 |
             return new SimpleVariableContext();
668 |  |
         }
669 |  |
670 |  |
         /** Select all nodes that match this XPath
671 |  |
          *  expression on the given Context object.
672 |  |
          *  If multiple nodes match, multiple nodes
673 |  |
          *  will be returned in document-order, as defined by the XPath
674 |  |
          *  specification. If the expression selects a non-node-set
675 |  |
          *  (i.e. a number, boolean, or string) then a List
676 |  |
          *  containing just that one object is returned.
677 |  |
          *  </p>
678 |  |
          *
679 |  |
          * @param context the Context which gets evaluated
680 |  |
          *
681 |  |
          * @return the node-set of all items selected
682 |  |
          *          by this XPath expression
683 |  |
          * @throws JaxenException if an XPath error occurs during expression evaluation
684 |  |
          *
685 |  |
          */
686 |  |
         protected List selectNodesForContext(Context context) throws JaxenException
687 |  |
         {
688 | 10296 |
             List list = this.xpath.asList( context );
689 | 9930 |
             return list;
690 |  |
691 |  |
         }
692 |  |
693 |  |
694 |  |
         /** Return only the first node that is selected by this XPath
695 |  |
          *  expression.  If multiple nodes match, only one node will be
696 |  |
          *  returned. The selected node will be the first
697 |  |
          *  selected node in document-order, as defined by the XPath
698 |  |
          *  specification. If the XPath expression selects a double,
699 |  |
          *  String, or boolean, then that object is returned.
700 |  |
          *  </p>
701 |  |
          *
702 |  |
          * @param context the Context against which this expression is evaluated
703 |  |
          *
704 |  |
          * @return the first node in document order of all nodes selected
705 |  |
          *          by this XPath expression
706 |  |
          * @throws JaxenException if an XPath error occurs during expression evaluation
707 |  |
          *
708 |  |
          *  @see #selectNodesForContext
709 |  |
          */
710 |  |
         protected Object selectSingleNodeForContext(Context context) throws JaxenException
711 |  |
         {
712 | 36 |
             List results = selectNodesForContext( context );
713 |  |
714 | 36 |
             if ( results.isEmpty() )
715 |  |
             {
716 | 12 |
                 return null;
717 |  |
             }
718 |  |
719 | 24 |
             return results.get( 0 );
720 |  |
         }
721 |  |
722 |  |
     }