KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xpath > CachedXPathAPI


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: CachedXPathAPI.java,v 1.5 2004/02/17 04:30:02 minchau Exp $
18  */

19 package org.apache.xpath;
20
21 import javax.xml.transform.TransformerException JavaDoc;
22
23 import org.apache.xml.utils.PrefixResolver;
24 import org.apache.xml.utils.PrefixResolverDefault;
25 import org.apache.xpath.objects.XObject;
26
27 import org.w3c.dom.Document JavaDoc;
28 import org.w3c.dom.Node JavaDoc;
29 import org.w3c.dom.NodeList JavaDoc;
30 import org.w3c.dom.traversal.NodeIterator;
31
32 /**
33  * The methods in this class are convenience methods into the
34  * low-level XPath API.
35  *
36  * These functions tend to be a little slow, since a number of objects must be
37  * created for each evaluation. A faster way is to precompile the
38  * XPaths using the low-level API, and then just use the XPaths
39  * over and over.
40  *
41  * This is an alternative for the old XPathAPI class, which provided
42  * static methods for the purpose but had the drawback of
43  * instantiating a new XPathContext (and thus building a new DTMManager,
44  * and new DTMs) each time it was called. XPathAPIObject instead retains
45  * its context as long as the object persists, reusing the DTMs. This
46  * does have a downside: if you've changed your source document, you should
47  * obtain a new XPathAPIObject to continue searching it, since trying to use
48  * the old DTMs will probably yield bad results or malfunction outright... and
49  * the cached DTMs may consume memory until this object and its context are
50  * returned to the heap. Essentially, it's the caller's responsibility to
51  * decide when to discard the cache.
52  *
53  * @see <a HREF="http://www.w3.org/TR/xpath">XPath Specification</a>
54  * */

55 public class CachedXPathAPI
56 {
57   /** XPathContext, and thus the document model system (DTMs), persists through multiple
58       calls to this object. This is set in the constructor.
59   */

60   protected XPathContext xpathSupport;
61
62   /** Default constructor. Establishes its own XPathContext, and hence
63    * its own DTMManager. Good choice for simple uses.
64    * */

65   public CachedXPathAPI()
66   {
67     xpathSupport = new XPathContext();
68   }
69   
70   /** This constructor shares its XPathContext with a pre-existing
71    * CachedXPathAPI. That allows sharing document models (DTMs) and
72    * previously established location state.
73    *
74    * Note that the original CachedXPathAPI and the new one should not
75    * be operated concurrently; we do not support multithreaded access
76    * to a single DTM at this time.
77    *
78    * %REVIEW% Should this instead do a clone-and-reset on the XPathSupport object?
79    * */

80   public CachedXPathAPI(CachedXPathAPI priorXPathAPI)
81   {
82     xpathSupport = priorXPathAPI.xpathSupport;
83   }
84
85
86   /** Returns the XPathSupport object used in this CachedXPathAPI
87    *
88    * %REVIEW% I'm somewhat concerned about the loss of encapsulation
89    * this causes, but the xml-security folks say they need it.
90    * */

91   public XPathContext getXPathContext()
92   {
93     return this.xpathSupport;
94   }
95   
96
97   /**
98    * Use an XPath string to select a single node. XPath namespace
99    * prefixes are resolved from the context node, which may not
100    * be what you want (see the next method).
101    *
102    * @param contextNode The node to start searching from.
103    * @param str A valid XPath string.
104    * @return The first node found that matches the XPath, or null.
105    *
106    * @throws TransformerException
107    */

108   public Node JavaDoc selectSingleNode(Node JavaDoc contextNode, String JavaDoc str)
109           throws TransformerException JavaDoc
110   {
111     return selectSingleNode(contextNode, str, contextNode);
112   }
113
114   /**
115    * Use an XPath string to select a single node.
116    * XPath namespace prefixes are resolved from the namespaceNode.
117    *
118    * @param contextNode The node to start searching from.
119    * @param str A valid XPath string.
120    * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
121    * @return The first node found that matches the XPath, or null.
122    *
123    * @throws TransformerException
124    */

125   public Node JavaDoc selectSingleNode(
126           Node JavaDoc contextNode, String JavaDoc str, Node JavaDoc namespaceNode)
127             throws TransformerException JavaDoc
128   {
129
130     // Have the XObject return its result as a NodeSetDTM.
131
NodeIterator nl = selectNodeIterator(contextNode, str, namespaceNode);
132
133     // Return the first node, or null
134
return nl.nextNode();
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 str A valid XPath string.
143    * @return A NodeIterator, should never be null.
144    *
145    * @throws TransformerException
146    */

147   public NodeIterator selectNodeIterator(Node JavaDoc contextNode, String JavaDoc str)
148           throws TransformerException JavaDoc
149   {
150     return selectNodeIterator(contextNode, str, contextNode);
151   }
152
153   /**
154    * Use an XPath string to select a nodelist.
155    * XPath namespace prefixes are resolved from the namespaceNode.
156    *
157    * @param contextNode The node to start searching from.
158    * @param str A valid XPath string.
159    * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
160    * @return A NodeIterator, should never be null.
161    *
162    * @throws TransformerException
163    */

164   public NodeIterator selectNodeIterator(
165           Node JavaDoc contextNode, String JavaDoc str, Node JavaDoc namespaceNode)
166             throws TransformerException JavaDoc
167   {
168
169     // Execute the XPath, and have it return the result
170
XObject list = eval(contextNode, str, namespaceNode);
171
172     // Have the XObject return its result as a NodeSetDTM.
173
return list.nodeset();
174   }
175
176   /**
177    * Use an XPath string to select a nodelist.
178    * XPath namespace prefixes are resolved from the contextNode.
179    *
180    * @param contextNode The node to start searching from.
181    * @param str A valid XPath string.
182    * @return A NodeIterator, should never be null.
183    *
184    * @throws TransformerException
185    */

186   public NodeList JavaDoc selectNodeList(Node JavaDoc contextNode, String JavaDoc str)
187           throws TransformerException JavaDoc
188   {
189     return selectNodeList(contextNode, str, contextNode);
190   }
191
192   /**
193    * Use an XPath string to select a nodelist.
194    * XPath namespace prefixes are resolved from the namespaceNode.
195    *
196    * @param contextNode The node to start searching from.
197    * @param str A valid XPath string.
198    * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
199    * @return A NodeIterator, should never be null.
200    *
201    * @throws TransformerException
202    */

203   public NodeList JavaDoc selectNodeList(
204           Node JavaDoc contextNode, String JavaDoc str, Node JavaDoc namespaceNode)
205             throws TransformerException JavaDoc
206   {
207
208     // Execute the XPath, and have it return the result
209
XObject list = eval(contextNode, str, namespaceNode);
210
211     // Return a NodeList.
212
return list.nodelist();
213   }
214
215   /**
216    * Evaluate XPath string to an XObject. Using this method,
217    * XPath namespace prefixes will be resolved from the namespaceNode.
218    * @param contextNode The node to start searching from.
219    * @param str A valid XPath string.
220    * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
221    * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
222    * @see org.apache.xpath.objects.XObject
223    * @see org.apache.xpath.objects.XNull
224    * @see org.apache.xpath.objects.XBoolean
225    * @see org.apache.xpath.objects.XNumber
226    * @see org.apache.xpath.objects.XString
227    * @see org.apache.xpath.objects.XRTreeFrag
228    *
229    * @throws TransformerException
230    */

231   public XObject eval(Node JavaDoc contextNode, String JavaDoc str)
232           throws TransformerException JavaDoc
233   {
234     return eval(contextNode, str, contextNode);
235   }
236
237   /**
238    * Evaluate XPath string to an XObject.
239    * XPath namespace prefixes are resolved from the namespaceNode.
240    * The implementation of this is a little slow, since it creates
241    * a number of objects each time it is called. This could be optimized
242    * to keep the same objects around, but then thread-safety issues would arise.
243    *
244    * @param contextNode The node to start searching from.
245    * @param str A valid XPath string.
246    * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
247    * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
248    * @see org.apache.xpath.objects.XObject
249    * @see org.apache.xpath.objects.XNull
250    * @see org.apache.xpath.objects.XBoolean
251    * @see org.apache.xpath.objects.XNumber
252    * @see org.apache.xpath.objects.XString
253    * @see org.apache.xpath.objects.XRTreeFrag
254    *
255    * @throws TransformerException
256    */

257   public XObject eval(Node JavaDoc contextNode, String JavaDoc str, Node JavaDoc namespaceNode)
258           throws TransformerException JavaDoc
259   {
260
261     // Since we don't have a XML Parser involved here, install some default support
262
// for things like namespaces, etc.
263
// (Changed from: XPathContext xpathSupport = new XPathContext();
264
// because XPathContext is weak in a number of areas... perhaps
265
// XPathContext should be done away with.)
266

267     // Create an object to resolve namespace prefixes.
268
// XPath namespaces are resolved from the input context node's document element
269
// if it is a root node, or else the current context node (for lack of a better
270
// resolution space, given the simplicity of this sample code).
271
PrefixResolverDefault prefixResolver = new PrefixResolverDefault(
272       (namespaceNode.getNodeType() == Node.DOCUMENT_NODE)
273       ? ((Document JavaDoc) namespaceNode).getDocumentElement() : namespaceNode);
274
275     // Create the XPath object.
276
XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
277
278     // Execute the XPath, and have it return the result
279
// return xpath.execute(xpathSupport, contextNode, prefixResolver);
280
int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
281
282     return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
283   }
284
285   /**
286    * Evaluate XPath string to an XObject.
287    * XPath namespace prefixes are resolved from the namespaceNode.
288    * The implementation of this is a little slow, since it creates
289    * a number of objects each time it is called. This could be optimized
290    * to keep the same objects around, but then thread-safety issues would arise.
291    *
292    * @param contextNode The node to start searching from.
293    * @param str A valid XPath string.
294    * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
295    * @param prefixResolver Will be called if the parser encounters namespace
296    * prefixes, to resolve the prefixes to URLs.
297    * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
298    * @see org.apache.xpath.objects.XObject
299    * @see org.apache.xpath.objects.XNull
300    * @see org.apache.xpath.objects.XBoolean
301    * @see org.apache.xpath.objects.XNumber
302    * @see org.apache.xpath.objects.XString
303    * @see org.apache.xpath.objects.XRTreeFrag
304    *
305    * @throws TransformerException
306    */

307   public XObject eval(
308           Node JavaDoc contextNode, String JavaDoc str, PrefixResolver prefixResolver)
309             throws TransformerException JavaDoc
310   {
311
312     // Since we don't have a XML Parser involved here, install some default support
313
// for things like namespaces, etc.
314
// (Changed from: XPathContext xpathSupport = new XPathContext();
315
// because XPathContext is weak in a number of areas... perhaps
316
// XPathContext should be done away with.)
317
// Create the XPath object.
318
XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
319
320     // Execute the XPath, and have it return the result
321
XPathContext xpathSupport = new XPathContext();
322     int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
323
324     return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
325   }
326 }
327
Popular Tags