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