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.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 */ @SuppressWarnings({"rawtypes" }) 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 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 (Exception 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 - 2025 Weber Informatics LLC | Privacy Policy