1/*2 * Copyright 2000-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 at7 * 8 * http://www.apache.org/licenses/LICENSE-2.09 * 10 * Unless required by applicable law or agreed to in writing, software11 * 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 and14 * limitations under the License.15 */1617packageorg.apache.jetspeed.util;
1819//java stuff20import java.io.IOException;
21import java.io.InputStreamReader;
22import java.io.OutputStreamWriter;
23import java.io.PipedInputStream;
24import java.io.PipedOutputStream;
25import java.io.Reader;
26import java.io.StringWriter;
27import java.io.Writer;
28import java.util.Iterator;
29import java.util.Map;
3031//Trax support32import javax.xml.transform.TransformerFactory;
33import javax.xml.transform.Transformer;
34import javax.xml.transform.Templates;
35//import javax.xml.transform.stream.StreamSource;36import javax.xml.transform.stream.StreamResult;
37import javax.xml.transform.dom.DOMSource;
38import javax.xml.transform.sax.SAXSource;
39import javax.xml.transform.sax.SAXTransformerFactory;
40import javax.xml.transform.sax.TemplatesHandler;
41import javax.xml.transform.sax.TransformerHandler;
4243//xpath objects44import org.apache.xpath.objects.XString;
4546//SAX Suport47import org.xml.sax.XMLReader;
48import org.xml.sax.SAXException;
49import org.xml.sax.helpers.XMLReaderFactory;
50import org.xml.sax.InputSource;
5152//DOM Support53import org.w3c.dom.Document;
5455//Jetspeed stuff56import org.apache.jetspeed.cache.disk.JetspeedDiskCache;
57import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
58import org.apache.jetspeed.services.logging.JetspeedLogger;
59import org.apache.jetspeed.xml.JetspeedXMLEntityResolver;
6061626364/***65 * Provides a very simple mechanism to transform a document using XSLT using 66 * one XML document and another XSL document. This implementation uses the TRAX API.67 * It can be used with any TRAX transformer. This can be used for very 68 * simple XML -> XSL processing to reduce the complexity and possibility of a 69 * runtime failure.70 *71 * @author <a href="mailto:burton@apache.org">Kevin A. Burton</a>72 * @author <a href="mailto:sgala@apache.org">Santiago Gala</a>73 * @version $Id: SimpleTransform.java,v 1.23 2004/02/23 03:23:42 jford Exp $74 */75publicclassSimpleTransform76 {
77/***78 * Static initialization of the logger for this class79 */80privatestaticfinalJetspeedLogger logger = JetspeedLogFactoryService.getLogger(SimpleTransform.class.getName());
8182//FIXME: This code should go into the Turbine XSLTservice.83//Also, it is a temporary hack, as it should be configurable,84// and done later.85static86 {
87try88 {
89if( System.getProperty( "org.xml.sax.driver" ) == null )
90 {
91 System.setProperty( "org.xml.sax.driver",
92"org.apache.xerces.parsers.SAXParser" );
93 }
94 }
95catch (Throwable t)
96 {
97//be very cautious here. We are in class initialization.98 t.printStackTrace();
99 }
100 }
101102/***103 * Given a a DOM and a URL to a stylesheet,104 * transform the original document.105 */106publicstatic String transform( Document doc,
107 String stylesheet_url)
108 throws SAXException
109 {
110return transform( doc, stylesheet_url, null );
111 }
112113114/***115 * Given a a DOM and a URL to a stylesheet,116 * transform the original document,117 * passing parameters to the stylesheet118 */119publicstatic String transform( Document doc,
120 String stylesheet_url,
121 Map params)
122 throws SAXException
123 {
124125// Instantiate a TransformerFactory.126 TransformerFactory tFactory = TransformerFactory.newInstance();
127// Determine whether the TransformerFactory supports the use of SAXSource 128// and SAXResult129if (!tFactory.getFeature(SAXTransformerFactory.FEATURE) )
130 {
131 logger.error( "SimpleTransform: nobody told you that we need a SAX Transformer?" );
132thrownew SAXException( "Invalid SAX Tranformer" );
133 }
134try135 {
136// Cast the TransformerFactory.137 SAXTransformerFactory saxTFactory = ((SAXTransformerFactory) tFactory);
138// Create a ContentHandler to handle parsing of the stylesheet.139 TemplatesHandler templatesHandler = saxTFactory.newTemplatesHandler();
140141// Create an XMLReader and set its ContentHandler.142 XMLReader reader = XMLReaderFactory.createXMLReader();
143 reader.setContentHandler(templatesHandler);
144// Set it to solve Entities through Jetspeed URL Manager145 reader.setEntityResolver( new JetspeedXMLEntityResolver() );
146147// Parse the stylesheet. 148final InputSource xstyle = new InputSource( JetspeedDiskCache.getInstance()
149 .getEntry( stylesheet_url ).getReader() );
150 xstyle.setSystemId( stylesheet_url );
151 reader.parse( xstyle );
152153//Get the Templates object from the ContentHandler.154 Templates templates = templatesHandler.getTemplates();
155// Create a ContentHandler to handle parsing of the XML source. 156 TransformerHandler handler
157 = saxTFactory.newTransformerHandler(templates);
158159// Reset the XMLReader's ContentHandler.160 reader.setContentHandler(handler);
161162// Set the ContentHandler to also function as a LexicalHandler, which163// includes "lexical" events (e.g., comments and CDATA).164try165 {
166 reader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
167 }
168catch( org.xml.sax.SAXNotRecognizedException e ) {}
169170final Transformer processor = handler.getTransformer();
171172if( params != null ) {
173 Iterator keys = params.keySet().iterator();
174while( keys.hasNext() )
175 {
176 String name = (String) keys.next();
177 String value = (String) params.get(name);
178 processor.setParameter(name,
179 value ); //FIXME: maybe we need to quote again...180// was processor.createXString( value)181 }
182 }
183184 StringWriter pw = new StringWriter();
185186// Have the XSLTProcessor processor object transform "foo.xml" to187// System.out, using the XSLT instructions found in "foo.xsl".188 processor.transform( new DOMSource( doc ),
189new StreamResult( pw ) );
190191try192 {
193194 pw.flush();
195 pw.close();
196197 }
198catch (IOException e)
199 {
200//should never really happen201 logger.error("Exception", e);
202 }
203return pw.toString();
204 }
205catch (Exception e)
206 {
207 logger.error( "Invalid SAX Transformer: " , e );
208thrownew SAXException( "problem in SAX transform: " + e.toString() );
209 }
210 }
211212/***213 * Given a URL to an XML file and a URL to a stylesheet, transform the 214 * original document.215 */216publicstatic String transform( String url,
217 String stylesheet_url )
218 throws SAXException
219 {
220221return transform( url, stylesheet_url, null );
222223 }
224225/***226 * Given a URL to an XML file and a URL to a stylesheet, transform the 227 * original document.228 */229publicstatic String transform( String url,
230 String stylesheet_url,
231 Map params )
232 throws SAXException
233 {
234235//bring these URLs local if they happen to be remote236237 InputSource in;
238 InputSource style;
239try240 {
241 in = new InputSource( JetspeedDiskCache.getInstance().getEntry( url ).getReader() );
242 style = new InputSource( JetspeedDiskCache.getInstance().getEntry( stylesheet_url ).getReader() );
243 }
244catch (IOException e)
245 {
246 logger.error("Exception", e);
247//at this point we can just use the original url and stylesheet_url so this shouldn't be a problem248 in = new InputSource( url );
249 style = new InputSource( stylesheet_url );
250 }
251252if ( logger.isInfoEnabled() )
253 {
254 logger.info( "SimpleTransform: transforming url: " +
255 url +
256" with stylesheet: " +
257 stylesheet_url );
258 }
259260 in.setSystemId( url );
261 style.setSystemId( stylesheet_url );
262263return transform( in,
264 style,
265 params );
266267 }
268269/***270 * Used internally to handle doing XSLT transformations directly.271 */272publicstatic String transform( InputSource content,
273 InputSource stylesheet,
274 Map params)
275 throws SAXException
276 {
277278// Instantiate a TransformerFactory.279 TransformerFactory tFactory = TransformerFactory.newInstance();
280// Determine whether the TransformerFactory supports the use of SAXSource 281// and SAXResult282if (!tFactory.getFeature(SAXTransformerFactory.FEATURE) )
283 {
284 logger.error( "SimpleTransform: nobody told you that we need a SAX Transformer?" );
285thrownew SAXException( "Invalid SAX Tranformer" );
286 }
287try288 {
289// Cast the TransformerFactory.290 SAXTransformerFactory saxTFactory = ((SAXTransformerFactory) tFactory);
291// Create a ContentHandler to handle parsing of the stylesheet.292 TemplatesHandler templatesHandler = saxTFactory.newTemplatesHandler();
293294// Create an XMLReader and set its ContentHandler.295 XMLReader reader = XMLReaderFactory.createXMLReader();
296 reader.setContentHandler(templatesHandler);
297298// Parse the stylesheet. 299 reader.parse( stylesheet );
300301//Get the Templates object from the ContentHandler.302 Templates templates = templatesHandler.getTemplates();
303// Create a ContentHandler to handle parsing of the XML source. 304 TransformerHandler handler
305 = saxTFactory.newTransformerHandler(templates);
306307// Reset the XMLReader's ContentHandler.308 reader.setContentHandler(handler);
309310// Set the ContentHandler to also function as a LexicalHandler, which311// includes "lexical" events (e.g., comments and CDATA). 312try313 {
314 reader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
315 }
316catch( org.xml.sax.SAXNotRecognizedException e ) {}
317318final Transformer processor = handler.getTransformer();
319320321if( params != null )
322 {
323 Iterator keys = params.keySet().iterator();
324while( keys.hasNext() )
325 {
326 String name = (String) keys.next();
327 String value = (String) params.get(name);
328 processor.setParameter(name,
329new XString( value )
330/*FIXME: was processor.createXString( value) */ );331 }
332 }
333334 StringWriter pw = new StringWriter();
335336// Have the XSLTProcessor processor object transform "foo.xml" to337// System.out, using the XSLT instructions found in "foo.xsl".338 processor.transform( new SAXSource( content ),
339new StreamResult( pw ) );
340341try342 {
343 pw.flush();
344 pw.close();
345 }
346catch (IOException e)
347 {
348//should never really happen349 logger.error("Exception", e);
350 }
351return pw.toString();
352 }
353catch (Exception e)
354 {
355 logger.error( "Invalid SAX Transformer: " , e);
356thrownew SAXException( "problem in SAX transform: " + e.toString() );
357 }
358 }
359360/***361 * Perform a event based parsing of the given content_url, 362 * process it with the XSLT stylesheet stylesheet_url, using the params363 * parameters, and return a Reader that will do the transformation dynamically.364 *365 * @param content_url The url of the xml document366 * @param stylesheet_url The url of the stylesheet367 * @param params A Map containing stylesheet parameters368 * @return a Reader on the transformed document369 *370 */371publicstatic Reader SAXTransform( String content_url,
372 String stylesheet_url,
373 Map params) throws IOException
374 {
375376// Instantiate a TransformerFactory.377 TransformerFactory tFactory = TransformerFactory.newInstance();
378// Determine whether the TransformerFactory supports the use of SAXSource 379// and SAXResult380if (!tFactory.getFeature(SAXTransformerFactory.FEATURE) )
381 {
382 logger.error( "SimpleTransform: nobody told you that we need a SAX Transformer?" );
383thrownew IOException( "Invalid SAX Tranformer" );
384 }
385try386 {
387// Cast the TransformerFactory.388 SAXTransformerFactory saxTFactory = ((SAXTransformerFactory) tFactory);
389// Create a ContentHandler to handle parsing of the stylesheet.390 TemplatesHandler templatesHandler = saxTFactory.newTemplatesHandler();
391392// Create an XMLReader and set its ContentHandler.393 XMLReader reader = XMLReaderFactory.createXMLReader();
394 reader.setContentHandler(templatesHandler);
395// Set it to solve Entities through Jetspeed URL Manager396 reader.setEntityResolver( new JetspeedXMLEntityResolver() );
397398// Parse the stylesheet. 399 InputSource style = new InputSource( JetspeedDiskCache.getInstance()
400 .getEntry( stylesheet_url ).getReader() );
401 style.setSystemId( stylesheet_url );
402final InputSource xstyle = style;
403404 reader.parse( xstyle );
405406//Get the Templates object from the ContentHandler.407 Templates templates = templatesHandler.getTemplates();
408// Create a ContentHandler to handle parsing of the XML source. 409 TransformerHandler handler
410 = saxTFactory.newTransformerHandler(templates);
411412// Reset the XMLReader's ContentHandler.413 reader.setContentHandler(handler);
414415// Set the ContentHandler to also function as a LexicalHandler, which416// includes "lexical" events (e.g., comments and CDATA). 417try418 {
419 reader.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
420 }
421catch( org.xml.sax.SAXNotRecognizedException e ) {}
422423final Transformer processor = handler.getTransformer();
424425//Set the parameters (if any)426if( params != null )
427 {
428 Iterator keys = params.keySet().iterator();
429while( keys.hasNext() )
430 {
431 String name = (String) keys.next();
432 String value = (String) params.get(name);
433//FIXME: maybe we need to quote again...434// was processor.createXString( value)435 processor.setParameter(name,
436new XString( value ) );
437 }
438 }
439440 PipedInputStream pis = new PipedInputStream();
441 PipedOutputStream pos = new PipedOutputStream( pis );
442try443 {
444445final Writer pw = new OutputStreamWriter( pos, "utf-8" );
446 InputSource is = new InputSource( JetspeedDiskCache.getInstance()
447 .getEntry( content_url ).getReader() );
448 is.setSystemId( content_url );
449450final SAXSource xinput = new SAXSource( is );
451//Perform the transformation on a new thread, using452// PipedStreams 453 Thread t = new Thread( new Runnable()
454 {
455publicvoid run()
456 {
457// Have the processor object transform 458// "foo.xml" to459// System.out, using the XSLT instructions 460//found in "foo.xsl".461 logger.debug("Starting SAX thread...");
462try463 {
464 processor.transform( xinput,
465new StreamResult( pw ) );
466 pw.close();
467 logger.debug("...ending SAX thread.");
468 }
469catch( Exception se)
470 {
471 logger.debug("Error in SAXTransform" + se.toString(), se );
472 }
473 }
474 } );
475 t.start();
476 }
477catch (java.io.UnsupportedEncodingException uee)
478 {
479 logger.error("Need utf-8 encoding to SAXTransform", uee);
480 }
481returnnew InputStreamReader ( pis, "utf-8" );
482 }
483catch (Exception e)
484 {
485 logger.error( "Invalid SAX Transformer:" , e);
486thrownew IOException( "problem in SAX transform: " + e.toString() );
487 }
488 }
489490 }