1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 /*
6  * Copyright 2002-2005 The Apache Software Foundation.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 /*
21  * $Id: XPathEvaluatorImpl.java,v 1.2.4.1 2005/09/10 04:04:07 jeffsuttor Exp $
22  */
23 
24 package com.sun.org.apache.xpath.internal.domapi;
25 
26 import javax.xml.transform.TransformerException;
27 
28 import com.sun.org.apache.xml.internal.utils.PrefixResolver;
29 import com.sun.org.apache.xpath.internal.XPath;
30 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
31 import com.sun.org.apache.xpath.internal.res.XPATHMessages;
32 import org.w3c.dom.DOMException;
33 import org.w3c.dom.Document;
34 import org.w3c.dom.Node;
35 import org.w3c.dom.xpath.XPathEvaluator;
36 import org.w3c.dom.xpath.XPathException;
37 import org.w3c.dom.xpath.XPathExpression;
38 import org.w3c.dom.xpath.XPathNSResolver;
39 
40 /**
41  *
42  * The class provides an implementation of XPathEvaluator according
43  * to the DOM L3 XPath Specification, Working Group Note 26 February 2004.
44  *
45  * <p>See also the <a href='http://www.w3.org/TR/2004/NOTE-DOM-Level-3-XPath-20040226'>Document Object Model (DOM) Level 3 XPath Specification</a>.</p>
46  *
47  * </p>The evaluation of XPath expressions is provided by
48  * <code>XPathEvaluator</code>, which will provide evaluation of XPath 1.0
49  * expressions with no specialized extension functions or variables. It is
50  * expected that the <code>XPathEvaluator</code> interface will be
51  * implemented on the same object which implements the <code>Document</code>
52  * interface in an implementation which supports the XPath DOM module.
53  * <code>XPathEvaluator</code> implementations may be available from other
54  * sources that may provide support for special extension functions or
55  * variables which are not defined in this specification.</p>
56  *
57  * @see org.w3c.dom.xpath.XPathEvaluator
58  *
59  * @xsl.usage internal
60  */
61 public final class XPathEvaluatorImpl implements XPathEvaluator {
62 
63         /**
64          * This prefix resolver is created whenever null is passed to the
65          * evaluate method.  Its purpose is to satisfy the DOM L3 XPath API
66          * requirement that if a null prefix resolver is used, an exception
67          * should only be thrown when an attempt is made to resolve a prefix.
68          */
69         private class DummyPrefixResolver implements PrefixResolver {
70 
71                 /**
72                  * Constructor for DummyPrefixResolver.
73                  */
DummyPrefixResolver()74                 DummyPrefixResolver() {}
75 
76                 /**
77                  * @exception DOMException
78          *   NAMESPACE_ERR: Always throws this exceptionn
79                  *
80                  * @see com.sun.org.apache.xml.internal.utils.PrefixResolver#getNamespaceForPrefix(String, Node)
81                  */
getNamespaceForPrefix(String prefix, Node context)82                 public String getNamespaceForPrefix(String prefix, Node context) {
83             String fmsg = XPATHMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_RESOLVER, null);
84             throw new DOMException(DOMException.NAMESPACE_ERR, fmsg);   // Unable to resolve prefix with null prefix resolver.
85                 }
86 
87                 /**
88                  * @exception DOMException
89          *   NAMESPACE_ERR: Always throws this exceptionn
90          *
91                  * @see com.sun.org.apache.xml.internal.utils.PrefixResolver#getNamespaceForPrefix(String)
92                  */
getNamespaceForPrefix(String prefix)93                 public String getNamespaceForPrefix(String prefix) {
94                         return getNamespaceForPrefix(prefix,null);
95                 }
96 
97                 /**
98                  * @see com.sun.org.apache.xml.internal.utils.PrefixResolver#handlesNullPrefixes()
99                  */
handlesNullPrefixes()100                 public boolean handlesNullPrefixes() {
101                         return false;
102                 }
103 
104                 /**
105                  * @see com.sun.org.apache.xml.internal.utils.PrefixResolver#getBaseIdentifier()
106                  */
getBaseIdentifier()107                 public String getBaseIdentifier() {
108                         return null;
109                 }
110 
111         }
112 
113     /**
114      * The document to be searched to parallel the case where the XPathEvaluator
115      * is obtained by casting a Document.
116      */
117     private final Document m_doc;
118 
119     /**
120      * Constructor for XPathEvaluatorImpl.
121      *
122      * @param doc The document to be searched, to parallel the case where''
123      *            the XPathEvaluator is obtained by casting the document.
124      */
XPathEvaluatorImpl(Document doc)125     public XPathEvaluatorImpl(Document doc) {
126         m_doc = doc;
127     }
128 
129     /**
130      * Constructor in the case that the XPath expression can be evaluated
131      * without needing an XML document at all.
132      *
133      */
XPathEvaluatorImpl()134     public XPathEvaluatorImpl() {
135             m_doc = null;
136     }
137 
138         /**
139      * Creates a parsed XPath expression with resolved namespaces. This is
140      * useful when an expression will be reused in an application since it
141      * makes it possible to compile the expression string into a more
142      * efficient internal form and preresolve all namespace prefixes which
143      * occur within the expression.
144      *
145      * @param expression The XPath expression string to be parsed.
146      * @param resolver The <code>resolver</code> permits translation of
147      *   prefixes within the XPath expression into appropriate namespace URIs
148      *   . If this is specified as <code>null</code>, any namespace prefix
149      *   within the expression will result in <code>DOMException</code>
150      *   being thrown with the code <code>NAMESPACE_ERR</code>.
151      * @return The compiled form of the XPath expression.
152      * @exception XPathException
153      *   INVALID_EXPRESSION_ERR: Raised if the expression is not legal
154      *   according to the rules of the <code>XPathEvaluator</code>i
155      * @exception DOMException
156      *   NAMESPACE_ERR: Raised if the expression contains namespace prefixes
157      *   which cannot be resolved by the specified
158      *   <code>XPathNSResolver</code>.
159      *
160          * @see org.w3c.dom.xpath.XPathEvaluator#createExpression(String, XPathNSResolver)
161          */
createExpression( String expression, XPathNSResolver resolver)162         public XPathExpression createExpression(
163                 String expression,
164                 XPathNSResolver resolver)
165                 throws XPathException, DOMException {
166 
167                 try {
168 
169                         // If the resolver is null, create a dummy prefix resolver
170                         XPath xpath =  new XPath(expression,null,
171                              ((null == resolver) ? new DummyPrefixResolver() : ((PrefixResolver)resolver)),
172                               XPath.SELECT);
173 
174             return new XPathExpressionImpl(xpath, m_doc);
175 
176                 } catch (TransformerException e) {
177                         // Need to pass back exception code DOMException.NAMESPACE_ERR also.
178                         // Error found in DOM Level 3 XPath Test Suite.
179                         if(e instanceof XPathStylesheetDOM3Exception)
180                                 throw new DOMException(DOMException.NAMESPACE_ERR,e.getMessageAndLocation());
181                         else
182                                 throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,e.getMessageAndLocation());
183 
184                 }
185         }
186 
187         /**
188      * Adapts any DOM node to resolve namespaces so that an XPath expression
189      * can be easily evaluated relative to the context of the node where it
190      * appeared within the document. This adapter works like the DOM Level 3
191      * method <code>lookupNamespaceURI</code> on nodes in resolving the
192      * namespaceURI from a given prefix using the current information available
193      * in the node's hierarchy at the time lookupNamespaceURI is called, also
194      * correctly resolving the implicit xml prefix.
195      *
196      * @param nodeResolver The node to be used as a context for namespace
197      *   resolution.
198      * @return <code>XPathNSResolver</code> which resolves namespaces with
199      *   respect to the definitions in scope for a specified node.
200      *
201          * @see org.w3c.dom.xpath.XPathEvaluator#createNSResolver(Node)
202          */
createNSResolver(Node nodeResolver)203         public XPathNSResolver createNSResolver(Node nodeResolver) {
204 
205                 return new XPathNSResolverImpl((nodeResolver.getNodeType() == Node.DOCUMENT_NODE)
206                    ? ((Document) nodeResolver).getDocumentElement() : nodeResolver);
207         }
208 
209         /**
210      * Evaluates an XPath expression string and returns a result of the
211      * specified type if possible.
212      *
213      * @param expression The XPath expression string to be parsed and
214      *   evaluated.
215      * @param contextNode The <code>context</code> is context node for the
216      *   evaluation of this XPath expression. If the XPathEvaluator was
217      *   obtained by casting the <code>Document</code> then this must be
218      *   owned by the same document and must be a <code>Document</code>,
219      *   <code>Element</code>, <code>Attribute</code>, <code>Text</code>,
220      *   <code>CDATASection</code>, <code>Comment</code>,
221      *   <code>ProcessingInstruction</code>, or <code>XPathNamespace</code>
222      *   node. If the context node is a <code>Text</code> or a
223      *   <code>CDATASection</code>, then the context is interpreted as the
224      *   whole logical text node as seen by XPath, unless the node is empty
225      *   in which case it may not serve as the XPath context.
226      * @param resolver The <code>resolver</code> permits translation of
227      *   prefixes within the XPath expression into appropriate namespace URIs
228      *   . If this is specified as <code>null</code>, any namespace prefix
229      *   within the expression will result in <code>DOMException</code>
230      *   being thrown with the code <code>NAMESPACE_ERR</code>.
231      * @param type If a specific <code>type</code> is specified, then the
232      *   result will be coerced to return the specified type relying on
233      *   XPath type conversions and fail if the desired coercion is not
234      *   possible. This must be one of the type codes of
235      *   <code>XPathResult</code>.
236      * @param result The <code>result</code> specifies a specific result
237      *   object which may be reused and returned by this method. If this is
238      *   specified as <code>null</code>or the implementation does not reuse
239      *   the specified result, a new result object will be constructed and
240      *   returned.For XPath 1.0 results, this object will be of type
241      *   <code>XPathResult</code>.
242      * @return The result of the evaluation of the XPath expression.For XPath
243      *   1.0 results, this object will be of type <code>XPathResult</code>.
244      * @exception XPathException
245      *   INVALID_EXPRESSION_ERR: Raised if the expression is not legal
246      *   according to the rules of the <code>XPathEvaluator</code>i
247      *   <br>TYPE_ERR: Raised if the result cannot be converted to return the
248      *   specified type.
249      * @exception DOMException
250      *   NAMESPACE_ERR: Raised if the expression contains namespace prefixes
251      *   which cannot be resolved by the specified
252      *   <code>XPathNSResolver</code>.
253      *   <br>WRONG_DOCUMENT_ERR: The Node is from a document that is not
254      *   supported by this XPathEvaluator.
255      *   <br>NOT_SUPPORTED_ERR: The Node is not a type permitted as an XPath
256      *   context node.
257          *
258          * @see org.w3c.dom.xpath.XPathEvaluator#evaluate(String, Node, XPathNSResolver, short, XPathResult)
259          */
evaluate( String expression, Node contextNode, XPathNSResolver resolver, short type, Object result)260         public Object evaluate(
261                 String expression,
262                 Node contextNode,
263                 XPathNSResolver resolver,
264                 short type,
265                 Object result)
266                 throws XPathException, DOMException {
267 
268                 XPathExpression xpathExpression = createExpression(expression, resolver);
269 
270                 return  xpathExpression.evaluate(contextNode, type, result);
271         }
272 
273 }
274