KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xalan > internal > lib > Extensions


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: Extensions.java,v 1.29 2004/02/23 10:29:34 aruny Exp $
18  */

19 package com.sun.org.apache.xalan.internal.lib;
20
21 import java.util.Hashtable JavaDoc;
22 import java.util.StringTokenizer JavaDoc;
23
24 import javax.xml.parsers.DocumentBuilder JavaDoc;
25 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
26 import javax.xml.parsers.ParserConfigurationException JavaDoc;
27
28 import com.sun.org.apache.xalan.internal.extensions.ExpressionContext;
29 import com.sun.org.apache.xalan.internal.xslt.EnvironmentCheck;
30 import com.sun.org.apache.xpath.internal.NodeSet;
31 import com.sun.org.apache.xpath.internal.objects.XBoolean;
32 import com.sun.org.apache.xpath.internal.objects.XNumber;
33 import com.sun.org.apache.xpath.internal.objects.XObject;
34
35 import org.w3c.dom.Document JavaDoc;
36 import org.w3c.dom.DocumentFragment JavaDoc;
37 import org.w3c.dom.Node JavaDoc;
38 import org.w3c.dom.NodeList JavaDoc;
39 import org.w3c.dom.Text JavaDoc;
40 import org.w3c.dom.traversal.NodeIterator;
41
42 import org.xml.sax.SAXNotSupportedException JavaDoc;
43
44 /**
45  * This class contains many of the Xalan-supplied extensions.
46  * It is accessed by specifying a namespace URI as follows:
47  * <pre>
48  * xmlns:xalan="http://xml.apache.org/xalan"
49  * </pre>
50  * @xsl.usage general
51  */

