KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > XSLTProcessorApplet


1 package com.icl.saxon;
2
3 // This code is adapted, with very minor modifications, from
4
// org.apache.xalan.client.XSLTProcessorApplet
5
// It should now run with any TrAX-conformant processor
6
// - Michael Kay, February 2001
7

8 /*
9  * The Apache Software License, Version 1.1
10  *
11  *
12  * Copyright (c) 1999 The Apache Software Foundation. All rights
13  * reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  *
19  * 1. Redistributions of source code must retain the above copyright
20  * notice, this list of conditions and the following disclaimer.
21  *
22  * 2. Redistributions in binary form must reproduce the above copyright
23  * notice, this list of conditions and the following disclaimer in
24  * the documentation and/or other materials provided with the
25  * distribution.
26  *
27  * 3. The end-user documentation included with the redistribution,
28  * if any, must include the following acknowledgment:
29  * "This product includes software developed by the
30  * Apache Software Foundation (http://www.apache.org/)."
31  * Alternately, this acknowledgment may appear in the software itself,
32  * if and wherever such third-party acknowledgments normally appear.
33  *
34  * 4. The names "Xalan" and "Apache Software Foundation" must
35  * not be used to endorse or promote products derived from this
36  * software without prior written permission. For written
37  * permission, please contact apache@apache.org.
38  *
39  * 5. Products derived from this software may not be called "Apache",
40  * nor may "Apache" appear in their name, without prior written
41  * permission of the Apache Software Foundation.
42  *
43  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
44  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
45  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
46  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
47  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
50  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
51  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
52  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
53  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54  * SUCH DAMAGE.
55  * ====================================================================
56  *
57  * This software consists of voluntary contributions made by many
58  * individuals on behalf of the Apache Software Foundation and was
59  * originally based on software copyright (c) 1999, Lotus
60  * Development Corporation., http://www.lotus.com. For more
61  * information on the Apache Software Foundation, please see
62  * <http://www.apache.org/>.
63  */

64
65 import java.applet.Applet JavaDoc;
66
67 import java.awt.Graphics JavaDoc;
68
69 import java.net.URL JavaDoc;
70 import java.net.MalformedURLException JavaDoc;
71
72 import java.io.PrintWriter JavaDoc;
73 import java.io.StringWriter JavaDoc;
74 import java.io.StringReader JavaDoc;
75 import java.io.IOException JavaDoc;
76 import java.io.InputStream JavaDoc;
77
78 import java.util.Properties JavaDoc;
79
80 // Needed Xalan classes
81
// import org.apache.xalan.res.XSLMessages;
82
// import org.apache.xalan.res.XSLTErrorResources;
83

84 // Needed TRaX classes
85
import javax.xml.transform.Result JavaDoc;
86 import javax.xml.transform.TransformerFactory JavaDoc;
87 import javax.xml.transform.TransformerConfigurationException JavaDoc;
88 import javax.xml.transform.Transformer JavaDoc;
89 import javax.xml.transform.TransformerException JavaDoc;
90 import javax.xml.transform.Templates JavaDoc;
91 import javax.xml.transform.Source JavaDoc;
92 import javax.xml.transform.Result JavaDoc;
93 import javax.xml.transform.stream.StreamResult JavaDoc;
94 import javax.xml.transform.stream.StreamSource JavaDoc;
95
96 /**
97  * <meta name="usage" content="general"/>
98  * Provides applet host for the XSLT processor. To perform transformations on an HTML client:
99  * <ol>
100  * <li>Use an &lt;applet&gt; tag to embed this applet in the HTML client.</li>
101  * <li>Use the DocumentURL and StyleURL PARAM tags or the {@link #setDocumentURL} and
102  * {@link #setStyleURL} methods to specify the XML source document and XSL stylesheet.</li>
103  * <li>Call the {@link #getHtmlText} method (or one of the transformToHtml() methods)
104  * to perform the transformation and return the result as a String.</li>
105  * </ol>
106  */

