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