blob: af8c0091a157aa41e09061892cf4888836f1e02c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5
6/*
7 * Copyright 1999-2004 The Apache Software Foundation.
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 */
22package com.sun.org.apache.xml.internal.security.utils;
23
24
25
26import javax.xml.transform.TransformerException;
27
28import com.sun.org.apache.xml.internal.security.transforms.implementations.FuncHereContext;
29import com.sun.org.apache.xml.internal.utils.PrefixResolver;
30import com.sun.org.apache.xml.internal.utils.PrefixResolverDefault;
31import com.sun.org.apache.xpath.internal.XPath;
32import com.sun.org.apache.xpath.internal.objects.XObject;
33import org.w3c.dom.Attr;
34import org.w3c.dom.Document;
35import org.w3c.dom.Node;
36import org.w3c.dom.NodeList;
37import org.w3c.dom.ProcessingInstruction;
38import org.w3c.dom.Text;
39import org.w3c.dom.traversal.NodeIterator;
40
41
42
43
44/**
45 * This class does the same as {@link com.sun.org.apache.xpath.internal.XPathAPI} except that the XPath strings
46 * are not supplied as Strings but as {@link Text}, {@link Attr}ibute or
47 * {ProcessingInstruction} nodes which contain the XPath string. This enables
48 * us to use the <CODE>here()</CODE> function.
49 * <BR>
50 * The methods in this class are convenience methods into the low-level XPath API.
51 * These functions tend to be a little slow, since a number of objects must be
52 * created for each evaluation. A faster way is to precompile the
53 * XPaths using the low-level API, and then just use the XPaths
54 * over and over.
55 *
56 * @author $Author: raul $
57 * @see <a href="http://www.w3.org/TR/xpath">XPath Specification</a>
58 */
59public class XPathFuncHereAPI {
60
61 /**
62 * Use an XPath string to select a single node. XPath namespace
63 * prefixes are resolved from the context node, which may not
64 * be what you want (see the next method).
65 *
66 * @param contextNode The node to start searching from.
67 * @param xpathnode A Node containing a valid XPath string.
68 * @return The first node found that matches the XPath, or null.
69 *
70 * @throws TransformerException
71 */
72 public static Node selectSingleNode(Node contextNode, Node xpathnode)
73 throws TransformerException {
74 return selectSingleNode(contextNode, xpathnode, contextNode);
75 }
76
77 /**
78 * Use an XPath string to select a single node.
79 * XPath namespace prefixes are resolved from the namespaceNode.
80 *
81 * @param contextNode The node to start searching from.
82 * @param xpathnode
83 * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
84 * @return The first node found that matches the XPath, or null.
85 *
86 * @throws TransformerException
87 */
88 public static Node selectSingleNode(
89 Node contextNode, Node xpathnode, Node namespaceNode)
90 throws TransformerException {
91
92 // Have the XObject return its result as a NodeSetDTM.
93 NodeIterator nl = selectNodeIterator(contextNode, xpathnode,
94 namespaceNode);
95
96 // Return the first node, or null
97 return nl.nextNode();
98 }
99
100 /**
101 * Use an XPath string to select a nodelist.
102 * XPath namespace prefixes are resolved from the contextNode.
103 *
104 * @param contextNode The node to start searching from.
105 * @param xpathnode
106 * @return A NodeIterator, should never be null.
107 *
108 * @throws TransformerException
109 */
110 public static NodeIterator selectNodeIterator(
111 Node contextNode, Node xpathnode) throws TransformerException {
112 return selectNodeIterator(contextNode, xpathnode, contextNode);
113 }
114
115 /**
116 * Use an XPath string to select a nodelist.
117 * XPath namespace prefixes are resolved from the namespaceNode.
118 *
119 * @param contextNode The node to start searching from.
120 * @param xpathnode
121 * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
122 * @return A NodeIterator, should never be null.
123 *
124 * @throws TransformerException
125 */
126 public static NodeIterator selectNodeIterator(
127 Node contextNode, Node xpathnode, Node namespaceNode)
128 throws TransformerException {
129
130 // Execute the XPath, and have it return the result
131 XObject list = eval(contextNode, xpathnode, namespaceNode);
132
133 // Have the XObject return its result as a NodeSetDTM.
134 return list.nodeset();
135 }
136
137 /**
138 * Use an XPath string to select a nodelist.
139 * XPath namespace prefixes are resolved from the contextNode.
140 *
141 * @param contextNode The node to start searching from.
142 * @param xpathnode
143 * @return A NodeIterator, should never be null.
144 *
145 * @throws TransformerException
146 */
147 public static NodeList selectNodeList(Node contextNode, Node xpathnode)
148 throws TransformerException {
149 return selectNodeList(contextNode, xpathnode, contextNode);
150 }
151
152 /**
153 * Use an XPath string to select a nodelist.
154 * XPath namespace prefixes are resolved from the namespaceNode.
155 *
156 * @param contextNode The node to start searching from.
157 * @param xpathnode
158 * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
159 * @return A NodeIterator, should never be null.
160 *
161 * @throws TransformerException
162 */
163 public static NodeList selectNodeList(
164 Node contextNode, Node xpathnode, Node namespaceNode)
165 throws TransformerException {
166
167 // Execute the XPath, and have it return the result
168 XObject list = eval(contextNode, xpathnode, namespaceNode);
169
170 // Return a NodeList.
171 return list.nodelist();
172 }
173
174 /**
175 * Evaluate XPath string to an XObject. Using this method,
176 * XPath namespace prefixes will be resolved from the namespaceNode.
177 * @param contextNode The node to start searching from.
178 * @param xpathnode
179 * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
180 * @see com.sun.org.apache.xpath.internal.objects.XObject
181 * @see com.sun.org.apache.xpath.internal.objects.XNull
182 * @see com.sun.org.apache.xpath.internal.objects.XBoolean
183 * @see com.sun.org.apache.xpath.internal.objects.XNumber
184 * @see com.sun.org.apache.xpath.internal.objects.XString
185 * @see com.sun.org.apache.xpath.internal.objects.XRTreeFrag
186 *
187 * @throws TransformerException
188 */
189 public static XObject eval(Node contextNode, Node xpathnode)
190 throws TransformerException {
191 return eval(contextNode, xpathnode, contextNode);
192 }
193
194 /**
195 * Evaluate XPath string to an XObject.
196 * XPath namespace prefixes are resolved from the namespaceNode.
197 * The implementation of this is a little slow, since it creates
198 * a number of objects each time it is called. This could be optimized
199 * to keep the same objects around, but then thread-safety issues would arise.
200 *
201 * @param contextNode The node to start searching from.
202 * @param xpathnode
203 * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
204 * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
205 * @see com.sun.org.apache.xpath.internal.objects.XObject
206 * @see com.sun.org.apache.xpath.internal.objects.XNull
207 * @see com.sun.org.apache.xpath.internal.objects.XBoolean
208 * @see com.sun.org.apache.xpath.internal.objects.XNumber
209 * @see com.sun.org.apache.xpath.internal.objects.XString
210 * @see com.sun.org.apache.xpath.internal.objects.XRTreeFrag
211 *
212 * @throws TransformerException
213 */
214 public static XObject eval(
215 Node contextNode, Node xpathnode, Node namespaceNode)
216 throws TransformerException {
217
218 // Since we don't have a XML Parser involved here, install some default support
219 // for things like namespaces, etc.
220 // (Changed from: XPathContext xpathSupport = new XPathContext();
221 // because XPathContext is weak in a number of areas... perhaps
222 // XPathContext should be done away with.)
223 FuncHereContext xpathSupport = new FuncHereContext(xpathnode);
224
225 // Create an object to resolve namespace prefixes.
226 // XPath namespaces are resolved from the input context node's document element
227 // if it is a root node, or else the current context node (for lack of a better
228 // resolution space, given the simplicity of this sample code).
229 PrefixResolverDefault prefixResolver =
230 new PrefixResolverDefault((namespaceNode.getNodeType()
231 == Node.DOCUMENT_NODE)
232 ? ((Document) namespaceNode)
233 .getDocumentElement()
234 : namespaceNode);
235 String str = getStrFromNode(xpathnode);
236
237 // Create the XPath object.
238 XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
239
240 // Execute the XPath, and have it return the result
241 // return xpath.execute(xpathSupport, contextNode, prefixResolver);
242 int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
243
244 return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
245 }
246
247 /**
248 * Evaluate XPath string to an XObject.
249 * XPath namespace prefixes are resolved from the namespaceNode.
250 * The implementation of this is a little slow, since it creates
251 * a number of objects each time it is called. This could be optimized
252 * to keep the same objects around, but then thread-safety issues would arise.
253 *
254 * @param contextNode The node to start searching from.
255 * @param xpathnode
256 * @param prefixResolver Will be called if the parser encounters namespace
257 * prefixes, to resolve the prefixes to URLs.
258 * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
259 * @see com.sun.org.apache.xpath.internal.objects.XObject
260 * @see com.sun.org.apache.xpath.internal.objects.XNull
261 * @see com.sun.org.apache.xpath.internal.objects.XBoolean
262 * @see com.sun.org.apache.xpath.internal.objects.XNumber
263 * @see com.sun.org.apache.xpath.internal.objects.XString
264 * @see com.sun.org.apache.xpath.internal.objects.XRTreeFrag
265 *
266 * @throws TransformerException
267 */
268 public static XObject eval(
269 Node contextNode, Node xpathnode, PrefixResolver prefixResolver)
270 throws TransformerException {
271
272 String str = getStrFromNode(xpathnode);
273
274 // Since we don't have a XML Parser involved here, install some default support
275 // for things like namespaces, etc.
276 // (Changed from: XPathContext xpathSupport = new XPathContext();
277 // because XPathContext is weak in a number of areas... perhaps
278 // XPathContext should be done away with.)
279 // Create the XPath object.
280 XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
281
282 // Execute the XPath, and have it return the result
283 FuncHereContext xpathSupport = new FuncHereContext(xpathnode);
284 int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
285
286 return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
287 }
288
289 /**
290 * Method getStrFromNode
291 *
292 * @param xpathnode
293 * @return the string from the node
294 */
295 private static String getStrFromNode(Node xpathnode) {
296
297 if (xpathnode.getNodeType() == Node.TEXT_NODE) {
298 return ((Text) xpathnode).getData();
299 } else if (xpathnode.getNodeType() == Node.ATTRIBUTE_NODE) {
300 return ((Attr) xpathnode).getNodeValue();
301 } else if (xpathnode.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
302 return ((ProcessingInstruction) xpathnode).getNodeValue();
303 }
304
305 return "";
306 }
307}