Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/xalan/xslt/extensions/Redirect.java


1   /*
2    * The Apache Software License, Version 1.1
3    *
4    *
5    * Copyright (c) 1999 The Apache Software Foundation.  All rights
6    * reserved.
7    *
8    * Redistribution and use in source and binary forms, with or without
9    * modification, are permitted provided that the following conditions
10   * are met:
11   *
12   * 1. Redistributions of source code must retain the above copyright
13   *    notice, this list of conditions and the following disclaimer.
14   *
15   * 2. Redistributions in binary form must reproduce the above copyright
16   *    notice, this list of conditions and the following disclaimer in
17   *    the documentation and/or other materials provided with the
18   *    distribution.
19   *
20   * 3. The end-user documentation included with the redistribution,
21   *    if any, must include the following acknowledgment:
22   *       "This product includes software developed by the
23   *        Apache Software Foundation (http://www.apache.org/)."
24   *    Alternately, this acknowledgment may appear in the software itself,
25   *    if and wherever such third-party acknowledgments normally appear.
26   *
27   * 4. The names "Xalan" and "Apache Software Foundation" must
28   *    not be used to endorse or promote products derived from this
29   *    software without prior written permission. For written
30   *    permission, please contact apache@apache.org.
31   *
32   * 5. Products derived from this software may not be called "Apache",
33   *    nor may "Apache" appear in their name, without prior written
34   *    permission of the Apache Software Foundation.
35   *
36   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47   * SUCH DAMAGE.
48   * ====================================================================
49   *
50   * This software consists of voluntary contributions made by many
51   * individuals on behalf of the Apache Software Foundation and was
52   * originally based on software copyright (c) 1999, Lotus
53   * Development Corporation., http://www.lotus.com.  For more
54   * information on the Apache Software Foundation, please see
55   * <http://www.apache.org/>.
56   */
57  package org.apache.xalan.xslt.extensions;
58  
59  import java.util.*;
60  import org.w3c.dom.*;
61  import org.apache.xalan.xslt.XSLProcessorContext;
62  import org.apache.xalan.xslt.XSLTEngineImpl;
63  import org.apache.xalan.xslt.ElemTemplateElement;
64  import org.apache.xalan.xslt.res.XSLTErrorResources;
65  import org.apache.xalan.xpath.XObject;
66  import org.apache.xalan.xslt.StylesheetRoot;
67  import org.apache.xalan.xslt.ElemExtensionCall;
68  import java.io.*;
69  import java.net.URL;
70  import org.apache.xalan.xpath.xml.*;
71  import org.apache.xml.serialize.*;
72  import org.xml.sax.DocumentHandler;
73  
74  /**
75   * Implements three extension elements to allow an XSLT transformation to
76   * redirect its output to multiple output files.
77   * You must declare the Xalan namespace (xmlns:lxslt="http://xml.apache.org/xslt"),
78   * a namespace for the extension prefix (such as xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"),
79   * and declare the extension namespace as an extension (extension-element-prefixes="redirect").
80   * You can either just use redirect:write, in which case the file will be
81   * opened and immediately closed after the write, or you can bracket the
82   * write calls by redirect:open and redirect:close, in which case the
83   * file will be kept open for multiple writes until the close call is
84   * encountered.  Calls can be nested.  Calls can take a 'file' attribute
85   * and/or a 'select' attribute in order to get the filename.  If a select
86   * attribute is encountered, it will evaluate that expression for a string
87   * that indicates the filename.  If the string evaluates to empty, it will
88   * attempt to use the 'file' attribute as a default.  Filenames can be relative
89   * or absolute.  If they are relative, the base directory will be the same as
90   * the base directory for the output document (setOutputFileName(outFileName) must
91   * be called first on the processor when using the API).
92   *
93   * <p>Example:</p>
94   * <PRE>
95   * &lt;?xml version="1.0"?>
96   * &lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/XSL/Transform/1.0"
97   *                 xmlns:lxslt="http://xml.apache.org/xslt"
98   *                 xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"
99   *                 extension-element-prefixes="redirect">
100  *
101  *   &lt;xsl:template match="/">
102  *     &lt;out>
103  *       default output.
104  *     &lt;/out>
105  *     &lt;redirect:open file="doc3.out"/>
106  *     &lt;redirect:write file="doc3.out">
107  *       &lt;out>
108  *         &lt;redirect:write file="doc1.out">
109  *           &lt;out>
110  *             doc1 output.
111  *             &lt;redirect:write file="doc3.out">
112  *               Some text to doc3
113  *             &lt;/redirect:write>
114  *           &lt;/out>
115  *         &lt;/redirect:write>
116  *         &lt;redirect:write file="doc2.out">
117  *           &lt;out>
118  *             doc2 output.
119  *             &lt;redirect:write file="doc3.out">
120  *               Some more text to doc3
121  *               &lt;redirect:write select="doc/foo">
122  *                 text for doc4
123  *               &lt;/redirect:write>
124  *             &lt;/redirect:write>
125  *           &lt;/out>
126  *         &lt;/redirect:write>
127  *       &lt;/out>
128  *     &lt;/redirect:write>
129  *     &lt;redirect:close file="doc3.out"/>
130  *   &lt;/xsl:template>
131  *
132  * &lt;/xsl:stylesheet>
133  * </PRE>
134  *
135  * @author Scott Boag
136  * @version 1.0
137  * @see <a href="../../../../../../extensions.html#ex-redirect" target="_top">Example with Redirect extension</a>
138  */
139 public class Redirect
140 {
141   /**
142    * List of formatter listeners indexed by filename.
143    */
144   protected Hashtable m_formatterListeners = new Hashtable ();
145 
146   /**
147    * List of output streams indexed by filename.
148    */
149   protected Hashtable m_outputStreams = new Hashtable ();
150 
151   /**
152    * Open the given file and put it in the XML, HTML, or Text formatter listener's table.
153    */
154   public void open(XSLProcessorContext context, Element elem)
155     throws java.net.MalformedURLException,
156            java.io.FileNotFoundException,
157            java.io.IOException,
158            org.xml.sax.SAXException
159   {
160     String fileName = getFilename(context, elem);
161     Object flistener = m_formatterListeners.get(fileName);
162     if(null == flistener)
163     {
164       String mkdirsExpr = ((ElemExtensionCall)elem).getAttribute ("mkdirs", context.sourceNode, context.processor);
165       boolean mkdirs = (mkdirsExpr != null)
166                        ? (mkdirsExpr.equals("true") || mkdirsExpr.equals("yes")) : true;
167     // DocumentHandler fl = 
168     makeFormatterListener(context, fileName, true, mkdirs);
169     // fl.startDocument();
170     }
171   }
172 
173   /**
174    * Write the evalutation of the element children to the given file. Then close the file
175    * unless it was opened with the open extension element and is in the formatter listener's table.
176    */
177   public void write(XSLProcessorContext context, Element elem)
178     throws java.net.MalformedURLException,
179            java.io.FileNotFoundException,
180            java.io.IOException,
181            org.xml.sax.SAXException
182   {
183     String fileName = getFilename(context, elem);
184     Object flObject = m_formatterListeners.get(fileName);
185     DocumentHandler formatter;
186     boolean inTable = false;
187     if(null == flObject)
188     {
189       String mkdirsExpr = ((ElemExtensionCall)elem).getAttribute ("mkdirs", context.sourceNode, context.processor);
190       boolean mkdirs = (mkdirsExpr != null)
191                        ? (mkdirsExpr.equals("true") || mkdirsExpr.equals("yes")) : true;
192       formatter = makeFormatterListener(context, fileName, true, mkdirs);
193     }
194     else
195     {
196       inTable = true;
197       formatter = (DocumentHandler)flObject;
198     }
199 
200     context.processor.writeChildren( formatter, context.stylesheetTree,
201                                      (ElemTemplateElement)elem,
202                                      context.sourceTree, context.sourceNode, context.mode);
203     if(!inTable)
204     {
205       OutputStream ostream = (OutputStream)m_outputStreams.get(fileName);
206       if(null != ostream)
207       {
208         formatter.endDocument();
209         ostream.close();
210         m_outputStreams.remove(fileName);
211         m_formatterListeners.remove(fileName);
212       }
213     }
214   }
215 
216 
217   /**
218    * Close the given file and remove it from the formatter listener's table.
219    */
220   public void close(XSLProcessorContext context, Element elem)
221     throws java.net.MalformedURLException,
222     java.io.FileNotFoundException,
223     java.io.IOException,
224     org.xml.sax.SAXException
225   {
226     String fileName = getFilename(context, elem);
227     Object formatterObj = m_formatterListeners.get(fileName);
228     if(null != formatterObj)
229     {
230       DocumentHandler fl = (DocumentHandler)formatterObj;
231       fl.endDocument();
232       OutputStream ostream = (OutputStream)m_outputStreams.get(fileName);
233       if(null != ostream)
234       {
235         ostream.close();
236         m_outputStreams.remove(fileName);
237       }
238       m_formatterListeners.remove(fileName);
239     }
240   }
241 
242   /**
243    * Get the filename from the 'select' or the 'file' attribute.
244    */
245   private String getFilename(XSLProcessorContext context, Element elem)
246     throws java.net.MalformedURLException,
247     java.io.FileNotFoundException,
248     java.io.IOException,
249     org.xml.sax.SAXException
250   {
251     String fileName;
252     String fileNameExpr = ((ElemExtensionCall)elem).getAttribute ("select", context.sourceNode, context.processor);
253     if(null != fileNameExpr)
254     {
255       org.apache.xalan.xpath.XPathSupport execContext = context.processor.getExecContext();
256       XObject xobj = context.processor.getStylesheet().evalXPathStr(execContext, fileNameExpr,
257                                                                     context.sourceNode,
258                                                                     execContext.getNamespaceContext());
259       fileName = xobj.str();
260       if((null == fileName) || (fileName.length() == 0))
261       {
262         fileName = ((ElemExtensionCall)elem).getAttribute ("file", context.sourceNode, context.processor);
263       }
264     }
265     else
266     {
267       fileName = ((ElemExtensionCall)elem).getAttribute ("file", context.sourceNode, context.processor);
268     }
269     if(null == fileName)
270     {
271       context.processor.error(elem, context.sourceNode, XSLTErrorResources.ER_REDIRECT_COULDNT_GET_FILENAME);
272                               //"Redirect extension: Could not get filename - file or select attribute must return vald string.");
273     }
274     return fileName;
275   }
276 
277   /**
278    * Create a new DocumentHandler, based on attributes of the current DocumentHandler.
279    */
280   private DocumentHandler makeFormatterListener(XSLProcessorContext context,
281                                                 String fileName,
282                                                 boolean shouldPutInTable,
283                                                 boolean mkdirs)
284     throws java.net.MalformedURLException,
285     java.io.FileNotFoundException,
286     java.io.IOException,
287     org.xml.sax.SAXException
288   {
289     File file = new File(fileName);
290     if(!file.isAbsolute())
291     {
292       if(null != context.processor.getOutputFileName())
293       {
294         File baseFile = new File(context.processor.getOutputFileName());
295         file = new File(baseFile.getParent(), fileName);
296       }
297     }
298 
299     if(mkdirs)
300     {
301       String dirStr = file.getParent();
302       if((null != dirStr) && (dirStr.length() > 0))
303       {
304         File dir = new File(dirStr);
305         dir.mkdirs();
306       }
307     }
308 
309     StylesheetRoot sr = context.stylesheetTree.m_stylesheetRoot;
310     OutputFormat formatter = sr.getOutputFormat();
311 
312     FileOutputStream ostream = new FileOutputStream(file);
313 
314     DocumentHandler flistener
315       = sr.makeSAXSerializer(ostream, formatter);
316 
317     flistener.startDocument();
318     if(shouldPutInTable)
319     {
320       m_outputStreams.put(fileName, ostream);
321       m_formatterListeners.put(fileName, flistener);
322     }
323     return flistener;
324   }
325 }