- /*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Xalan" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
- * ITS 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 Apache Software Foundation and was
- * originally based on software copyright (c) 1999, Lotus
- * Development Corporation., http://www.lotus.com. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
- package org.apache.xpath;
-
- import javax.xml.transform.TransformerException;
-
- import org.w3c.dom.Node;
- import org.w3c.dom.Document;
- import org.w3c.dom.traversal.NodeIterator;
- import org.w3c.dom.NodeList;
-
- import org.apache.xpath.XPathContext;
- import org.apache.xpath.XPath;
- import org.apache.xpath.compiler.XPathParser;
- import org.apache.xpath.XPathContext;
- import org.apache.xml.utils.PrefixResolverDefault;
- import org.apache.xml.utils.PrefixResolver;
- import org.apache.xpath.objects.XObject;
- import org.apache.xml.dtm.DTM;
- import org.apache.xml.dtm.ref.DTMNodeIterator;
- import org.apache.xml.dtm.ref.DTMNodeList;
- import org.apache.xml.dtm.ref.DTMManagerDefault;
-
- /**
- * The methods in this class are convenience methods into the
- * low-level XPath API.
- *
- * These functions tend to be a little slow, since a number of objects must be
- * created for each evaluation. A faster way is to precompile the
- * XPaths using the low-level API, and then just use the XPaths
- * over and over.
- *
- * This is an alternative for the old XPathAPI class, which provided
- * static methods for the purpose but had the drawback of
- * instantiating a new XPathContext (and thus building a new DTMManager,
- * and new DTMs) each time it was called. XPathAPIObject instead retains
- * its context as long as the object persists, reusing the DTMs. This
- * does have a downside: if you've changed your source document, you should
- * obtain a new XPathAPIObject to continue searching it, since trying to use
- * the old DTMs will probably yield bad results or malfunction outright... and
- * the cached DTMs may consume memory until this object and its context are
- * returned to the heap. Essentially, it's the caller's responsibility to
- * decide when to discard the cache.
- *
- * @see <a href="http://www.w3.org/TR/xpath">XPath Specification</a>
- * */
- public class CachedXPathAPI
- {
- /** XPathContext, and thus the document model system (DTMs), persists through multiple
- calls to this object. This is set in the constructor.
- */
- protected XPathContext xpathSupport;
-
- /** Default constructor. Establishes its own XPathContext, and hence
- * its own DTMManager. Good choice for simple uses.
- * */
- public CachedXPathAPI()
- {
- xpathSupport = new XPathContext();
- }
-
- /** This constructor shares its XPathContext with a pre-existing
- * CachedXPathAPI. That allows sharing document models (DTMs) and
- * previously established location state.
- *
- * Note that the original CachedXPathAPI and the new one should not
- * be operated concurrently; we do not support multithreaded access
- * to a single DTM at this time.
- *
- * %REVIEW% Should this instead do a clone-and-reset on the XPathSupport object?
- * */
- public CachedXPathAPI(CachedXPathAPI priorXPathAPI)
- {
- xpathSupport = priorXPathAPI.xpathSupport;
- }
-
-
- /** Returns the XPathSupport object used in this CachedXPathAPI
- *
- * %REVIEW% I'm somewhat concerned about the loss of encapsulation
- * this causes, but the xml-security folks say they need it.
- * */
- public XPathContext getXPathContext()
- {
- return this.xpathSupport;
- }
-
-
- /**
- * Use an XPath string to select a single node. XPath namespace
- * prefixes are resolved from the context node, which may not
- * be what you want (see the next method).
- *
- * @param contextNode The node to start searching from.
- * @param str A valid XPath string.
- * @return The first node found that matches the XPath, or null.
- *
- * @throws TransformerException
- */
- public Node selectSingleNode(Node contextNode, String str)
- throws TransformerException
- {
- return selectSingleNode(contextNode, str, contextNode);
- }
-
- /**
- * Use an XPath string to select a single node.
- * XPath namespace prefixes are resolved from the namespaceNode.
- *
- * @param contextNode The node to start searching from.
- * @param str A valid XPath string.
- * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
- * @return The first node found that matches the XPath, or null.
- *
- * @throws TransformerException
- */
- public Node selectSingleNode(
- Node contextNode, String str, Node namespaceNode)
- throws TransformerException
- {
-
- // Have the XObject return its result as a NodeSetDTM.
- NodeIterator nl = selectNodeIterator(contextNode, str, namespaceNode);
-
- // Return the first node, or null
- return nl.nextNode();
- }
-
- /**
- * Use an XPath string to select a nodelist.
- * XPath namespace prefixes are resolved from the contextNode.
- *
- * @param contextNode The node to start searching from.
- * @param str A valid XPath string.
- * @return A NodeIterator, should never be null.
- *
- * @throws TransformerException
- */
- public NodeIterator selectNodeIterator(Node contextNode, String str)
- throws TransformerException
- {
- return selectNodeIterator(contextNode, str, contextNode);
- }
-
- /**
- * Use an XPath string to select a nodelist.
- * XPath namespace prefixes are resolved from the namespaceNode.
- *
- * @param contextNode The node to start searching from.
- * @param str A valid XPath string.
- * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
- * @return A NodeIterator, should never be null.
- *
- * @throws TransformerException
- */
- public NodeIterator selectNodeIterator(
- Node contextNode, String str, Node namespaceNode)
- throws TransformerException
- {
-
- // Execute the XPath, and have it return the result
- XObject list = eval(contextNode, str, namespaceNode);
-
- // Have the XObject return its result as a NodeSetDTM.
- return list.nodeset();
- }
-
- /**
- * Use an XPath string to select a nodelist.
- * XPath namespace prefixes are resolved from the contextNode.
- *
- * @param contextNode The node to start searching from.
- * @param str A valid XPath string.
- * @return A NodeIterator, should never be null.
- *
- * @throws TransformerException
- */
- public NodeList selectNodeList(Node contextNode, String str)
- throws TransformerException
- {
- return selectNodeList(contextNode, str, contextNode);
- }
-
- /**
- * Use an XPath string to select a nodelist.
- * XPath namespace prefixes are resolved from the namespaceNode.
- *
- * @param contextNode The node to start searching from.
- * @param str A valid XPath string.
- * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
- * @return A NodeIterator, should never be null.
- *
- * @throws TransformerException
- */
- public NodeList selectNodeList(
- Node contextNode, String str, Node namespaceNode)
- throws TransformerException
- {
-
- // Execute the XPath, and have it return the result
- XObject list = eval(contextNode, str, namespaceNode);
-
- // Return a NodeList.
- return list.nodelist();
- }
-
- /**
- * Evaluate XPath string to an XObject. Using this method,
- * XPath namespace prefixes will be resolved from the namespaceNode.
- * @param contextNode The node to start searching from.
- * @param str A valid XPath string.
- * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
- * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
- * @see org.apache.xpath.objects.XObject
- * @see org.apache.xpath.objects.XNull
- * @see org.apache.xpath.objects.XBoolean
- * @see org.apache.xpath.objects.XNumber
- * @see org.apache.xpath.objects.XString
- * @see org.apache.xpath.objects.XRTreeFrag
- *
- * @throws TransformerException
- */
- public XObject eval(Node contextNode, String str)
- throws TransformerException
- {
- return eval(contextNode, str, contextNode);
- }
-
- /**
- * Evaluate XPath string to an XObject.
- * XPath namespace prefixes are resolved from the namespaceNode.
- * The implementation of this is a little slow, since it creates
- * a number of objects each time it is called. This could be optimized
- * to keep the same objects around, but then thread-safety issues would arise.
- *
- * @param contextNode The node to start searching from.
- * @param str A valid XPath string.
- * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
- * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
- * @see org.apache.xpath.objects.XObject
- * @see org.apache.xpath.objects.XNull
- * @see org.apache.xpath.objects.XBoolean
- * @see org.apache.xpath.objects.XNumber
- * @see org.apache.xpath.objects.XString
- * @see org.apache.xpath.objects.XRTreeFrag
- *
- * @throws TransformerException
- */
- public XObject eval(Node contextNode, String str, Node namespaceNode)
- throws TransformerException
- {
-
- // Since we don't have a XML Parser involved here, install some default support
- // for things like namespaces, etc.
- // (Changed from: XPathContext xpathSupport = new XPathContext();
- // because XPathContext is weak in a number of areas... perhaps
- // XPathContext should be done away with.)
-
- // Create an object to resolve namespace prefixes.
- // XPath namespaces are resolved from the input context node's document element
- // if it is a root node, or else the current context node (for lack of a better
- // resolution space, given the simplicity of this sample code).
- PrefixResolverDefault prefixResolver = new PrefixResolverDefault(
- (namespaceNode.getNodeType() == Node.DOCUMENT_NODE)
- ? ((Document) namespaceNode).getDocumentElement() : namespaceNode);
-
- // Create the XPath object.
- XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
-
- // Execute the XPath, and have it return the result
- // return xpath.execute(xpathSupport, contextNode, prefixResolver);
- int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
-
- return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
- }
-
- /**
- * Evaluate XPath string to an XObject.
- * XPath namespace prefixes are resolved from the namespaceNode.
- * The implementation of this is a little slow, since it creates
- * a number of objects each time it is called. This could be optimized
- * to keep the same objects around, but then thread-safety issues would arise.
- *
- * @param contextNode The node to start searching from.
- * @param str A valid XPath string.
- * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
- * @param prefixResolver Will be called if the parser encounters namespace
- * prefixes, to resolve the prefixes to URLs.
- * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
- * @see org.apache.xpath.objects.XObject
- * @see org.apache.xpath.objects.XNull
- * @see org.apache.xpath.objects.XBoolean
- * @see org.apache.xpath.objects.XNumber
- * @see org.apache.xpath.objects.XString
- * @see org.apache.xpath.objects.XRTreeFrag
- *
- * @throws TransformerException
- */
- public XObject eval(
- Node contextNode, String str, PrefixResolver prefixResolver)
- throws TransformerException
- {
-
- // Since we don't have a XML Parser involved here, install some default support
- // for things like namespaces, etc.
- // (Changed from: XPathContext xpathSupport = new XPathContext();
- // because XPathContext is weak in a number of areas... perhaps
- // XPathContext should be done away with.)
- // Create the XPath object.
- XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
-
- // Execute the XPath, and have it return the result
- XPathContext xpathSupport = new XPathContext();
- int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
-
- return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
- }
- }