107 public class XSLTProcessorApplet extends Applet JavaDoc
108 {
109
110   /**
111    * The stylesheet processor.
112    * @serial
113    */

114   TransformerFactory JavaDoc m_tfactory = null;
115
116   /**
117    * @serial
118    */

119   private String JavaDoc m_styleURL;
120
121   /**
122    * @serial
123    */

124   private String JavaDoc m_documentURL;
125
126   // Parameter names. To change a name of a parameter, you need only make
127
// a single change. Simply modify the value of the parameter string below.
128
//--------------------------------------------------------------------------
129

130   /**
131    * @serial
132    */

133   private final String JavaDoc PARAM_styleURL = "styleURL";
134
135   /**
136    * @serial
137    */

138   private final String JavaDoc PARAM_documentURL = "documentURL";
139
140
141   // We'll keep the DOM trees around, so tell which trees
142
// are cached.
143

144   /**
145    * @serial
146    */

147   private String JavaDoc m_styleURLOfCached = null;
148
149   /**
150    * @serial
151    */

152   private String JavaDoc m_documentURLOfCached = null;
153
154   /**
155    * Save this for use on the worker thread; may not be necessary.
156    * @serial
157    */

158   private URL JavaDoc m_codeBase = null;
159   
160   /**
161    * @serial
162    */

163   private String JavaDoc m_treeURL = null;
164
165   /**
166    * DocumentBase URL
167    * @serial
168    */

169   private URL JavaDoc m_documentBase = null;
170
171   /**
172    * Thread stuff for the trusted worker thread.
173    */

174   transient private Thread JavaDoc m_callThread = null;
175
176   /**
177    */

178   transient private TrustedAgent m_trustedAgent = null;
179
180   /**
181    * Thread for running TrustedAgent.
182    */

183   transient private Thread JavaDoc m_trustedWorker = null;
184
185   /**
186    * Where the worker thread puts the HTML text.
187    */

188   transient private String JavaDoc m_htmlText = null;
189   
190   /**
191    * Where the worker thread puts the document/stylesheet text.
192    */

193   transient private String JavaDoc m_sourceText = null;
194   
195   /**
196    * Stylesheet attribute name and value that the caller can set.
197    */

198   transient private String JavaDoc m_nameOfIDAttrOfElemToModify = null;
199
200   /**
201    */

202   transient private String JavaDoc m_elemIdToModify = null;
203
204   /**
205    */

206   transient private String JavaDoc m_attrNameToSet = null;
207
208   /**
209    */

210   transient private String JavaDoc m_attrValueToSet = null;
211
212   /**
213    * The XSLTProcessorApplet constructor takes no arguments.
214    */

215   public XSLTProcessorApplet(){}
216
217   /**
218    * Get basic information about the applet
219    * @return A String with the applet name and author.
220    */

221   public String JavaDoc getAppletInfo()
222   {
223     return "Name: XSLTProcessorApplet\r\n" + "Author: Scott Boag";
224   }
225
226   /**
227    * Get descriptions of the applet parameters.
228    * @return A two-dimensional array of Strings with Name, Type, and Description
229    * for each parameter.
230    */

231   public String JavaDoc[][] getParameterInfo()
232   {
233
234     String JavaDoc[][] info =
235     {
236       { PARAM_styleURL, "String", "URL to an XSL stylesheet" },
237       { PARAM_documentURL, "String", "URL to an XML document" },
238     };
239
240     return info;
241   }
242
243   /**
244    * Standard applet initialization.
245    */

246   public void init()
247   {
248
249     // PARAMETER SUPPORT
250
// The following code retrieves the value of each parameter
251
// specified with the <PARAM> tag and stores it in a member
252
// variable.
253
//----------------------------------------------------------------------
254
String JavaDoc param;
255
256     // styleURL: Parameter description
257
//----------------------------------------------------------------------
258
param = getParameter(PARAM_styleURL);
259
260     if (param != null)
261       setStyleURL(param);
262
263     // documentURL: Parameter description
264
//----------------------------------------------------------------------
265
param = getParameter(PARAM_documentURL);
266
267     if (param != null)
268       setDocumentURL(param);
269
270     m_codeBase = this.getCodeBase();
271     m_documentBase = this.getDocumentBase();
272
273     // If you use a ResourceWizard-generated "control creator" class to
274
// arrange controls in your applet, you may want to call its
275
// CreateControls() method from within this method. Remove the following
276
// call to resize() before adding the call to CreateControls();
277
// CreateControls() does its own resizing.
278
//----------------------------------------------------------------------
279
resize(320, 240);
280   }
281   
282     /**
283    * Automatically called when the HTML client containing the applet loads.
284    * This method starts execution of the applet thread.
285    */

286   public void start()
287   {
288
289     m_trustedAgent = new TrustedAgent();
290     Thread JavaDoc currentThread = Thread.currentThread();
291     m_trustedWorker = new Thread JavaDoc(currentThread.getThreadGroup(),
292                                  m_trustedAgent);
293     m_trustedWorker.start();
294     try
295     {
296       m_tfactory = TransformerFactory.newInstance();
297       this.showStatus("Causing Transformer and Parser to Load and JIT...");
298
299       // Prime the pump so that subsequent transforms are faster.
300
StringReader JavaDoc xmlbuf = new StringReader JavaDoc("<?xml version='1.0'?><foo/>");
301       StringReader JavaDoc xslbuf = new StringReader JavaDoc(
302         "<?xml version='1.0'?><xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'><xsl:template match='foo'><out/></xsl:template></xsl:stylesheet>");
303       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(new StringWriter JavaDoc());
304
305       synchronized (m_tfactory)
306       {
307         Templates JavaDoc templates = m_tfactory.newTemplates(new StreamSource JavaDoc(xslbuf));
308         Transformer JavaDoc transformer = templates.newTransformer();
309         transformer.transform(new StreamSource JavaDoc(xmlbuf), new StreamResult JavaDoc(pw));
310       }
311       System.out.println("Primed the pump!");
312       this.showStatus("Ready to go!");
313     }
314     catch (Exception JavaDoc e)
315     {
316       this.showStatus("Could not prime the pump!");
317       System.out.println("Could not prime the pump!");
318       e.printStackTrace();
319     }
320   }
321
322   /**
323    * Do not call; this applet contains no UI or visual components.
324    *
325    */

326   public void paint(Graphics JavaDoc g){}
327   
328   /**
329    * Automatically called when the HTML page containing the applet is no longer
330    * on the screen. Stops execution of the applet thread.
331    */

332   public void stop()
333   {
334     if (null != m_trustedWorker)
335     {
336       m_trustedWorker.stop();
337
338       // m_trustedWorker.destroy();
339
m_trustedWorker = null;
340     }
341
342     m_styleURLOfCached = null;
343     m_documentURLOfCached = null;
344   }
345   
346   /**
347    * Cleanup; called when applet is terminated and unloaded.
348    */

349   public void destroy()
350   {
351     if (null != m_trustedWorker)
352     {
353       m_trustedWorker.stop();
354
355       // m_trustedWorker.destroy();
356
m_trustedWorker = null;
357     }
358     m_styleURLOfCached = null;
359     m_documentURLOfCached = null;
360   }
361
362   /**
363    * Set the URL to the XSL stylesheet that will be used
364    * to transform the input XML. No processing is done yet.
365    * @param urlString valid URL string for XSL stylesheet.
366    */

367   public void setStyleURL(String JavaDoc urlString)
368   {
369     m_styleURL = urlString;
370   }
371
372   /**
373    * Set the URL to the XML document that will be transformed
374    * with the XSL stylesheet. No processing is done yet.
375    * @param urlString valid URL string for XML document.
376    */

377   public void setDocumentURL(String JavaDoc urlString)
378   {
379     m_documentURL = urlString;
380   }
381
382   /**
383    * The processor keeps a cache of the source and
384    * style trees, so call this method if they have changed
385    * or you want to do garbage collection.
386    */

387   public void freeCache()
388   {
389     m_styleURLOfCached = null;
390     m_documentURLOfCached = null;
391   }
392
393   /**
394    * Set an attribute in the stylesheet, which gives the ability
395    * to have some dynamic selection control.
396    * @param nameOfIDAttrOfElemToModify The name of an attribute to search for a unique id.
397    * @param elemId The unique ID to look for.
398    * @param attrName Once the element is found, the name of the attribute to set.
399    * @param value The value to set the attribute to.
400    */

401   public void setStyleSheetAttribute(String JavaDoc nameOfIDAttrOfElemToModify,
402                                      String JavaDoc elemId, String JavaDoc attrName,
403                                      String JavaDoc value)
404   {
405     m_nameOfIDAttrOfElemToModify = nameOfIDAttrOfElemToModify;
406     m_elemIdToModify = elemId;
407     m_attrNameToSet = attrName;
408     m_attrValueToSet = value;
409   }
410
411   /**
412    * Stylesheet parameter key
413    */

414   transient String JavaDoc m_key;
415
416   /**
417    * Stylesheet parameter value
418    */

419   transient String JavaDoc m_expression;
420
421   /**
422    * Submit a stylesheet parameter.
423    *
424    * @param key stylesheet parameter key
425    * @param expr the parameter expression to be submitted.
426    * @see javax.xml.transform.Transformer#setParameter(String,Object)
427    */

428   public void setStylesheetParam(String JavaDoc key, String JavaDoc expr)
429   {
430     m_key = key;
431     m_expression = expr;
432   }
433
434   /**
435    * Given a String containing markup, escape the markup so it
436    * can be displayed in the browser.
437    *
438    * @param s String to escape
439    *
440    * The escaped string.
441    */

442   public String JavaDoc escapeString(String JavaDoc s)
443   {
444     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
445     int length = s.length();
446
447     for (int i = 0; i < length; i++)
448     {
449       char ch = s.charAt(i);
450
451       if ('<' == ch)
452       {
453         sb.append("&lt;");
454       }
455       else if ('>' == ch)
456       {
457         sb.append("&gt;");
458       }
459       else if ('&' == ch)
460       {
461         sb.append("&amp;");
462       }
463       else if (0xd800 <= ch && ch < 0xdc00)
464       {
465         // UTF-16 surrogate
466
int next;
467
468         if (i + 1 >= length)
469         {
470             next = '?'; // invalid surrogate character
471
}
472         else
473         {
474           next = s.charAt(++i);
475
476           if (!(0xdc00 <= next && next < 0xe000)) {
477               next = '?'; // invalid surrogate character
478
} else {
479               //+Integer.toHexString(ch)+" "+Integer.toHexString(next));
480
next = ((ch - 0xd800) << 10) + next - 0xdc00 + 0x00010000;
481           }
482         }
483         sb.append("&#x");
484         sb.append(Integer.toHexString(next));
485         sb.append(";");
486       }
487       else
488       {
489         sb.append(ch);
490       }
491     }
492     return sb.toString();
493   }
494
495   /**
496    * Assuming the stylesheet URL and the input XML URL have been set,
497    * perform the transformation and return the result as a String.
498    *
499    * @return A string that contains the contents pointed to by the URL.
500    *
501    */

502   public String JavaDoc getHtmlText()
503   {
504     m_trustedAgent.m_getData = true;
505     m_callThread = Thread.currentThread();
506     try
507     {
508       synchronized (m_callThread)
509       {
510         m_callThread.wait();
511       }
512     }
513     catch (InterruptedException JavaDoc ie)
514     {
515       System.out.println(ie.getMessage());
516     }
517     return m_htmlText;
518   }
519
520   /**
521    * Get an XML document (or stylesheet)
522    *
523    * @param treeURL valid URL string for the document.
524    *
525    * @return document
526    *
527    * @throws IOException
528    */

529   public String JavaDoc getTreeAsText(String JavaDoc treeURL) throws IOException JavaDoc
530   {
531     m_treeURL = treeURL;
532     m_trustedAgent.m_getData = true;
533     m_trustedAgent.m_getSource = true;
534     m_callThread = Thread.currentThread();
535     try
536     {
537       synchronized (m_callThread)
538       {
539         m_callThread.wait();
540       }
541     }
542     catch (InterruptedException JavaDoc ie)
543     {
544       System.out.println(ie.getMessage());
545     }
546     return m_sourceText;
547   }
548   
549   /**
550    * Use a Transformer to copy the source document
551    * to a StreamResult.
552    *
553    * @return the document as a string
554    */

555   private String JavaDoc getSource() throws TransformerException JavaDoc
556   {
557     StringWriter JavaDoc osw = new StringWriter JavaDoc();
558     PrintWriter JavaDoc pw = new PrintWriter JavaDoc(osw, false);
559     String JavaDoc text = "";
560     try
561     {
562       URL JavaDoc docURL = new URL JavaDoc(m_documentBase, m_treeURL);
563       synchronized (m_tfactory)
564       {
565         Transformer JavaDoc transformer = m_tfactory.newTransformer();
566         StreamSource JavaDoc source = new StreamSource JavaDoc(docURL.toString());
567         StreamResult JavaDoc result = new StreamResult JavaDoc(pw);
568         transformer.transform(source, result);
569         text = osw.toString();
570       }
571     }
572     catch (MalformedURLException JavaDoc e)
573     {
574       e.printStackTrace();
575       System.exit(-1);
576     }
577     catch (Exception JavaDoc any_error)
578     {
579       any_error.printStackTrace();
580     }
581     return text;
582   }
583
584   /**
585    * Get the XML source Tree as a text string suitable
586    * for display in a browser. Note that this is for display of the
587    * XML itself, not for rendering of HTML by the browser.
588    *
589    * @return XML source document as a string.
590    * @throws Exception thrown if tree can not be converted.
591    */

592   public String JavaDoc getSourceTreeAsText() throws Exception JavaDoc
593   {
594     return getTreeAsText(m_documentURL);
595   }
596
597   /**
598    * Get the XSL style Tree as a text string suitable
599    * for display in a browser. Note that this is for display of the
600    * XML itself, not for rendering of HTML by the browser.
601    *
602    * @return The XSL stylesheet as a string.
603    * @throws Exception thrown if tree can not be converted.
604    */

605   public String JavaDoc getStyleTreeAsText() throws Exception JavaDoc
606   {
607     return getTreeAsText(m_styleURL);
608   }
609
610   /**
611    * Get the HTML result Tree as a text string suitable
612    * for display in a browser. Note that this is for display of the
613    * XML itself, not for rendering of HTML by the browser.
614    *
615    * @return Transformation result as unmarked text.
616    * @throws Exception thrown if tree can not be converted.
617    */

618   public String JavaDoc getResultTreeAsText() throws Exception JavaDoc
619   {
620     return escapeString(getHtmlText());
621   }
622
623   /**
624    * Process a document and a stylesheet and return
625    * the transformation result. If one of these is null, the
626    * existing value (of a previous transformation) is not affected.
627    *
628    * @param doc URL string to XML document
629    * @param style URL string to XSL stylesheet
630    *
631    * @return HTML transformation result
632    */

633   public String JavaDoc transformToHtml(String JavaDoc doc, String JavaDoc style)
634   {
635
636     if (null != doc)
637     {
638       m_documentURL = doc;
639     }
640
641     if (null != style)
642     {
643       m_styleURL = style;
644     }
645
646     return getHtmlText();
647   }
648
649   /**
650    * Process a document and a stylesheet and return
651    * the transformation result. Use the xsl:stylesheet PI to find the
652    * document, if one exists.
653    *
654    * @param doc URL string to XML document containing an xsl:stylesheet PI.
655    *
656    * @return HTML transformation result
657    */

658   public String JavaDoc transformToHtml(String JavaDoc doc)
659   {
660
661     if (null != doc)
662     {
663       m_documentURL = doc;
664     }
665
666     m_styleURL = null;
667
668     return getHtmlText();
669   }
670
671
672   /**
673    * Process the transformation.
674    *
675    * @return The transformation result as a string.
676    *
677    * @throws TransformerException
678    */

679   private String JavaDoc processTransformation() throws TransformerException JavaDoc
680   {
681     String JavaDoc htmlData = null;
682     this.showStatus("Waiting for Transformer and Parser to finish loading and JITing...");
683     
684     synchronized (m_tfactory)
685     {
686      URL JavaDoc documentURL = null;
687       URL JavaDoc styleURL = null;
688       StringWriter JavaDoc osw = new StringWriter JavaDoc();
689       PrintWriter JavaDoc pw = new PrintWriter JavaDoc(osw, false);
690       StreamResult JavaDoc result = new StreamResult JavaDoc(pw);
691     
692       this.showStatus("Begin Transformation...");
693       try
694       {
695         documentURL = new URL JavaDoc(m_codeBase, m_documentURL);
696         StreamSource JavaDoc xmlSource = new StreamSource JavaDoc(documentURL.toString());
697
698         styleURL = new URL JavaDoc(m_codeBase, m_styleURL);
699         StreamSource JavaDoc xslSource = new StreamSource JavaDoc(styleURL.toString());
700
701         Transformer JavaDoc transformer = m_tfactory.newTransformer(xslSource);
702
703         if (null != m_key)
704           transformer.setParameter(m_key, m_expression);
705       
706          transformer.transform(xmlSource, result);
707       }
708       catch (TransformerConfigurationException JavaDoc tfe)
709       {
710         tfe.printStackTrace();
711         System.exit(-1);
712       }
713       catch (MalformedURLException JavaDoc e)
714       {
715         e.printStackTrace();
716         System.exit(-1);
717       }
718       
719       this.showStatus("Transformation Done!");
720       htmlData = osw.toString();
721     }
722     return htmlData;
723   }
724
725   /**
726    * This class maintains a worker thread that that is
727    * trusted and can do things like access data. You need
728    * this because the thread that is called by the browser
729    * is not trusted and can't access data from the URLs.
730    */

731   class TrustedAgent implements Runnable JavaDoc
732   {
733
734     /**
735      * Specifies whether the worker thread should perform a transformation.
736      */

737     public boolean m_getData = false;
738
739     /**
740      * Specifies whether the worker thread should get an XML document or XSL stylesheet.
741      */

742     public boolean m_getSource = false;
743
744     /**
745      * The real work is done from here.
746      *
747      */

748     public void run()
749     {
750       while (true)
751       {
752         m_trustedWorker.yield();
753
754         if (m_getData) // Perform a transformation or get a document.
755
{
756           try
757           {
758             m_getData = false;
759             m_htmlText = null;
760             m_sourceText = null;
761             if (m_getSource) // Get a document.
762
{
763               m_getSource = false;
764               m_sourceText = getSource();
765             }
766             else // Perform a transformation.
767
m_htmlText = processTransformation();
768           }
769           catch (Exception JavaDoc e)
770           {
771             e.printStackTrace();
772           }
773           finally
774           {
775             synchronized (m_callThread)
776             {
777               m_callThread.notify();
778             }
779           }
780         }
781         else
782         {
783           try
784           {
785             m_trustedWorker.sleep(50);
786           }
787           catch (InterruptedException JavaDoc ie)
788           {
789             ie.printStackTrace();
790           }
791         }
792       }
793     }
794   }
795 }
796
Popular Tags