1 /* |
1 /* |
2 * reserved comment block |
2 * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT REMOVE OR ALTER! |
|
4 */ |
3 */ |
5 /* |
4 /* |
6 * Copyright 1999-2004 The Apache Software Foundation. |
5 * Licensed to the Apache Software Foundation (ASF) under one or more |
|
6 * contributor license agreements. See the NOTICE file distributed with |
|
7 * this work for additional information regarding copyright ownership. |
|
8 * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
9 * (the "License"); you may not use this file except in compliance with |
|
10 * the License. You may obtain a copy of the License at |
7 * |
11 * |
8 * Licensed under the Apache License, Version 2.0 (the "License"); |
12 * http://www.apache.org/licenses/LICENSE-2.0 |
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 * |
13 * |
14 * Unless required by applicable law or agreed to in writing, software |
14 * Unless required by applicable law or agreed to in writing, software |
15 * distributed under the License is distributed on an "AS IS" BASIS, |
15 * distributed under the License is distributed on an "AS IS" BASIS, |
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
17 * See the License for the specific language governing permissions and |
17 * See the License for the specific language governing permissions and |
18 * limitations under the License. |
18 * limitations under the License. |
19 */ |
19 */ |
20 // $Id: XPathExpressionImpl.java,v 1.3 2005/09/27 09:40:43 sunithareddy Exp $ |
|
21 |
20 |
22 package com.sun.org.apache.xpath.internal.jaxp; |
21 package com.sun.org.apache.xpath.internal.jaxp; |
23 |
22 |
24 import com.sun.org.apache.xpath.internal.*; |
23 import com.sun.org.apache.xalan.internal.utils.FeatureManager; |
|
24 import com.sun.org.apache.xpath.internal.objects.XObject; |
|
25 import javax.xml.namespace.QName; |
25 import javax.xml.transform.TransformerException; |
26 import javax.xml.transform.TransformerException; |
26 |
27 import javax.xml.xpath.XPathConstants; |
27 import com.sun.org.apache.xpath.internal.objects.XObject; |
28 import javax.xml.xpath.XPathEvaluationResult; |
28 import com.sun.org.apache.xml.internal.dtm.DTM; |
29 import javax.xml.xpath.XPathExpression; |
29 import com.sun.org.apache.xml.internal.utils.PrefixResolver; |
|
30 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; |
|
31 import com.sun.org.apache.xalan.internal.res.XSLMessages; |
|
32 import com.sun.org.apache.xalan.internal.utils.FactoryImpl; |
|
33 import com.sun.org.apache.xalan.internal.utils.FeatureManager; |
|
34 |
|
35 import javax.xml.namespace.NamespaceContext; |
|
36 import javax.xml.namespace.QName; |
|
37 import javax.xml.xpath.XPathExpressionException; |
30 import javax.xml.xpath.XPathExpressionException; |
38 import javax.xml.xpath.XPathConstants; |
|
39 import javax.xml.xpath.XPathFunctionResolver; |
31 import javax.xml.xpath.XPathFunctionResolver; |
40 import javax.xml.xpath.XPathVariableResolver; |
32 import javax.xml.xpath.XPathVariableResolver; |
41 import javax.xml.xpath.XPathConstants; |
33 import org.w3c.dom.Document; |
42 |
|
43 import org.w3c.dom.Node; |
34 import org.w3c.dom.Node; |
44 import org.w3c.dom.Document; |
|
45 import org.w3c.dom.DOMImplementation; |
|
46 import org.w3c.dom.traversal.NodeIterator; |
|
47 import javax.xml.parsers.DocumentBuilderFactory; |
|
48 import javax.xml.parsers.DocumentBuilder; |
|
49 |
|
50 import org.xml.sax.InputSource; |
35 import org.xml.sax.InputSource; |
51 |
36 |
52 /** |
37 /** |
53 * The XPathExpression interface encapsulates a (compiled) XPath expression. |
38 * The XPathExpression interface encapsulates a (compiled) XPath expression. |
54 * |
39 * |
55 * @author Ramesh Mandava |
40 * @author Ramesh Mandava |
56 */ |
41 */ |
57 public class XPathExpressionImpl implements javax.xml.xpath.XPathExpression{ |
42 public class XPathExpressionImpl extends XPathImplUtil implements XPathExpression { |
58 |
43 |
59 private XPathFunctionResolver functionResolver; |
|
60 private XPathVariableResolver variableResolver; |
|
61 private JAXPPrefixResolver prefixResolver; |
|
62 private com.sun.org.apache.xpath.internal.XPath xpath; |
44 private com.sun.org.apache.xpath.internal.XPath xpath; |
63 |
|
64 // By default Extension Functions are allowed in XPath Expressions. If |
|
65 // Secure Processing Feature is set on XPathFactory then the invocation of |
|
66 // extensions function need to throw XPathFunctionException |
|
67 private boolean featureSecureProcessing = false; |
|
68 |
|
69 private boolean useServicesMechanism = true; |
|
70 |
|
71 private final FeatureManager featureManager; |
|
72 |
45 |
73 /** Protected constructor to prevent direct instantiation; use compile() |
46 /** Protected constructor to prevent direct instantiation; use compile() |
74 * from the context. |
47 * from the context. |
75 */ |
48 */ |
76 protected XPathExpressionImpl() { |
49 protected XPathExpressionImpl() { |
79 }; |
52 }; |
80 |
53 |
81 protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, |
54 protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, |
82 JAXPPrefixResolver prefixResolver, |
55 JAXPPrefixResolver prefixResolver, |
83 XPathFunctionResolver functionResolver, |
56 XPathFunctionResolver functionResolver, |
84 XPathVariableResolver variableResolver ) { |
57 XPathVariableResolver variableResolver) { |
85 this(xpath, prefixResolver, functionResolver, variableResolver, |
58 this(xpath, prefixResolver, functionResolver, variableResolver, |
86 false, true, new FeatureManager()); |
59 false, true, new FeatureManager()); |
87 }; |
60 }; |
88 |
61 |
89 protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, |
62 protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, |
90 JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver, |
63 JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver, |
91 XPathVariableResolver variableResolver, boolean featureSecureProcessing, |
64 XPathVariableResolver variableResolver, boolean featureSecureProcessing, |
92 boolean useServicesMechanism, FeatureManager featureManager ) { |
65 boolean useServiceMechanism, FeatureManager featureManager) { |
93 this.xpath = xpath; |
66 this.xpath = xpath; |
94 this.prefixResolver = prefixResolver; |
67 this.prefixResolver = prefixResolver; |
95 this.functionResolver = functionResolver; |
68 this.functionResolver = functionResolver; |
96 this.variableResolver = variableResolver; |
69 this.variableResolver = variableResolver; |
97 this.featureSecureProcessing = featureSecureProcessing; |
70 this.featureSecureProcessing = featureSecureProcessing; |
98 this.useServicesMechanism = useServicesMechanism; |
71 this.useServiceMechanism = useServiceMechanism; |
99 this.featureManager = featureManager; |
72 this.featureManager = featureManager; |
100 }; |
73 }; |
101 |
74 |
102 public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath ) { |
75 public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath) { |
103 this.xpath = xpath; |
76 this.xpath = xpath; |
104 } |
77 } |
105 |
78 |
106 public Object eval(Object item, QName returnType) |
79 public Object eval(Object item, QName returnType) |
107 throws javax.xml.transform.TransformerException { |
80 throws javax.xml.transform.TransformerException { |
108 XObject resultObject = eval ( item ); |
81 XObject resultObject = eval(item, xpath); |
109 return getResultAsType( resultObject, returnType ); |
82 return getResultAsType(resultObject, returnType); |
110 } |
83 } |
111 |
84 |
112 private XObject eval ( Object contextItem ) |
85 @Override |
113 throws javax.xml.transform.TransformerException { |
86 public Object evaluate(Object item, QName returnType) |
114 com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null; |
87 throws XPathExpressionException { |
115 if ( functionResolver != null ) { |
88 isSupported(returnType); |
116 JAXPExtensionsProvider jep = new JAXPExtensionsProvider( |
89 try { |
117 functionResolver, featureSecureProcessing, featureManager ); |
90 return eval(item, returnType); |
118 xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep ); |
91 } catch (java.lang.NullPointerException npe) { |
119 } else { |
92 // If VariableResolver returns null Or if we get |
120 xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); |
93 // NullPointerException at this stage for some other reason |
|
94 // then we have to reurn XPathException |
|
95 throw new XPathExpressionException (npe); |
|
96 } catch (javax.xml.transform.TransformerException te) { |
|
97 Throwable nestedException = te.getException(); |
|
98 if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { |
|
99 throw (javax.xml.xpath.XPathFunctionException)nestedException; |
|
100 } else { |
|
101 // For any other exceptions we need to throw |
|
102 // XPathExpressionException (as per spec) |
|
103 throw new XPathExpressionException(te); |
|
104 } |
121 } |
105 } |
122 |
|
123 xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); |
|
124 XObject xobj = null; |
|
125 |
|
126 Node contextNode = (Node)contextItem; |
|
127 // We always need to have a ContextNode with Xalan XPath implementation |
|
128 // To allow simple expression evaluation like 1+1 we are setting |
|
129 // dummy Document as Context Node |
|
130 |
|
131 if ( contextNode == null ) |
|
132 xobj = xpath.execute(xpathSupport, DTM.NULL, prefixResolver); |
|
133 else |
|
134 xobj = xpath.execute(xpathSupport, contextNode, prefixResolver); |
|
135 |
|
136 return xobj; |
|
137 } |
106 } |
138 |
107 |
139 |
108 |
140 /** |
109 @Override |
141 * <p>Evaluate the compiled XPath expression in the specified context and |
110 public String evaluate(Object item) |
142 * return the result as the specified type.</p> |
|
143 * |
|
144 * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec |
|
145 * for context item evaluation, |
|
146 * variable, function and QName resolution and return type conversion.</p> |
|
147 * |
|
148 * <p>If <code>returnType</code> is not one of the types defined |
|
149 * in {@link XPathConstants}, |
|
150 * then an <code>IllegalArgumentException</code> is thrown.</p> |
|
151 * |
|
152 * <p>If a <code>null</code> value is provided for |
|
153 * <code>item</code>, an empty document will be used for the |
|
154 * context. |
|
155 * If <code>returnType</code> is <code>null</code>, then a |
|
156 * <code>NullPointerException</code> is thrown.</p> |
|
157 * |
|
158 * @param item The starting context (node or node list, for example). |
|
159 * @param returnType The desired return type. |
|
160 * |
|
161 * @return The <code>Object</code> that is the result of evaluating the |
|
162 * expression and converting the result to |
|
163 * <code>returnType</code>. |
|
164 * |
|
165 * @throws XPathExpressionException If the expression cannot be evaluated. |
|
166 * @throws IllegalArgumentException If <code>returnType</code> is not one |
|
167 * of the types defined in {@link XPathConstants}. |
|
168 * @throws NullPointerException If <code>returnType</code> is |
|
169 * <code>null</code>. |
|
170 */ |
|
171 public Object evaluate(Object item, QName returnType) |
|
172 throws XPathExpressionException { |
111 throws XPathExpressionException { |
173 //Validating parameters to enforce constraints defined by JAXP spec |
112 return (String)this.evaluate(item, XPathConstants.STRING); |
174 if ( returnType == null ) { |
|
175 //Throwing NullPointerException as defined in spec |
|
176 String fmsg = XSLMessages.createXPATHMessage( |
|
177 XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, |
|
178 new Object[] {"returnType"} ); |
|
179 throw new NullPointerException( fmsg ); |
|
180 } |
|
181 // Checking if requested returnType is supported. returnType need to be |
|
182 // defined in XPathConstants |
|
183 if ( !isSupported ( returnType ) ) { |
|
184 String fmsg = XSLMessages.createXPATHMessage( |
|
185 XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, |
|
186 new Object[] { returnType.toString() } ); |
|
187 throw new IllegalArgumentException ( fmsg ); |
|
188 } |
|
189 try { |
|
190 return eval( item, returnType); |
|
191 } catch ( java.lang.NullPointerException npe ) { |
|
192 // If VariableResolver returns null Or if we get |
|
193 // NullPointerException at this stage for some other reason |
|
194 // then we have to reurn XPathException |
|
195 throw new XPathExpressionException ( npe ); |
|
196 } catch ( javax.xml.transform.TransformerException te ) { |
|
197 Throwable nestedException = te.getException(); |
|
198 if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { |
|
199 throw (javax.xml.xpath.XPathFunctionException)nestedException; |
|
200 } else { |
|
201 // For any other exceptions we need to throw |
|
202 // XPathExpressionException ( as per spec ) |
|
203 throw new XPathExpressionException( te); |
|
204 } |
|
205 } |
|
206 |
|
207 } |
113 } |
208 |
114 |
209 /** |
115 @Override |
210 * <p>Evaluate the compiled XPath expression in the specified context and |
|
211 * return the result as a <code>String</code>.</p> |
|
212 * |
|
213 * <p>This method calls {@link #evaluate(Object item, QName returnType)} |
|
214 * with a <code>returnType</code> of |
|
215 * {@link XPathConstants#STRING}.</p> |
|
216 * |
|
217 * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec |
|
218 * for context item evaluation, |
|
219 * variable, function and QName resolution and return type conversion.</p> |
|
220 * |
|
221 * <p>If a <code>null</code> value is provided for |
|
222 * <code>item</code>, an empty document will be used for the |
|
223 * context. |
|
224 * |
|
225 * @param item The starting context (node or node list, for example). |
|
226 * |
|
227 * @return The <code>String</code> that is the result of evaluating the |
|
228 * expression and converting the result to a |
|
229 * <code>String</code>. |
|
230 * |
|
231 * @throws XPathExpressionException If the expression cannot be evaluated. |
|
232 */ |
|
233 public String evaluate(Object item) |
|
234 throws XPathExpressionException { |
|
235 return (String)this.evaluate( item, XPathConstants.STRING ); |
|
236 } |
|
237 |
|
238 |
|
239 |
|
240 static DocumentBuilderFactory dbf = null; |
|
241 static DocumentBuilder db = null; |
|
242 static Document d = null; |
|
243 |
|
244 /** |
|
245 * <p>Evaluate the compiled XPath expression in the context of the |
|
246 * specified <code>InputSource</code> and return the result as the |
|
247 * specified type.</p> |
|
248 * |
|
249 * <p>This method builds a data model for the {@link InputSource} and calls |
|
250 * {@link #evaluate(Object item, QName returnType)} on the resulting |
|
251 * document object.</p> |
|
252 * |
|
253 * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec |
|
254 * for context item evaluation, |
|
255 * variable, function and QName resolution and return type conversion.</p> |
|
256 * |
|
257 * <p>If <code>returnType</code> is not one of the types defined in |
|
258 * {@link XPathConstants}, |
|
259 * then an <code>IllegalArgumentException</code> is thrown.</p> |
|
260 * |
|
261 *<p>If <code>source</code> or <code>returnType</code> is <code>null</code>, |
|
262 * then a <code>NullPointerException</code> is thrown.</p> |
|
263 * |
|
264 * @param source The <code>InputSource</code> of the document to evaluate |
|
265 * over. |
|
266 * @param returnType The desired return type. |
|
267 * |
|
268 * @return The <code>Object</code> that is the result of evaluating the |
|
269 * expression and converting the result to |
|
270 * <code>returnType</code>. |
|
271 * |
|
272 * @throws XPathExpressionException If the expression cannot be evaluated. |
|
273 * @throws IllegalArgumentException If <code>returnType</code> is not one |
|
274 * of the types defined in {@link XPathConstants}. |
|
275 * @throws NullPointerException If <code>source</code> or |
|
276 * <code>returnType</code> is <code>null</code>. |
|
277 */ |
|
278 public Object evaluate(InputSource source, QName returnType) |
116 public Object evaluate(InputSource source, QName returnType) |
279 throws XPathExpressionException { |
117 throws XPathExpressionException { |
280 if ( ( source == null ) || ( returnType == null ) ) { |
118 isSupported (returnType); |
281 String fmsg = XSLMessages.createXPATHMessage( |
|
282 XPATHErrorResources.ER_SOURCE_RETURN_TYPE_CANNOT_BE_NULL, |
|
283 null ); |
|
284 throw new NullPointerException ( fmsg ); |
|
285 } |
|
286 // Checking if requested returnType is supported. returnType need to be |
|
287 // defined in XPathConstants |
|
288 if ( !isSupported ( returnType ) ) { |
|
289 String fmsg = XSLMessages.createXPATHMessage( |
|
290 XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, |
|
291 new Object[] { returnType.toString() } ); |
|
292 throw new IllegalArgumentException ( fmsg ); |
|
293 } |
|
294 try { |
119 try { |
295 if ( dbf == null ) { |
120 Document document = getDocument(source); |
296 dbf = FactoryImpl.getDOMFactory(useServicesMechanism); |
121 return eval(document, returnType); |
297 dbf.setNamespaceAware( true ); |
122 } catch (TransformerException e) { |
298 dbf.setValidating( false ); |
123 throw new XPathExpressionException(e); |
299 } |
|
300 db = dbf.newDocumentBuilder(); |
|
301 Document document = db.parse( source ); |
|
302 return eval( document, returnType ); |
|
303 } catch ( Exception e ) { |
|
304 throw new XPathExpressionException ( e ); |
|
305 } |
124 } |
306 } |
125 } |
307 |
126 |
308 /** |
127 @Override |
309 * <p>Evaluate the compiled XPath expression in the context of the specified <code>InputSource</code> and return the result as a |
|
310 * <code>String</code>.</p> |
|
311 * |
|
312 * <p>This method calls {@link #evaluate(InputSource source, QName returnType)} with a <code>returnType</code> of |
|
313 * {@link XPathConstants#STRING}.</p> |
|
314 * |
|
315 * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec |
|
316 * for context item evaluation, |
|
317 * variable, function and QName resolution and return type conversion.</p> |
|
318 * |
|
319 * <p>If <code>source</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p> |
|
320 * |
|
321 * @param source The <code>InputSource</code> of the document to evaluate over. |
|
322 * |
|
323 * @return The <code>String</code> that is the result of evaluating the expression and converting the result to a |
|
324 * <code>String</code>. |
|
325 * |
|
326 * @throws XPathExpressionException If the expression cannot be evaluated. |
|
327 * @throws NullPointerException If <code>source</code> is <code>null</code>. |
|
328 */ |
|
329 public String evaluate(InputSource source) |
128 public String evaluate(InputSource source) |
330 throws XPathExpressionException { |
129 throws XPathExpressionException { |
331 return (String)this.evaluate( source, XPathConstants.STRING ); |
130 return (String)this.evaluate(source, XPathConstants.STRING); |
332 } |
131 } |
333 |
132 |
334 private boolean isSupported( QName returnType ) { |
133 @Override |
335 // XPathConstants.STRING |
134 public <T>T evaluateExpression(Object item, Class<T> type) |
336 if ( ( returnType.equals( XPathConstants.STRING ) ) || |
135 throws XPathExpressionException { |
337 ( returnType.equals( XPathConstants.NUMBER ) ) || |
136 isSupportedClassType(type); |
338 ( returnType.equals( XPathConstants.BOOLEAN ) ) || |
|
339 ( returnType.equals( XPathConstants.NODE ) ) || |
|
340 ( returnType.equals( XPathConstants.NODESET ) ) ) { |
|
341 |
137 |
342 return true; |
138 try { |
|
139 XObject resultObject = eval(item, xpath); |
|
140 if (type.isAssignableFrom(XPathEvaluationResult.class)) { |
|
141 return getXPathResult(resultObject, type); |
|
142 } else { |
|
143 return XPathResultImpl.getValue(resultObject, type); |
|
144 } |
|
145 |
|
146 } catch (javax.xml.transform.TransformerException te) { |
|
147 throw new XPathExpressionException(te); |
343 } |
148 } |
344 return false; |
|
345 } |
|
346 |
|
347 private Object getResultAsType( XObject resultObject, QName returnType ) |
|
348 throws javax.xml.transform.TransformerException { |
|
349 // XPathConstants.STRING |
|
350 if ( returnType.equals( XPathConstants.STRING ) ) { |
|
351 return resultObject.str(); |
|
352 } |
|
353 // XPathConstants.NUMBER |
|
354 if ( returnType.equals( XPathConstants.NUMBER ) ) { |
|
355 return new Double ( resultObject.num()); |
|
356 } |
|
357 // XPathConstants.BOOLEAN |
|
358 if ( returnType.equals( XPathConstants.BOOLEAN ) ) { |
|
359 return new Boolean( resultObject.bool()); |
|
360 } |
|
361 // XPathConstants.NODESET ---ORdered, UNOrdered??? |
|
362 if ( returnType.equals( XPathConstants.NODESET ) ) { |
|
363 return resultObject.nodelist(); |
|
364 } |
|
365 // XPathConstants.NODE |
|
366 if ( returnType.equals( XPathConstants.NODE ) ) { |
|
367 NodeIterator ni = resultObject.nodeset(); |
|
368 //Return the first node, or null |
|
369 return ni.nextNode(); |
|
370 } |
|
371 // If isSupported check is already done then the execution path |
|
372 // shouldn't come here. Being defensive |
|
373 String fmsg = XSLMessages.createXPATHMessage( |
|
374 XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, |
|
375 new Object[] { returnType.toString()}); |
|
376 throw new IllegalArgumentException ( fmsg ); |
|
377 } |
149 } |
378 |
150 |
|
151 @Override |
|
152 public XPathEvaluationResult<?> evaluateExpression(Object item) |
|
153 throws XPathExpressionException { |
|
154 return evaluateExpression(item, XPathEvaluationResult.class); |
|
155 } |
|
156 |
|
157 @Override |
|
158 public <T>T evaluateExpression(InputSource source, Class<T> type) |
|
159 throws XPathExpressionException { |
|
160 Document document = getDocument(source); |
|
161 return evaluateExpression(document, type); |
|
162 } |
|
163 |
|
164 @Override |
|
165 public XPathEvaluationResult<?> evaluateExpression(InputSource source) |
|
166 throws XPathExpressionException { |
|
167 return evaluateExpression(source, XPathEvaluationResult.class); |
|
168 } |
379 } |
169 } |