Coverage Report - org.jaxen.BaseXPath
 
Classes in this File Line Coverage Branch Coverage Complexity
BaseXPath
99%
140/142
100%
20/20
1.815
 
 1  
 /*
 2  
  * $Header$
 3  
  * $Revision: 1321 $
 4  
  * $Date: 2008-04-26 17:30:06 -0700 (Sat, 26 Apr 2008) $
 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 1321 2008-04-27 00:30:06Z elharo $
 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  
 
 88  
     private static final long serialVersionUID = -1993731281300293168L;
 89  
 
 90  
     /** Original expression text. */
 91  
     private final String exprText;
 92  
 
 93  
     /** the parsed form of the XPath expression */
 94  
     private final XPathExpr xpath;
 95  
     
 96  
     /** the support information and function, namespace and variable contexts */
 97  
     private ContextSupport support;
 98  
 
 99  
     /** the implementation-specific Navigator for retrieving XML nodes **/
 100  
     private Navigator navigator;
 101  
     
 102  
     /** Construct given an XPath expression string. 
 103  
      *
 104  
      *  @param xpathExpr the XPath expression
 105  
      *
 106  
      *  @throws JaxenException if there is a syntax error while
 107  3035
      *          parsing the expression
 108  
      */
 109  
     protected BaseXPath(String xpathExpr) throws JaxenException
 110  15231
     {
 111  3034
         try
 112  3034
         {
 113  15230
             XPathReader reader = XPathReaderFactory.createReader();
 114  15186
             JaxenHandler handler = new JaxenHandler();
 115  12192
             reader.setXPathHandler( handler );
 116  12232
             reader.parse( xpathExpr );
 117  12032
             this.xpath = handler.getXPathExpr();
 118  40
         }
 119  160
         catch (org.jaxen.saxpath.XPathSyntaxException e)
 120  1
         {
 121  160
             throw new org.jaxen.XPathSyntaxException( e );
 122  1
         }
 123  2998
         catch (SAXPathException e)
 124  
         {
 125  2998
             throw new JaxenException( e );
 126  15026
         }
 127  
 
 128  12032
         this.exprText = xpathExpr;
 129  12032
     }
 130  
 
 131  
     /** Construct given an XPath expression string.
 132  
      *
 133  
      *  @param xpathExpr the XPath expression
 134  
      *
 135  
      *  @param navigator the XML navigator to use
 136  
      *
 137  
      *  @throws JaxenException if there is a syntax error while
 138  
      *          parsing the expression
 139  3035
      */
 140  2994
     public BaseXPath(String xpathExpr, Navigator navigator) throws JaxenException
 141  2994
     {
 142  12196
         this( xpathExpr );
 143  12032
         this.navigator = navigator;
 144  12032
     }
 145  
 
 146  
     /** Evaluate this XPath against a given context.
 147  
      *  The context of evaluation may be any object type
 148  
      *  the navigator recognizes as a node.
 149  
      *  The return value is either a <code>String</code>,
 150  
      *  <code>Double</code>, <code>Boolean</code>, or <code>List</code>
 151  
      *  of nodes.
 152  
      *
 153  
      *  <p>
 154  
      *  When using this method, one must be careful to
 155  
      *  test the class of the returned object.  If the returned 
 156  
      *  object is a list, then the items in this 
 157  
      *  list will be the actual <code>Document</code>,
 158  
      *  <code>Element</code>, <code>Attribute</code>, etc. objects
 159  
      *  as defined by the concrete XML object-model implementation,
 160  
      *  directly from the context document.  This method <strong>does
 161  
      *  not return <em>copies</em> of anything</strong>, but merely 
 162  
      *  returns references to objects within the source document.
 163  
      *  </p>
 164  
      *  
 165  
      * @param context the node, node-set or Context object for evaluation. 
 166  
      *      This value can be null.
 167  
      *
 168  
      * @return the result of evaluating the XPath expression
 169  
      *          against the supplied context
 170  
      * @throws JaxenException if an XPath error occurs during expression evaluation
 171  
      * @throws ClassCastException if the context is not a node
 172  832
      */
 173  
     public Object evaluate(Object context) throws JaxenException
 174  822
     {
 175  3376
         List answer = selectNodes(context);
 176  
 
 177  3336
         if ( answer != null
 178  819
              &&
 179  
              answer.size() == 1 )
 180  819
         {
 181  3324
             Object first = answer.get(0);
 182  
 
 183  3324
             if ( first instanceof String
 184  
                  ||
 185  
                  first instanceof Number
 186  685
                  ||
 187  
                  first instanceof Boolean ) 
 188  
             {
 189  2925
                 return first;
 190  
             }
 191  
         }
 192  548
         return answer;
 193  
     }
 194  
     
 195  
     /** Select all nodes that are selected by this XPath
 196  
      *  expression. If multiple nodes match, multiple nodes
 197  
      *  will be returned. Nodes will be returned
 198  
      *  in document-order, as defined by the XPath
 199  
      *  specification. If the expression selects a non-node-set
 200  
      *  (i.e. a number, boolean, or string) then a List
 201  
      *  containing just that one object is returned.
 202  
      *  </p>
 203  
      *
 204  
      * @param node the node, node-set or Context object for evaluation. 
 205  
      *     This value can be null.
 206  
      *
 207  
      * @return the node-set of all items selected
 208  
      *          by this XPath expression
 209  
      * @throws JaxenException if an XPath error occurs during expression evaluation
 210  
      *
 211  
      * @see #selectNodesForContext
 212  1790
      */
 213  1790
     public List selectNodes(Object node) throws JaxenException
 214  
     {
 215  7208
         Context context = getContext( node );
 216  7208
         return selectNodesForContext( context );
 217  
     }
 218  
 
 219  
     /** Select only the first node selected by this XPath
 220  
      *  expression.  If multiple nodes match, only one node will be
 221  
      *  returned. The selected node will be the first
 222  
      *  selected node in document-order, as defined by the XPath
 223  
      *  specification.
 224  
      *  </p>
 225  
      *
 226  
      * @param node the node, node-set or Context object for evaluation. 
 227  
      *     This value can be null.
 228  
      *
 229  
      * @return the node-set of all items selected
 230  
      *          by this XPath expression
 231  
      * @throws JaxenException if an XPath error occurs during expression evaluation
 232  
      *
 233  
      * @see #selectNodes
 234  4
      */
 235  
     public Object selectSingleNode(Object node) throws JaxenException
 236  4
     {
 237  16
         List results = selectNodes( node );
 238  2
 
 239  16
         if ( results.isEmpty() )
 240  
         {
 241  10
             return null;
 242  
         }
 243  
 
 244  8
         return results.get( 0 );
 245  
     }
 246  
 
 247  
     /**
 248  
      * Returns the XPath string-value of the argument node.
 249  
      * 
 250  
      * @param node the node whose value to take
 251  
      * @return the XPath string value of this node
 252  
      * @throws JaxenException if an XPath error occurs during expression evaluation
 253  
      * @deprecated replaced by {@link #stringValueOf}
 254  0
      */
 255  
     public String valueOf(Object node) throws JaxenException
 256  
     {
 257  0
         return stringValueOf( node );
 258  
     }
 259  
 
 260  
     /** Retrieves the string-value of the result of
 261  
      *  evaluating this XPath expression when evaluated 
 262  
      *  against the specified context.
 263  
      *
 264  
      *  <p>
 265  
      *  The string-value of the expression is determined per
 266  
      *  the <code>string(..)</code> core function defined
 267  
      *  in the XPath specification.  This means that an expression
 268  
      *  that selects zero nodes will return the empty string,
 269  
      *  while an expression that selects one-or-more nodes will
 270  
      *  return the string-value of the first node.
 271  
      *  </p>
 272  
      *
 273  
      * @param node the node, node-set or Context object for evaluation. This value can be null.
 274  
      *
 275  
      * @return the string-value of the result of evaluating this expression with the specified context node
 276  
      * @throws JaxenException if an XPath error occurs during expression evaluation
 277  3
      */
 278  
     public String stringValueOf(Object node) throws JaxenException
 279  3
     {
 280  12
         Context context = getContext( node );
 281  3
         
 282  12
         Object result = selectSingleNodeForContext( context );
 283  1
 
 284  12
         if ( result == null )
 285  
         {
 286  6
             return "";
 287  
         }
 288  
 
 289  8
         return StringFunction.evaluate( result,
 290  
                                         context.getNavigator() );
 291  
     }
 292  
 
 293  
     /** Retrieve a boolean-value interpretation of this XPath
 294  
      *  expression when evaluated against a given context.
 295  
      *
 296  
      *  <p>
 297  
      *  The boolean-value of the expression is determined per
 298  
      *  the <code>boolean(..)</code> function defined
 299  
      *  in the XPath specification.  This means that an expression
 300  
      *  that selects zero nodes will return <code>false</code>,
 301  
      *  while an expression that selects one or more nodes will
 302  
      *  return <code>true</code>.
 303  
      *  </p>
 304  
      *
 305  
      * @param node the node, node-set or Context object for evaluation. This value can be null.
 306  
      *
 307  
      * @return the boolean-value of the result of evaluating this expression with the specified context node
 308  
      * @throws JaxenException if an XPath error occurs during expression evaluation
 309  4
      */
 310  4
     public boolean booleanValueOf(Object node) throws JaxenException
 311  4
     {
 312  20
         Context context = getContext( node );
 313  16
         List result = selectNodesForContext( context );
 314  16
         if ( result == null ) return false;
 315  16
         return BooleanFunction.evaluate( result, context.getNavigator() ).booleanValue();
 316  
     }
 317  
 
 318  
     /** Retrieve a number-value interpretation of this XPath
 319  
      *  expression when evaluated against a given context.
 320  
      *
 321  
      *  <p>
 322  
      *  The number-value of the expression is determined per
 323  
      *  the <code>number(..)</code> core function as defined
 324  
      *  in the XPath specification. This means that if this
 325  
      *  expression selects multiple nodes, the number-value
 326  
      *  of the first node is returned.
 327  
      *  </p>
 328  
      *
 329  
      * @param node the node, node-set or Context object for evaluation. This value can be null.
 330  
      *
 331  
      * @return a <code>Double</code> indicating the numeric value of
 332  
      *      evaluating this expression against the specified context
 333  
      * @throws JaxenException if an XPath error occurs during expression evaluation
 334  3
      */
 335  3
     public Number numberValueOf(Object node) throws JaxenException
 336  3
     {
 337  12
         Context context = getContext( node );
 338  12
         Object result = selectSingleNodeForContext( context );
 339  12
         return NumberFunction.evaluate( result,
 340  
                                         context.getNavigator() );
 341  
     }
 342  
 
 343  
     // Helpers
 344  
 
 345  
     /** Add a namespace prefix-to-URI mapping for this XPath
 346  
      *  expression.
 347  
      *
 348  
      *  <p>
 349  
      *  Namespace prefix-to-URI mappings in an XPath are independent
 350  
      *  of those used within any document.  Only the mapping explicitly
 351  
      *  added to this XPath will be available for resolving the
 352  
      *  XPath expression.
 353  
      *  </p>
 354  
      *
 355  
      *  <p>
 356  
      *  This is a convenience method for adding mappings to the
 357  
      *  default {@link NamespaceContext} in place for this XPath.
 358  
      *  If you have installed a custom <code>NamespaceContext</code>
 359  
      *  that is not a <code>SimpleNamespaceContext</code>,
 360  
      *  then this method will throw a <code>JaxenException</code>.
 361  
      *  </p>
 362  
      *
 363  
      *  @param prefix the namespace prefix
 364  
      *  @param uri the namespace URI
 365  
      *
 366  
      *  @throws JaxenException if the <code>NamespaceContext</code>
 367  
      *          used by this XPath is not a <code>SimpleNamespaceContext</code>
 368  
      */
 369  4
     public void addNamespace(String prefix,
 370  4
                              String uri) throws JaxenException
 371  
     {
 372  19
         NamespaceContext nsContext = getNamespaceContext();
 373  16
         if ( nsContext instanceof SimpleNamespaceContext )
 374  3
         {
 375  12
             ((SimpleNamespaceContext)nsContext).addNamespace( prefix,
 376  
                                                               uri );
 377  13
             return;
 378  
         }
 379  
 
 380  4
         throw new JaxenException("Operation not permitted while using a non-simple namespace context.");
 381  
     }
 382  
 
 383  
 
 384  
     // ------------------------------------------------------------
 385  
     // ------------------------------------------------------------
 386  
     //     Properties
 387  
     // ------------------------------------------------------------
 388  
     // ------------------------------------------------------------
 389  
 
 390  
     
 391  
     /** Set a <code>NamespaceContext</code> for use with this
 392  
      *  XPath expression.
 393  
      *
 394  
      *  <p>
 395  
      *  A <code>NamespaceContext</code> is responsible for translating
 396  
      *  namespace prefixes within the expression into namespace URIs.
 397  
      *  </p>
 398  
      *
 399  
      *  @param namespaceContext the <code>NamespaceContext</code> to
 400  
      *         install for this expression
 401  
      *
 402  
      *  @see NamespaceContext
 403  
      *  @see NamespaceContext#translateNamespacePrefixToUri
 404  33
      */
 405  33
     public void setNamespaceContext(NamespaceContext namespaceContext)
 406  
     {
 407  132
         getContextSupport().setNamespaceContext(namespaceContext);
 408  132
     }
 409  
 
 410  
     /** Set a <code>FunctionContext</code> for use with this XPath
 411  
      *  expression.
 412  
      *
 413  
      *  <p>
 414  
      *  A <code>FunctionContext</code> is responsible for resolving
 415  
      *  all function calls used within the expression.
 416  
      *  </p>
 417  
      *
 418  
      *  @param functionContext the <code>FunctionContext</code> to
 419  
      *         install for this expression
 420  
      *
 421  
      *  @see FunctionContext
 422  
      *  @see FunctionContext#getFunction
 423  29
      */
 424  29
     public void setFunctionContext(FunctionContext functionContext)
 425  
     {
 426  116
         getContextSupport().setFunctionContext(functionContext);
 427  116
     }
 428  
 
 429  
     /** Set a <code>VariableContext</code> for use with this XPath
 430  
      *  expression.
 431  
      *
 432  
      *  <p>
 433  
      *  A <code>VariableContext</code> is responsible for resolving
 434  
      *  all variables referenced within the expression.
 435  
      *  </p>
 436  
      *
 437  
      *  @param variableContext The <code>VariableContext</code> to
 438  
      *         install for this expression
 439  
      *
 440  
      *  @see VariableContext
 441  
      *  @see VariableContext#getVariableValue
 442  28
      */
 443  28
     public void setVariableContext(VariableContext variableContext)
 444  
     {
 445  112
         getContextSupport().setVariableContext(variableContext);
 446  112
     }
 447  
 
 448  
     /** Retrieve the <code>NamespaceContext</code> used by this XPath
 449  
      *  expression.
 450  
      *
 451  
      *  <p>
 452  
      *  A <code>NamespaceContext</code> is responsible for mapping
 453  
      *  prefixes used within the expression to namespace URIs.
 454  
      *  </p>
 455  
      *
 456  
      *  <p>
 457  
      *  If this XPath expression has not previously had a <code>NamespaceContext</code>
 458  
      *  installed, a new default <code>NamespaceContext</code> will be created,
 459  
      *  installed and returned.
 460  
      *  </p>
 461  
      *
 462  
      *  @return the <code>NamespaceContext</code> used by this expression
 463  
      *
 464  
      *  @see NamespaceContext
 465  5
      */
 466  
     public NamespaceContext getNamespaceContext()
 467  
     {
 468  20
         return getContextSupport().getNamespaceContext();
 469  
     }
 470  
 
 471  
     /** Retrieve the <code>FunctionContext</code> used by this XPath
 472  
      *  expression.
 473  
      *
 474  
      *  <p>
 475  
      *  A <code>FunctionContext</code> is responsible for resolving
 476  
      *  all function calls used within the expression.
 477  
      *  </p>
 478  
      *
 479  
      *  <p>
 480  
      *  If this XPath expression has not previously had a <code>FunctionContext</code>
 481  
      *  installed, a new default <code>FunctionContext</code> will be created,
 482  
      *  installed and returned.
 483  
      *  </p>
 484  
      *
 485  
      *  @return the <code>FunctionContext</code> used by this expression
 486  
      *
 487  
      *  @see FunctionContext
 488  2
      */
 489  
     public FunctionContext getFunctionContext()
 490  
     {
 491  8
         return getContextSupport().getFunctionContext();
 492  
     }
 493  
 
 494  
     /** Retrieve the <code>VariableContext</code> used by this XPath
 495  
      *  expression.
 496  
      *
 497  
      *  <p>
 498  
      *  A <code>VariableContext</code> is responsible for resolving
 499  
      *  all variables referenced within the expression.
 500  
      *  </p>
 501  
      *
 502  
      *  <p>
 503  
      *  If this XPath expression has not previously had a <code>VariableContext</code>
 504  
      *  installed, a new default <code>VariableContext</code> will be created,
 505  
      *  installed and returned.
 506  
      *  </p>
 507  
      *  
 508  
      *  @return the <code>VariableContext</code> used by this expression
 509  
      *
 510  
      *  @see VariableContext
 511  1
      */
 512  
     public VariableContext getVariableContext()
 513  
     {
 514  4
         return getContextSupport().getVariableContext();
 515  
     }
 516  
     
 517  
     
 518  
     /** Retrieve the root expression of the internal
 519  
      *  compiled form of this XPath expression.
 520  
      *
 521  
      *  <p>
 522  
      *  Internally, Jaxen maintains a form of Abstract Syntax
 523  
      *  Tree (AST) to represent the structure of the XPath expression.
 524  
      *  This is normally not required during normal consumer-grade
 525  
      *  usage of Jaxen.  This method is provided for hard-core users
 526  
      *  who wish to manipulate or inspect a tree-based version of
 527  
      *  the expression.
 528  
      *  </p>
 529  
      *
 530  
      *  @return the root of the AST of this expression
 531  3527
      */
 532  
     public Expr getRootExpr() 
 533  
     {
 534  14108
         return xpath.getRootExpr();
 535  
     }
 536  
     
 537  
     /** Return the original expression text.
 538  
      *
 539  
      *  @return the normalized XPath expression string
 540  256
      */
 541  
     public String toString()
 542  
     {
 543  1032
         return this.exprText;
 544  
     }
 545  
 
 546  
     /** Returns a string representation of the parse tree.
 547  
      *
 548  
      *  @return a string representation of the parse tree.
 549  1
      */
 550  
     public String debug()
 551  
     {
 552  4
         return this.xpath.toString();
 553  
     }
 554  
     
 555  
     // ------------------------------------------------------------
 556  
     // ------------------------------------------------------------
 557  
     //     Implementation methods
 558  
     // ------------------------------------------------------------
 559  
     // ------------------------------------------------------------
 560  
 
 561  
     
 562  
     /** Create a {@link Context} wrapper for the provided
 563  
      *  implementation-specific object.
 564  
      *
 565  
      *  @param node the implementation-specific object 
 566  
      *         to be used as the context
 567  
      *
 568  
      *  @return a <code>Context</code> wrapper around the object
 569  1800
      */
 570  
     protected Context getContext(Object node)
 571  1224
     {
 572  7248
         if ( node instanceof Context )
 573  
         {
 574  5472
             return (Context) node;
 575  
         }
 576  576
 
 577  2352
         Context fullContext = new Context( getContextSupport() );
 578  1
 
 579  2352
         if ( node instanceof List )
 580  
         {
 581  4
             fullContext.setNodeSet( (List) node );
 582  575
         }
 583  575
         else
 584  
         {
 585  2348
             List list = new SingletonList(node);
 586  2924
             fullContext.setNodeSet( list );
 587  
         }
 588  
 
 589  2352
         return fullContext;
 590  
     }
 591  
 
 592  
     /** Retrieve the {@link ContextSupport} aggregation of
 593  
      *  <code>NamespaceContext</code>, <code>FunctionContext</code>,
 594  
      *  <code>VariableContext</code>, and {@link Navigator}.
 595  
      *
 596  
      *  @return aggregate <code>ContextSupport</code> for this
 597  
      *          XPath expression
 598  674
      */
 599  
     protected ContextSupport getContextSupport()
 600  607
     {
 601  2744
         if ( support == null )
 602  
         {
 603  2476
             support = new ContextSupport( 
 604  
                 createNamespaceContext(),
 605  
                 createFunctionContext(),
 606  
                 createVariableContext(),
 607  
                 getNavigator() 
 608  674
             );
 609  
         }
 610  
 
 611  2744
         return support;
 612  
     }
 613  
 
 614  
     /** Retrieve the XML object-model-specific {@link Navigator} 
 615  
      *  for us in evaluating this XPath expression.
 616  
      *
 617  
      *  @return the implementation-specific <code>Navigator</code>
 618  608
      */
 619  
     public Navigator getNavigator()
 620  
     {
 621  2480
         return navigator;
 622  
     }
 623  
     
 624  
     
 625  
 
 626  
     // ------------------------------------------------------------
 627  
     // ------------------------------------------------------------
 628  
     //     Factory methods for default contexts
 629  
     // ------------------------------------------------------------
 630  
     // ------------------------------------------------------------
 631  
 
 632  
     /** Create a default <code>FunctionContext</code>.
 633  
      *
 634  
      *  @return a default <code>FunctionContext</code>
 635  607
      */
 636  
     protected FunctionContext createFunctionContext()
 637  
     {
 638  2476
         return XPathFunctionContext.getInstance();
 639  
     }
 640  
     
 641  
     /** Create a default <code>NamespaceContext</code>.
 642  
      *
 643  
      *  @return a default <code>NamespaceContext</code> instance
 644  607
      */
 645  
     protected NamespaceContext createNamespaceContext()
 646  
     {
 647  2476
         return new SimpleNamespaceContext();
 648  
     }
 649  
     
 650  
     /** Create a default <code>VariableContext</code>.
 651  
      *
 652  
      *  @return a default <code>VariableContext</code> instance
 653  607
      */
 654  
     protected VariableContext createVariableContext()
 655  
     {
 656  2476
         return new SimpleVariableContext();
 657  
     }
 658  
     
 659  
     /** Select all nodes that match this XPath
 660  
      *  expression on the given Context object. 
 661  
      *  If multiple nodes match, multiple nodes
 662  
      *  will be returned in document-order, as defined by the XPath
 663  
      *  specification. If the expression selects a non-node-set
 664  
      *  (i.e. a number, boolean, or string) then a List
 665  
      *  containing just that one object is returned.
 666  
      *  </p>
 667  
      *
 668  
      * @param context the Context which gets evaluated
 669  
      *
 670  
      * @return the node-set of all items selected
 671  
      *          by this XPath expression