52 public class Extensions
53 {
54   /**
55    * Constructor Extensions
56    *
57    */

58   private Extensions(){} // Make sure class cannot be instantiated
59

60   /**
61    * This method is an extension that implements as a Xalan extension
62    * the node-set function also found in xt and saxon.
63    * If the argument is a Result Tree Fragment, then <code>nodeset</code>
64    * returns a node-set consisting of a single root node as described in
65    * section 11.1 of the XSLT 1.0 Recommendation. If the argument is a
66    * node-set, <code>nodeset</code> returns a node-set. If the argument
67    * is a string, number, or boolean, then <code>nodeset</code> returns
68    * a node-set consisting of a single root node with a single text node
69    * child that is the result of calling the XPath string() function on the
70    * passed parameter. If the argument is anything else, then a node-set
71    * is returned consisting of a single root node with a single text node
72    * child that is the result of calling the java <code>toString()</code>
73    * method on the passed argument.
74    * Most of the
75    * actual work here is done in <code>MethodResolver</code> and
76    * <code>XRTreeFrag</code>.
77    * @param myProcessor Context passed by the extension processor
78    * @param rtf Argument in the stylesheet to the nodeset extension function
79    *
80    * NEEDSDOC ($objectName$) @return
81    */

82   public static NodeSet nodeset(ExpressionContext myProcessor, Object JavaDoc rtf)
83   {
84
85     String JavaDoc textNodeValue;
86
87     if (rtf instanceof NodeIterator)
88     {
89       return new NodeSet((NodeIterator) rtf);
90     }
91     else
92     {
93       if (rtf instanceof String JavaDoc)
94       {
95         textNodeValue = (String JavaDoc) rtf;
96       }
97       else if (rtf instanceof Boolean JavaDoc)
98       {
99         textNodeValue = new XBoolean(((Boolean JavaDoc) rtf).booleanValue()).str();
100       }
101       else if (rtf instanceof Double JavaDoc)
102       {
103         textNodeValue = new XNumber(((Double JavaDoc) rtf).doubleValue()).str();
104       }
105       else
106       {
107         textNodeValue = rtf.toString();
108       }
109
110       // This no longer will work right since the DTM.
111
// Document myDoc = myProcessor.getContextNode().getOwnerDocument();
112
try
113       {
114         DocumentBuilderFactory JavaDoc dbf = DocumentBuilderFactory.newInstance();
115         DocumentBuilder JavaDoc db = dbf.newDocumentBuilder();
116         Document JavaDoc myDoc = db.newDocument();
117         
118         Text JavaDoc textNode = myDoc.createTextNode(textNodeValue);
119         DocumentFragment JavaDoc docFrag = myDoc.createDocumentFragment();
120   
121         docFrag.appendChild(textNode);
122   
123         return new NodeSet(docFrag);
124       }
125       catch(ParserConfigurationException JavaDoc pce)
126       {
127         throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(pce);
128       }
129     }
130   }
131
132   /**
133    * Returns the intersection of two node-sets.
134    *
135    * @param nl1 NodeList for first node-set
136    * @param nl2 NodeList for second node-set
137    * @return a NodeList containing the nodes in nl1 that are also in nl2
138    *
139    * Note: The usage of this extension function in the xalan namespace
140    * is deprecated. Please use the same function in the EXSLT sets extension
141    * (http://exslt.org/sets).
142    */

143   public static NodeList JavaDoc intersection(NodeList JavaDoc nl1, NodeList JavaDoc nl2)
144   {
145     return ExsltSets.intersection(nl1, nl2);
146   }
147
148   /**
149    * Returns the difference between two node-sets.
150    *
151    * @param nl1 NodeList for first node-set
152    * @param nl2 NodeList for second node-set
153    * @return a NodeList containing the nodes in nl1 that are not in nl2
154    *
155    * Note: The usage of this extension function in the xalan namespace
156    * is deprecated. Please use the same function in the EXSLT sets extension
157    * (http://exslt.org/sets).
158    */

159   public static NodeList JavaDoc difference(NodeList JavaDoc nl1, NodeList JavaDoc nl2)
160   {
161     return ExsltSets.difference(nl1, nl2);
162   }
163
164   /**
165    * Returns node-set containing distinct string values.
166    *
167    * @param nl NodeList for node-set
168    * @return a NodeList with nodes from nl containing distinct string values.
169    * In other words, if more than one node in nl contains the same string value,
170    * only include the first such node found.
171    *
172    * Note: The usage of this extension function in the xalan namespace
173    * is deprecated. Please use the same function in the EXSLT sets extension
174    * (http://exslt.org/sets).
175    */

176   public static NodeList JavaDoc distinct(NodeList JavaDoc nl)
177   {
178     return ExsltSets.distinct(nl);
179   }
180
181   /**
182    * Returns true if both node-sets contain the same set of nodes.
183    *
184    * @param nl1 NodeList for first node-set
185    * @param nl2 NodeList for second node-set
186    * @return true if nl1 and nl2 contain exactly the same set of nodes.
187    */

188   public static boolean hasSameNodes(NodeList JavaDoc nl1, NodeList JavaDoc nl2)
189   {
190
191     NodeSet ns1 = new NodeSet(nl1);
192     NodeSet ns2 = new NodeSet(nl2);
193
194     if (ns1.getLength() != ns2.getLength())
195       return false;
196
197     for (int i = 0; i < ns1.getLength(); i++)
198     {
199       Node JavaDoc n = ns1.elementAt(i);
200
201       if (!ns2.contains(n))
202         return false;
203     }
204
205     return true;
206   }
207
208   /**
209    * Returns the result of evaluating the argument as a string containing
210    * an XPath expression. Used where the XPath expression is not known until
211    * run-time. The expression is evaluated as if the run-time value of the
212    * argument appeared in place of the evaluate function call at compile time.
213    *
214    * @param myContext an <code>ExpressionContext</code> passed in by the
215    * extension mechanism. This must be an XPathContext.
216    * @param xpathExtr The XPath expression to be evaluated.
217    * @return the XObject resulting from evaluating the XPath
218    *
219    * @throws SAXNotSupportedException
220    *
221    * Note: The usage of this extension function in the xalan namespace
222    * is deprecated. Please use the same function in the EXSLT dynamic extension
223    * (http://exslt.org/dynamic).
224    */

225   public static XObject evaluate(ExpressionContext myContext, String JavaDoc xpathExpr)
226          throws SAXNotSupportedException JavaDoc
227   {
228     return ExsltDynamic.evaluate(myContext, xpathExpr);
229   }
230
231   /**
232    * Returns a NodeSet containing one text node for each token in the first argument.
233    * Delimiters are specified in the second argument.
234    * Tokens are determined by a call to <code>StringTokenizer</code>.
235    * If the first argument is an empty string or contains only delimiters, the result
236    * will be an empty NodeSet.
237    *
238    * Contributed to XalanJ1 by <a HREF="mailto:benoit.cerrina@writeme.com">Benoit Cerrina</a>.
239    *
240    * @param myContext an <code>ExpressionContext</code> passed in by the
241    * extension mechanism. This must be an XPathContext.
242    * @param toTokenize The string to be split into text tokens.
243    * @param delims The delimiters to use.
244    * @return a NodeSet as described above.
245    */

246   public static NodeList JavaDoc tokenize(String JavaDoc toTokenize, String JavaDoc delims)
247   {
248
249     Document JavaDoc doc = DocumentHolder.m_doc;
250
251
252     StringTokenizer JavaDoc lTokenizer = new StringTokenizer JavaDoc(toTokenize, delims);
253     NodeSet resultSet = new NodeSet();
254
255     synchronized (doc)
256     {
257       while (lTokenizer.hasMoreTokens())
258       {
259         resultSet.addNode(doc.createTextNode(lTokenizer.nextToken()));
260       }
261     }
262
263     return resultSet;
264   }
265
266   /**
267    * Returns a NodeSet containing one text node for each token in the first argument.
268    * Delimiters are whitespace. That is, the delimiters that are used are tab (&#x09),
269    * linefeed (&#x0A), return (&#x0D), and space (&#x20).
270    * Tokens are determined by a call to <code>StringTokenizer</code>.
271    * If the first argument is an empty string or contains only delimiters, the result
272    * will be an empty NodeSet.
273    *
274    * Contributed to XalanJ1 by <a HREF="mailto:benoit.cerrina@writeme.com">Benoit Cerrina</a>.
275    *
276    * @param myContext an <code>ExpressionContext</code> passed in by the
277    * extension mechanism. This must be an XPathContext.
278    * @param toTokenize The string to be split into text tokens.
279    * @return a NodeSet as described above.
280    */

281   public static NodeList JavaDoc tokenize(String JavaDoc toTokenize)
282   {
283     return tokenize(toTokenize, " \t\n\r");
284   }
285
286   /**
287    * Return a Node of basic debugging information from the
288    * EnvironmentCheck utility about the Java environment.
289    *
290    * <p>Simply calls the {@link com.sun.org.apache.xalan.internal.xslt.EnvironmentCheck}
291    * utility to grab info about the Java environment and CLASSPATH,
292    * etc., and then returns the resulting Node. Stylesheets can
293    * then maniuplate this data or simply xsl:copy-of the Node. Note
294    * that we first attempt to load the more advanced
295    * org.apache.env.Which utility by reflection; only if that fails
296    * to we still use the internal version. Which is available from
297    * <a HREF="http://xml.apache.org/commons/">http://xml.apache.org/commons/</a>.</p>
298    *
299    * <p>We throw a WrappedRuntimeException in the unlikely case
300    * that reading information from the environment throws us an
301    * exception. (Is this really the best thing to do?)</p>
302    *
303    * @param myContext an <code>ExpressionContext</code> passed in by the
304    * extension mechanism. This must be an XPathContext.
305    * @return a Node as described above.
306    */

307   public static Node JavaDoc checkEnvironment(ExpressionContext myContext)
308   {
309
310     Document JavaDoc factoryDocument;
311     try
312     {
313       DocumentBuilderFactory JavaDoc dbf = DocumentBuilderFactory.newInstance();
314       DocumentBuilder JavaDoc db = dbf.newDocumentBuilder();
315       factoryDocument = db.newDocument();
316     }
317     catch(ParserConfigurationException JavaDoc pce)
318     {
319       throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(pce);
320     }
321
322     Node JavaDoc resultNode = null;
323     try
324     {
325       // First use reflection to try to load Which, which is a
326
// better version of EnvironmentCheck
327
resultNode = checkEnvironmentUsingWhich(myContext, factoryDocument);
328
329       if (null != resultNode)
330         return resultNode;
331
332       // If reflection failed, fallback to our internal EnvironmentCheck
333
EnvironmentCheck envChecker = new EnvironmentCheck();
334       Hashtable JavaDoc h = envChecker.getEnvironmentHash();
335       resultNode = factoryDocument.createElement("checkEnvironmentExtension");
336       envChecker.appendEnvironmentReport(resultNode, factoryDocument, h);
337       envChecker = null;
338     }
339     catch(Exception JavaDoc e)
340     {
341       throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
342     }
343
344     return resultNode;
345   }
346
347   /**
348    * Private worker method to attempt to use org.apache.env.Which.
349    *
350    * @param myContext an <code>ExpressionContext</code> passed in by the
351    * extension mechanism. This must be an XPathContext.
352    * @param factoryDocument providing createElement services, etc.
353    * @return a Node with environment info; null if any error
354    */

355   private static Node JavaDoc checkEnvironmentUsingWhich(ExpressionContext myContext,
356         Document JavaDoc factoryDocument)
357   {
358     final String JavaDoc WHICH_CLASSNAME = "org.apache.env.Which";
359     final String JavaDoc WHICH_METHODNAME = "which";
360     final Class JavaDoc WHICH_METHOD_ARGS[] = { java.util.Hashtable JavaDoc.class,
361                                         java.lang.String JavaDoc.class,
362                                         java.lang.String JavaDoc.class };
363     try
364     {
365       // Use reflection to try to find xml-commons utility 'Which'
366
Class JavaDoc clazz = ObjectFactory.findProviderClass(
367         WHICH_CLASSNAME, ObjectFactory.findClassLoader(), true);
368       if (null == clazz)
369         return null;
370         
371       // Fully qualify names since this is the only method they're used in
372
java.lang.reflect.Method JavaDoc method = clazz.getMethod(WHICH_METHODNAME, WHICH_METHOD_ARGS);
373       Hashtable JavaDoc report = new Hashtable JavaDoc();
374
375       // Call the method with our Hashtable, common options, and ignore return value
376
Object JavaDoc[] methodArgs = { report, "XmlCommons;Xalan;Xerces;Crimson;Ant", "" };
377       Object JavaDoc returnValue = method.invoke(null, methodArgs);
378
379       // Create a parent to hold the report and append hash to it
380
Node JavaDoc resultNode = factoryDocument.createElement("checkEnvironmentExtension");
381       com.sun.org.apache.xml.internal.utils.Hashtree2Node.appendHashToNode(report, "whichReport",
382             resultNode, factoryDocument);
383
384       return resultNode;
385     }
386     catch (Throwable JavaDoc t)
387     {
388       // Simply return null; no need to report error
389
return null;
390     }
391   }
392   
393     /**
394      * This class is not loaded until first referenced (see Java Language
395      * Specification by Gosling/Joy/Steele, section 12.4.1)
396      *
397      * The static members are created when this class is first referenced, as a
398      * lazy initialization not needing checking against null or any
399      * synchronization.
400      *
401      */

402     private static class DocumentHolder
403     {
404         // Reuse the Document object to reduce memory usage.
405
private static final Document JavaDoc m_doc;
406         static
407         {
408             try
409             {
410                 m_doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
411             }
412
413             catch(ParserConfigurationException JavaDoc pce)
414             {
415                   throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(pce);
416             }
417
418         }
419     }
420 }
421
Popular Tags