All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jaxen.BaseXPath Maven / Gradle / Ivy

/*
 * $Header$
 * $Revision$
 * $Date$
 *
 * ====================================================================
 *
 * Copyright 2000-2002 bob mcwhirter & James Strachan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 
 *   * Neither the name of the Jaxen Project nor the names of its
 *     contributors may be used to endorse or promote products derived 
 *     from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 * This software consists of voluntary contributions made by many 
 * individuals on behalf of the Jaxen Project and was originally 
 * created by bob mcwhirter  and 
 * James Strachan .  For more information on the 
 * Jaxen Project, please see .
 * 
 * $Id$
 */


package org.jaxen;

import java.io.Serializable;
import java.util.List;

import org.jaxen.expr.Expr;
import org.jaxen.expr.XPathExpr;
import org.jaxen.function.BooleanFunction;
import org.jaxen.function.NumberFunction;
import org.jaxen.function.StringFunction;
import org.jaxen.saxpath.SAXPathException;
import org.jaxen.saxpath.XPathReader;
import org.jaxen.saxpath.helpers.XPathReaderFactory;
import org.jaxen.util.SingletonList;

/** Base functionality for all concrete, implementation-specific XPaths.
 *
 *  

* This class provides generic functionality for further-defined * implementation-specific XPaths. *

* *

* If you want to adapt the Jaxen engine to traverse your own * object model, then this is a good base class to derive from. * Typically you only really need to provide your own * {@link org.jaxen.Navigator} implementation. *

* * @see org.jaxen.dom4j.Dom4jXPath XPath for dom4j * @see org.jaxen.jdom.JDOMXPath XPath for JDOM * @see org.jaxen.dom.DOMXPath XPath for W3C DOM * * @author bob mcwhirter * @author James Strachan */ public class BaseXPath implements XPath, Serializable { private static final long serialVersionUID = -1993731281300293168L; /** Original expression text. */ private final String exprText; /** the parsed form of the XPath expression */ private final XPathExpr xpath; /** the support information and function, namespace and variable contexts */ private ContextSupport support; /** the implementation-specific Navigator for retrieving XML nodes **/ private Navigator navigator; /** Construct given an XPath expression string. * * @param xpathExpr the XPath expression * * @throws JaxenException if there is a syntax error while * parsing the expression */ protected BaseXPath(String xpathExpr) throws JaxenException { try { XPathReader reader = XPathReaderFactory.createReader(); JaxenHandler handler = new JaxenHandler(); reader.setXPathHandler( handler ); reader.parse( xpathExpr ); this.xpath = handler.getXPathExpr(); } catch (org.jaxen.saxpath.XPathSyntaxException e) { throw new org.jaxen.XPathSyntaxException( e ); } catch (SAXPathException e) { throw new JaxenException( e ); } this.exprText = xpathExpr; } /** Construct given an XPath expression string. * * @param xpathExpr the XPath expression * * @param navigator the XML navigator to use * * @throws JaxenException if there is a syntax error while * parsing the expression */ public BaseXPath(String xpathExpr, Navigator navigator) throws JaxenException { this( xpathExpr ); this.navigator = navigator; } /** Evaluate this XPath against a given context. * The context of evaluation may be any object type * the navigator recognizes as a node. * The return value is either a String, * Double, Boolean, or List * of nodes. * *

* When using this method, one must be careful to * test the class of the returned object. If the returned * object is a list, then the items in this * list will be the actual Document, * Element, Attribute, etc. objects * as defined by the concrete XML object-model implementation, * directly from the context document. This method does * not return copies of anything, but merely * returns references to objects within the source document. *

* * @param context the node, node-set or Context object for evaluation. * This value can be null. * * @return the result of evaluating the XPath expression * against the supplied context * @throws JaxenException if an XPath error occurs during expression evaluation * @throws ClassCastException if the context is not a node */ public Object evaluate(Object context) throws JaxenException { List answer = selectNodes(context); if ( answer != null && answer.size() == 1 ) { Object first = answer.get(0); if ( first instanceof String || first instanceof Number || first instanceof Boolean ) { return first; } } return answer; } /** * List all the nodes selected by this XPath * expression. If multiple nodes match, multiple nodes * are returned. Nodes are returned * in document-order, as defined by the XPath * specification. If the expression selects a non-node-set * (i.e. a number, boolean, or string) then a List * containing just that one object is returned. * * @param node the node, node-set or Context object for evaluation. * This value can be null. * * @return the node-set of all items selected by this XPath expression * @throws JaxenException if an XPath error occurs during expression evaluation * * @see #selectNodesForContext */ public List selectNodes(Object node) throws JaxenException { Context context = getContext( node ); return selectNodesForContext( context ); } /** * Return the first node selected by this XPath * expression. If multiple nodes match, only one node is * returned. The selected node will be the first * selected node in document-order, as defined by the XPath * specification. * * @param node the node, node-set or Context object for evaluation. * This value can be null. * * @return the node-set of all items selected * by this XPath expression * @throws JaxenException if an XPath error occurs during expression evaluation * * @see #selectNodes */ public Object selectSingleNode(Object node) throws JaxenException { List results = selectNodes( node ); if ( results.isEmpty() ) { return null; } return results.get( 0 ); } /** * Returns the XPath string-value of the argument node. * * @param node the node whose value to take * @return the XPath string value of this node * @throws JaxenException if an XPath error occurs during expression evaluation * @deprecated replaced by {@link #stringValueOf} */ public String valueOf(Object node) throws JaxenException { return stringValueOf( node ); } /** Retrieves the string-value of the result of * evaluating this XPath expression when evaluated * against the specified context. * *

* The string-value of the expression is determined per * the string(..) core function defined * in the XPath specification. This means that an expression * that selects zero nodes will return the empty string, * while an expression that selects one-or-more nodes will * return the string-value of the first node. *

* * @param node the node, node-set or Context object for evaluation. This value can be null. * * @return the string-value of the result of evaluating this expression with the specified context node * @throws JaxenException if an XPath error occurs during expression evaluation */ public String stringValueOf(Object node) throws JaxenException { Context context = getContext( node ); Object result = selectSingleNodeForContext( context ); if ( result == null ) { return ""; } return StringFunction.evaluate( result, context.getNavigator() ); } /** Retrieve a boolean-value interpretation of this XPath * expression when evaluated against a given context. * *

* The boolean-value of the expression is determined per * the boolean(..) function defined * in the XPath specification. This means that an expression * that selects zero nodes will return false, * while an expression that selects one or more nodes will * return true. *

* * @param node the node, node-set or Context object for evaluation. This value can be null. * * @return the boolean-value of the result of evaluating this expression with the specified context node * @throws JaxenException if an XPath error occurs during expression evaluation */ public boolean booleanValueOf(Object node) throws JaxenException { Context context = getContext( node ); List result = selectNodesForContext( context ); if ( result == null ) return false; return BooleanFunction.evaluate( result, context.getNavigator() ).booleanValue(); } /** Retrieve a number-value interpretation of this XPath * expression when evaluated against a given context. * *

* The number-value of the expression is determined per * the number(..) core function as defined * in the XPath specification. This means that if this * expression selects multiple nodes, the number-value * of the first node is returned. *

* * @param node the node, node-set or Context object for evaluation. This value can be null. * * @return a Double indicating the numeric value of * evaluating this expression against the specified context * @throws JaxenException if an XPath error occurs during expression evaluation */ public Number numberValueOf(Object node) throws JaxenException { Context context = getContext( node ); Object result = selectSingleNodeForContext( context ); return NumberFunction.evaluate( result, context.getNavigator() ); } // Helpers /** Add a namespace prefix-to-URI mapping for this XPath * expression. * *

* Namespace prefix-to-URI mappings in an XPath are independent * of those used within any document. Only the mapping explicitly * added to this XPath will be available for resolving the * XPath expression. *

* *

* This is a convenience method for adding mappings to the * default {@link NamespaceContext} in place for this XPath. * If you have installed a custom NamespaceContext * that is not a SimpleNamespaceContext, * then this method will throw a JaxenException. *

* * @param prefix the namespace prefix * @param uri the namespace URI * * @throws JaxenException if the NamespaceContext * used by this XPath is not a SimpleNamespaceContext */ public void addNamespace(String prefix, String uri) throws JaxenException { NamespaceContext nsContext = getNamespaceContext(); if ( nsContext instanceof SimpleNamespaceContext ) { ((SimpleNamespaceContext)nsContext).addNamespace( prefix, uri ); return; } throw new JaxenException("Operation not permitted while using a non-simple namespace context."); } // ------------------------------------------------------------ // ------------------------------------------------------------ // Properties // ------------------------------------------------------------ // ------------------------------------------------------------ /** Set a NamespaceContext for use with this * XPath expression. * *

* A NamespaceContext is responsible for translating * namespace prefixes within the expression into namespace URIs. *

* * @param namespaceContext the NamespaceContext to * install for this expression * * @see NamespaceContext * @see NamespaceContext#translateNamespacePrefixToUri */ public void setNamespaceContext(NamespaceContext namespaceContext) { getContextSupport().setNamespaceContext(namespaceContext); } /** Set a FunctionContext for use with this XPath * expression. * *

* A FunctionContext is responsible for resolving * all function calls used within the expression. *

* * @param functionContext the FunctionContext to * install for this expression * * @see FunctionContext * @see FunctionContext#getFunction */ public void setFunctionContext(FunctionContext functionContext) { getContextSupport().setFunctionContext(functionContext); } /** Set a VariableContext for use with this XPath * expression. * *

* A VariableContext is responsible for resolving * all variables referenced within the expression. *

* * @param variableContext The VariableContext to * install for this expression * * @see VariableContext * @see VariableContext#getVariableValue */ public void setVariableContext(VariableContext variableContext) { getContextSupport().setVariableContext(variableContext); } /** Retrieve the NamespaceContext used by this XPath * expression. * *

* A NamespaceContext is responsible for mapping * prefixes used within the expression to namespace URIs. *

* *

* If this XPath expression has not previously had a NamespaceContext * installed, a new default NamespaceContext will be created, * installed and returned. *

* * @return the NamespaceContext used by this expression * * @see NamespaceContext */ public NamespaceContext getNamespaceContext() { return getContextSupport().getNamespaceContext(); } /** Retrieve the FunctionContext used by this XPath * expression. * *

* A FunctionContext is responsible for resolving * all function calls used within the expression. *

* *

* If this XPath expression has not previously had a FunctionContext * installed, a new default FunctionContext will be created, * installed and returned. *

* * @return the FunctionContext used by this expression * * @see FunctionContext */ public FunctionContext getFunctionContext() { return getContextSupport().getFunctionContext(); } /** Retrieve the VariableContext used by this XPath * expression. * *

* A VariableContext is responsible for resolving * all variables referenced within the expression. *

* *

* If this XPath expression has not previously had a VariableContext * installed, a new default VariableContext will be created, * installed and returned. *

* * @return the VariableContext used by this expression * * @see VariableContext */ public VariableContext getVariableContext() { return getContextSupport().getVariableContext(); } /** Retrieve the root expression of the internal * compiled form of this XPath expression. * *

* Internally, Jaxen maintains a form of Abstract Syntax * Tree (AST) to represent the structure of the XPath expression. * This is normally not required during normal consumer-grade * usage of Jaxen. This method is provided for hard-core users * who wish to manipulate or inspect a tree-based version of * the expression. *

* * @return the root of the AST of this expression */ public Expr getRootExpr() { return xpath.getRootExpr(); } /** Return the original expression text. * * @return the normalized XPath expression string */ public String toString() { return this.exprText; } /** Returns a string representation of the parse tree. * * @return a string representation of the parse tree. */ public String debug() { return this.xpath.toString(); } // ------------------------------------------------------------ // ------------------------------------------------------------ // Implementation methods // ------------------------------------------------------------ // ------------------------------------------------------------ /** Create a {@link Context} wrapper for the provided * implementation-specific object. * * @param node the implementation-specific object * to be used as the context * * @return a Context wrapper around the object */ protected Context getContext(Object node) { if ( node instanceof Context ) { return (Context) node; } Context fullContext = new Context( getContextSupport() ); if ( node instanceof List ) { fullContext.setNodeSet( (List) node ); } else { List list = new SingletonList(node); fullContext.setNodeSet( list ); } return fullContext; } /** Retrieve the {@link ContextSupport} aggregation of * NamespaceContext, FunctionContext, * VariableContext, and {@link Navigator}. * * @return aggregate ContextSupport for this * XPath expression */ protected ContextSupport getContextSupport() { if ( support == null ) { support = new ContextSupport( createNamespaceContext(), createFunctionContext(), createVariableContext(), getNavigator() ); } return support; } /** Retrieve the XML object-model-specific {@link Navigator} * for us in evaluating this XPath expression. * * @return the implementation-specific Navigator */ public Navigator getNavigator() { return navigator; } // ------------------------------------------------------------ // ------------------------------------------------------------ // Factory methods for default contexts // ------------------------------------------------------------ // ------------------------------------------------------------ /** Create a default FunctionContext. * * @return a default FunctionContext */ protected FunctionContext createFunctionContext() { return XPathFunctionContext.getInstance(); } /** Create a default NamespaceContext. * * @return a default NamespaceContext instance */ protected NamespaceContext createNamespaceContext() { return new SimpleNamespaceContext(); } /** Create a default VariableContext. * * @return a default VariableContext instance */ protected VariableContext createVariableContext() { return new SimpleVariableContext(); } /** Select all nodes that match this XPath * expression on the given Context object. * If multiple nodes match, multiple nodes * will be returned in document-order, as defined by the XPath * specification. If the expression selects a non-node-set * (i.e. a number, boolean, or string) then a List * containing just that one object is returned. * * @param context the Context which gets evaluated * * @return the node-set of all items selected * by this XPath expression * @throws JaxenException if an XPath error occurs during expression evaluation * */ protected List selectNodesForContext(Context context) throws JaxenException { List list = this.xpath.asList( context ); return list; } /** Return only the first node that is selected by this XPath * expression. If multiple nodes match, only one node will be * returned. The selected node will be the first * selected node in document-order, as defined by the XPath * specification. If the XPath expression selects a double, * String, or boolean, then that object is returned. * * @param context the Context against which this expression is evaluated * * @return the first node in document order of all nodes selected * by this XPath expression * @throws JaxenException if an XPath error occurs during expression evaluation * * @see #selectNodesForContext */ protected Object selectSingleNodeForContext(Context context) throws JaxenException { List results = selectNodesForContext(context); if ( results.isEmpty() ) { return null; } return results.get( 0 ); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy