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: XPathAPI.java,v 1.17 2004/02/17 04:30:02 minchau Exp $
  18. */
  19. package com.sun.org.apache.xpath.internal;
  20. import javax.xml.transform.TransformerException;
  21. import com.sun.org.apache.xml.internal.utils.PrefixResolver;
  22. import com.sun.org.apache.xml.internal.utils.PrefixResolverDefault;
  23. import com.sun.org.apache.xpath.internal.objects.XObject;
  24. import org.w3c.dom.Document;
  25. import org.w3c.dom.Node;
  26. import org.w3c.dom.NodeList;
  27. import org.w3c.dom.traversal.NodeIterator;
  28. /**
  29. * The methods in this class are convenience methods into the
  30. * low-level XPath API.
  31. * These functions tend to be a little slow, since a number of objects must be
  32. * created for each evaluation. A faster way is to precompile the
  33. * XPaths using the low-level API, and then just use the XPaths
  34. * over and over.
  35. *
  36. * NOTE: In particular, each call to this method will create a new
  37. * XPathContext, a new DTMManager... and thus a new DTM. That's very
  38. * safe, since it guarantees that you're always processing against a
  39. * fully up-to-date view of your document. But it's also portentially
  40. * very expensive, since you're rebuilding the DTM every time. You should
  41. * consider using an instance of CachedXPathAPI rather than these static
  42. * methods.
  43. *
  44. * @see <a href="http://www.w3.org/TR/xpath">XPath Specification</a>
  45. * */
  46. public class XPathAPI
  47. {
  48. /**
  49. * Use an XPath string to select a single node. XPath namespace
  50. * prefixes are resolved from the context node, which may not
  51. * be what you want (see the next method).
  52. *
  53. * @param contextNode The node to start searching from.
  54. * @param str A valid XPath string.
  55. * @return The first node found that matches the XPath, or null.
  56. *
  57. * @throws TransformerException
  58. */
  59. public static Node selectSingleNode(Node contextNode, String str)
  60. throws TransformerException
  61. {
  62. return selectSingleNode(contextNode, str, contextNode);
  63. }
  64. /**
  65. * Use an XPath string to select a single node.
  66. * XPath namespace prefixes are resolved from the namespaceNode.
  67. *
  68. * @param contextNode The node to start searching from.
  69. * @param str A valid XPath string.
  70. * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
  71. * @return The first node found that matches the XPath, or null.
  72. *
  73. * @throws TransformerException
  74. */
  75. public static Node selectSingleNode(
  76. Node contextNode, String str, Node namespaceNode)
  77. throws TransformerException
  78. {
  79. // Have the XObject return its result as a NodeSetDTM.
  80. NodeIterator nl = selectNodeIterator(contextNode, str, namespaceNode);
  81. // Return the first node, or null
  82. return nl.nextNode();
  83. }
  84. /**
  85. * Use an XPath string to select a nodelist.
  86. * XPath namespace prefixes are resolved from the contextNode.
  87. *
  88. * @param contextNode The node to start searching from.
  89. * @param str A valid XPath string.
  90. * @return A NodeIterator, should never be null.
  91. *
  92. * @throws TransformerException
  93. */
  94. public static NodeIterator selectNodeIterator(Node contextNode, String str)
  95. throws TransformerException
  96. {
  97. return selectNodeIterator(contextNode, str, contextNode);
  98. }
  99. /**
  100. * Use an XPath string to select a nodelist.
  101. * XPath namespace prefixes are resolved from the namespaceNode.
  102. *
  103. * @param contextNode The node to start searching from.
  104. * @param str A valid XPath string.
  105. * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
  106. * @return A NodeIterator, should never be null.
  107. *
  108. * @throws TransformerException
  109. */
  110. public static NodeIterator selectNodeIterator(
  111. Node contextNode, String str, Node namespaceNode)
  112. throws TransformerException
  113. {
  114. // Execute the XPath, and have it return the result
  115. XObject list = eval(contextNode, str, namespaceNode);
  116. // Have the XObject return its result as a NodeSetDTM.
  117. return list.nodeset();
  118. }
  119. /**
  120. * Use an XPath string to select a nodelist.
  121. * XPath namespace prefixes are resolved from the contextNode.
  122. *
  123. * @param contextNode The node to start searching from.
  124. * @param str A valid XPath string.
  125. * @return A NodeIterator, should never be null.
  126. *
  127. * @throws TransformerException
  128. */
  129. public static NodeList selectNodeList(Node contextNode, String str)
  130. throws TransformerException
  131. {
  132. return selectNodeList(contextNode, str, contextNode);
  133. }
  134. /**
  135. * Use an XPath string to select a nodelist.
  136. * XPath namespace prefixes are resolved from the namespaceNode.
  137. *
  138. * @param contextNode The node to start searching from.
  139. * @param str A valid XPath string.
  140. * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
  141. * @return A NodeIterator, should never be null.
  142. *
  143. * @throws TransformerException
  144. */
  145. public static NodeList selectNodeList(
  146. Node contextNode, String str, Node namespaceNode)
  147. throws TransformerException
  148. {
  149. // Execute the XPath, and have it return the result
  150. XObject list = eval(contextNode, str, namespaceNode);
  151. // Return a NodeList.
  152. return list.nodelist();
  153. }
  154. /**
  155. * Evaluate XPath string to an XObject. Using this method,
  156. * XPath namespace prefixes will be resolved from the namespaceNode.
  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 An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
  161. * @see com.sun.org.apache.xpath.internal.objects.XObject
  162. * @see com.sun.org.apache.xpath.internal.objects.XNull
  163. * @see com.sun.org.apache.xpath.internal.objects.XBoolean
  164. * @see com.sun.org.apache.xpath.internal.objects.XNumber
  165. * @see com.sun.org.apache.xpath.internal.objects.XString
  166. * @see com.sun.org.apache.xpath.internal.objects.XRTreeFrag
  167. *
  168. * @throws TransformerException
  169. */
  170. public static XObject eval(Node contextNode, String str)
  171. throws TransformerException
  172. {
  173. return eval(contextNode, str, contextNode);
  174. }
  175. /**
  176. * Evaluate XPath string to an XObject.
  177. * XPath namespace prefixes are resolved from the namespaceNode.
  178. * The implementation of this is a little slow, since it creates
  179. * a number of objects each time it is called. This could be optimized
  180. * to keep the same objects around, but then thread-safety issues would arise.
  181. *
  182. * @param contextNode The node to start searching from.
  183. * @param str A valid XPath string.
  184. * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
  185. * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
  186. * @see com.sun.org.apache.xpath.internal.objects.XObject
  187. * @see com.sun.org.apache.xpath.internal.objects.XNull
  188. * @see com.sun.org.apache.xpath.internal.objects.XBoolean
  189. * @see com.sun.org.apache.xpath.internal.objects.XNumber
  190. * @see com.sun.org.apache.xpath.internal.objects.XString
  191. * @see com.sun.org.apache.xpath.internal.objects.XRTreeFrag
  192. *
  193. * @throws TransformerException
  194. */
  195. public static XObject eval(Node contextNode, String str, Node namespaceNode)
  196. throws TransformerException
  197. {
  198. // Since we don't have a XML Parser involved here, install some default support
  199. // for things like namespaces, etc.
  200. // (Changed from: XPathContext xpathSupport = new XPathContext();
  201. // because XPathContext is weak in a number of areas... perhaps
  202. // XPathContext should be done away with.)
  203. XPathContext xpathSupport = new XPathContext();
  204. // Create an object to resolve namespace prefixes.
  205. // XPath namespaces are resolved from the input context node's document element
  206. // if it is a root node, or else the current context node (for lack of a better
  207. // resolution space, given the simplicity of this sample code).
  208. PrefixResolverDefault prefixResolver = new PrefixResolverDefault(
  209. (namespaceNode.getNodeType() == Node.DOCUMENT_NODE)
  210. ? ((Document) namespaceNode).getDocumentElement() : namespaceNode);
  211. // Create the XPath object.
  212. XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
  213. // Execute the XPath, and have it return the result
  214. // return xpath.execute(xpathSupport, contextNode, prefixResolver);
  215. int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
  216. return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
  217. }
  218. /**
  219. * Evaluate XPath string to an XObject.
  220. * XPath namespace prefixes are resolved from the namespaceNode.
  221. * The implementation of this is a little slow, since it creates
  222. * a number of objects each time it is called. This could be optimized
  223. * to keep the same objects around, but then thread-safety issues would arise.
  224. *
  225. * @param contextNode The node to start searching from.
  226. * @param str A valid XPath string.
  227. * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
  228. * @param prefixResolver Will be called if the parser encounters namespace
  229. * prefixes, to resolve the prefixes to URLs.
  230. * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
  231. * @see com.sun.org.apache.xpath.internal.objects.XObject
  232. * @see com.sun.org.apache.xpath.internal.objects.XNull
  233. * @see com.sun.org.apache.xpath.internal.objects.XBoolean
  234. * @see com.sun.org.apache.xpath.internal.objects.XNumber
  235. * @see com.sun.org.apache.xpath.internal.objects.XString
  236. * @see com.sun.org.apache.xpath.internal.objects.XRTreeFrag
  237. *
  238. * @throws TransformerException
  239. */
  240. public static XObject eval(
  241. Node contextNode, String str, PrefixResolver prefixResolver)
  242. throws TransformerException
  243. {
  244. // Since we don't have a XML Parser involved here, install some default support
  245. // for things like namespaces, etc.
  246. // (Changed from: XPathContext xpathSupport = new XPathContext();
  247. // because XPathContext is weak in a number of areas... perhaps
  248. // XPathContext should be done away with.)
  249. // Create the XPath object.
  250. XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
  251. // Execute the XPath, and have it return the result
  252. XPathContext xpathSupport = new XPathContext();
  253. int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
  254. return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
  255. }
  256. }