001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: XPathAPI.java 524807 2007-04-02 15:51:43Z zongaro $ 020 */ 021 package org.apache.xpath; 022 023 import javax.xml.transform.TransformerException; 024 025 import org.apache.xml.utils.PrefixResolver; 026 import org.apache.xml.utils.PrefixResolverDefault; 027 import org.apache.xpath.objects.XObject; 028 029 import org.w3c.dom.Document; 030 import org.w3c.dom.Node; 031 import org.w3c.dom.NodeList; 032 import org.w3c.dom.traversal.NodeIterator; 033 034 /** 035 * The methods in this class are convenience methods into the 036 * low-level XPath API. 037 * These functions tend to be a little slow, since a number of objects must be 038 * created for each evaluation. A faster way is to precompile the 039 * XPaths using the low-level API, and then just use the XPaths 040 * over and over. 041 * 042 * NOTE: In particular, each call to this method will create a new 043 * XPathContext, a new DTMManager... and thus a new DTM. That's very 044 * safe, since it guarantees that you're always processing against a 045 * fully up-to-date view of your document. But it's also portentially 046 * very expensive, since you're rebuilding the DTM every time. You should 047 * consider using an instance of CachedXPathAPI rather than these static 048 * methods. 049 * 050 * @see <a href="http://www.w3.org/TR/xpath">XPath Specification</a> 051 * */ 052 public class XPathAPI 053 { 054 055 /** 056 * Use an XPath string to select a single node. XPath namespace 057 * prefixes are resolved from the context node, which may not 058 * be what you want (see the next method). 059 * 060 * @param contextNode The node to start searching from. 061 * @param str A valid XPath string. 062 * @return The first node found that matches the XPath, or null. 063 * 064 * @throws TransformerException 065 */ 066 public static Node selectSingleNode(Node contextNode, String str) 067 throws TransformerException 068 { 069 return selectSingleNode(contextNode, str, contextNode); 070 } 071 072 /** 073 * Use an XPath string to select a single node. 074 * XPath namespace prefixes are resolved from the namespaceNode. 075 * 076 * @param contextNode The node to start searching from. 077 * @param str A valid XPath string. 078 * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces. 079 * @return The first node found that matches the XPath, or null. 080 * 081 * @throws TransformerException 082 */ 083 public static Node selectSingleNode( 084 Node contextNode, String str, Node namespaceNode) 085 throws TransformerException 086 { 087 088 // Have the XObject return its result as a NodeSetDTM. 089 NodeIterator nl = selectNodeIterator(contextNode, str, namespaceNode); 090 091 // Return the first node, or null 092 return nl.nextNode(); 093 } 094 095 /** 096 * Use an XPath string to select a nodelist. 097 * XPath namespace prefixes are resolved from the contextNode. 098 * 099 * @param contextNode The node to start searching from. 100 * @param str A valid XPath string. 101 * @return A NodeIterator, should never be null. 102 * 103 * @throws TransformerException 104 */ 105 public static NodeIterator selectNodeIterator(Node contextNode, String str) 106 throws TransformerException 107 { 108 return selectNodeIterator(contextNode, str, contextNode); 109 } 110 111 /** 112 * Use an XPath string to select a nodelist. 113 * XPath namespace prefixes are resolved from the namespaceNode. 114 * 115 * @param contextNode The node to start searching from. 116 * @param str A valid XPath string. 117 * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces. 118 * @return A NodeIterator, should never be null. 119 * 120 * @throws TransformerException 121 */ 122 public static NodeIterator selectNodeIterator( 123 Node contextNode, String str, Node namespaceNode) 124 throws TransformerException 125 { 126 127 // Execute the XPath, and have it return the result 128 XObject list = eval(contextNode, str, namespaceNode); 129 130 // Have the XObject return its result as a NodeSetDTM. 131 return list.nodeset(); 132 } 133 134 /** 135 * Use an XPath string to select a nodelist. 136 * XPath namespace prefixes are resolved from the contextNode. 137 * 138 * @param contextNode The node to start searching from. 139 * @param str A valid XPath string. 140 * @return A NodeIterator, should never be null. 141 * 142 * @throws TransformerException 143 */ 144 public static NodeList selectNodeList(Node contextNode, String str) 145 throws TransformerException 146 { 147 return selectNodeList(contextNode, str, contextNode); 148 } 149 150 /** 151 * Use an XPath string to select a nodelist. 152 * XPath namespace prefixes are resolved from the namespaceNode. 153 * 154 * @param contextNode The node to start searching from. 155 * @param str A valid XPath string. 156 * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces. 157 * @return A NodeIterator, should never be null. 158 * 159 * @throws TransformerException 160 */ 161 public static NodeList selectNodeList( 162 Node contextNode, String str, Node namespaceNode) 163 throws TransformerException 164 { 165 166 // Execute the XPath, and have it return the result 167 XObject list = eval(contextNode, str, namespaceNode); 168 169 // Return a NodeList. 170 return list.nodelist(); 171 } 172 173 /** 174 * Evaluate XPath string to an XObject. Using this method, 175 * XPath namespace prefixes will be resolved from the namespaceNode. 176 * @param contextNode The node to start searching from. 177 * @param str A valid XPath string. 178 * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null. 179 * @see org.apache.xpath.objects.XObject 180 * @see org.apache.xpath.objects.XNull 181 * @see org.apache.xpath.objects.XBoolean 182 * @see org.apache.xpath.objects.XNumber 183 * @see org.apache.xpath.objects.XString 184 * @see org.apache.xpath.objects.XRTreeFrag 185 * 186 * @throws TransformerException 187 */ 188 public static XObject eval(Node contextNode, String str) 189 throws TransformerException 190 { 191 return eval(contextNode, str, 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 str A valid XPath string. 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 org.apache.xpath.objects.XObject 206 * @see org.apache.xpath.objects.XNull 207 * @see org.apache.xpath.objects.XBoolean 208 * @see org.apache.xpath.objects.XNumber 209 * @see org.apache.xpath.objects.XString 210 * @see org.apache.xpath.objects.XRTreeFrag 211 * 212 * @throws TransformerException 213 */ 214 public static XObject eval(Node contextNode, String str, Node namespaceNode) 215 throws TransformerException 216 { 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 // Create an XPathContext that doesn't support pushing and popping of 224 // variable resolution scopes. Sufficient for simple XPath 1.0 expressions. 225 XPathContext xpathSupport = new XPathContext(false); 226 227 // Create an object to resolve namespace prefixes. 228 // XPath namespaces are resolved from the input context node's document element 229 // if it is a root node, or else the current context node (for lack of a better 230 // resolution space, given the simplicity of this sample code). 231 PrefixResolverDefault prefixResolver = new PrefixResolverDefault( 232 (namespaceNode.getNodeType() == Node.DOCUMENT_NODE) 233 ? ((Document) namespaceNode).getDocumentElement() : namespaceNode); 234 235 // Create the XPath object. 236 XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null); 237 238 // Execute the XPath, and have it return the result 239 // return xpath.execute(xpathSupport, contextNode, prefixResolver); 240 int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode); 241 242 return xpath.execute(xpathSupport, ctxtNode, prefixResolver); 243 } 244 245 /** 246 * Evaluate XPath string to an XObject. 247 * XPath namespace prefixes are resolved from the namespaceNode. 248 * The implementation of this is a little slow, since it creates 249 * a number of objects each time it is called. This could be optimized 250 * to keep the same objects around, but then thread-safety issues would arise. 251 * 252 * @param contextNode The node to start searching from. 253 * @param str A valid XPath string. 254 * @param prefixResolver Will be called if the parser encounters namespace 255 * prefixes, to resolve the prefixes to URLs. 256 * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null. 257 * @see org.apache.xpath.objects.XObject 258 * @see org.apache.xpath.objects.XNull 259 * @see org.apache.xpath.objects.XBoolean 260 * @see org.apache.xpath.objects.XNumber 261 * @see org.apache.xpath.objects.XString 262 * @see org.apache.xpath.objects.XRTreeFrag 263 * 264 * @throws TransformerException 265 */ 266 public static XObject eval( 267 Node contextNode, String str, PrefixResolver prefixResolver) 268 throws TransformerException 269 { 270 271 // Since we don't have a XML Parser involved here, install some default support 272 // for things like namespaces, etc. 273 // (Changed from: XPathContext xpathSupport = new XPathContext(); 274 // because XPathContext is weak in a number of areas... perhaps 275 // XPathContext should be done away with.) 276 // Create the XPath object. 277 XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null); 278 279 // Create an XPathContext that doesn't support pushing and popping of 280 // variable resolution scopes. Sufficient for simple XPath 1.0 expressions. 281 XPathContext xpathSupport = new XPathContext(false); 282 283 // Execute the XPath, and have it return the result 284 int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode); 285 286 return xpath.execute(xpathSupport, ctxtNode, prefixResolver); 287 } 288 }