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