/*
* Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
* $Id: TemplateTransformerXslt.java 3918 2008-04-14 17:35:35Z gbevin $
*/
package com.uwyn.rife.template;
import com.uwyn.rife.resources.ResourceFinder;
import com.uwyn.rife.resources.ResourceFinderClasspath;
import com.uwyn.rife.template.exceptions.FilterNotFoundException;
import com.uwyn.rife.template.exceptions.TemplateException;
import com.uwyn.rife.template.exceptions.TransformerErrorException;
import com.uwyn.rife.xml.XmlInputSource;
import com.uwyn.rife.xml.XmlUriResolver;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.xml.sax.SAXException;
import org.xml.sax.XMLFilter;
import org.xml.sax.XMLReader;
public class TemplateTransformerXslt implements TemplateTransformer
{
private ResourceFinder mResourceFinder = ResourceFinderClasspath.getInstance();
private ArrayList<SAXSource> mFilters = null;
private Properties mProperties = null;
private String mState = null;
public final static String OUTPUT_METHOD = "method";
public final static String OUTPUT_INDENT = "indent";
public final static String OUTPUT_MEDIA_TYPE = "media-type";
public final static String OUTPUT_VERSION = "version";
public final static String OUTPUT_INDENT_AMOUNT = "{http\u003a//xml.apache.org/xalan}indent-amount";
public final static String OUTPUT_USE_URL_ESCAPING = "{http\u003a//xml.apache.org/xalan}use-url-escaping";
public final static String OUTPUT_OMIT_META_TAG = "{http\u003a//xml.apache.org/xalan}omit-meta-tag";
public String getState()
{
if (null == mState)
{
StringBuilder state = new StringBuilder();
if (mFilters != null)
{
for (SAXSource filter : mFilters)
{
state.append(filter.getInputSource().toString());
state.append(";");
}
}
if (mProperties != null)
{
state.append("\n");
Enumeration property_names = mProperties.propertyNames();
String property_name = null;
while (property_names.hasMoreElements())
{
property_name = (String)property_names.nextElement();
state.append(property_name);
state.append("=");
state.append(mProperties.getProperty(property_name));
state.append(";");
}
}
mState = state.toString();
}
return mState;
}
public void addFilter(String xmlPath)
throws TemplateException
{
if (null == xmlPath) throw new IllegalArgumentException("xmlPath can't be null");
if (0 == xmlPath.length()) throw new IllegalArgumentException("xmlPath can't be empty");
if (null == mFilters)
{
mFilters = new ArrayList<SAXSource>();
}
URL resource = mResourceFinder.getResource(xmlPath);
if (null == resource)
{
throw new FilterNotFoundException(xmlPath);
}
mState = null;
mFilters.add(new SAXSource(new XmlInputSource(resource)));
}
public void clearFilters()
{
mState = null;
mFilters = null;
}
public ResourceFinder getResourceFinder()
{
return mResourceFinder;
}
public void setResourceFinder(ResourceFinder resourceFinder)
{
mResourceFinder = resourceFinder;
}
public void setOutputProperty(String name, String value)
throws IllegalArgumentException
{
if (null == mProperties)
{
mProperties = new Properties();
}
mState = null;
mProperties.setProperty(name, value);
}
public void setOutputProperties(Properties properties)
throws IllegalArgumentException
{
mState = null;
mProperties = properties;
}
public Collection<URL> transform(String templateName, URL resource, OutputStream result, String encoding)
throws TemplateException
{
ArrayList<URL> stylesheets = new ArrayList<URL>();
XmlInputSource input = new XmlInputSource(resource);
if (encoding != null)
{
input.setEncoding(encoding);
}
try
{
SAXParserFactory parser_factory = SAXParserFactory.newInstance();
parser_factory.setNamespaceAware(true);
SAXParser parser = parser_factory.newSAXParser();
XMLReader reader = parser.getXMLReader();
XMLReader parent = reader;
XMLFilter filter = null;
SAXTransformerFactory transformer_factory = (SAXTransformerFactory)TransformerFactory.newInstance();
transformer_factory.setURIResolver(new XmlUriResolver(mResourceFinder));
// try to obtain the associated stylesheet and use it as the first filter
Source stylesheet = transformer_factory.getAssociatedStylesheet(new SAXSource(input), null, null, null);
if (stylesheet != null)
{
filter = transformer_factory.newXMLFilter(stylesheet);
filter.setParent(parent);
parent = filter;
// store the stylesheet so that it can be included in the modification checks
stylesheets.add(new URL(stylesheet.getSystemId()));
reader = filter;
}
// set up the additional filters
if (mFilters != null &&
mFilters.size() > 0)
{
Iterator<SAXSource> filters_it = mFilters.iterator();
while (filters_it.hasNext())
{
stylesheet = filters_it.next();
filter = transformer_factory.newXMLFilter(stylesheet);
filter.setParent(parent);
parent = filter;
// store the stylesheet so that it can be included in the modification checks
stylesheets.add(new URL(stylesheet.getSystemId()));
}
reader = filter;
}
// setup the transformer by applying the custom properties
Transformer transformer = transformer_factory.newTransformer();
if (mProperties != null)
{
Properties merged_properties = transformer.getOutputProperties();
merged_properties.putAll(mProperties);
transformer.setOutputProperties(merged_properties);
}
// perform the transformation
StreamResult stream_result = new StreamResult(result);
SAXSource transform_source = new SAXSource(reader, input);
transformer.transform(transform_source, stream_result);
}
catch (MalformedURLException e)
{
throw new TransformerErrorException(resource, e);
}
catch (TransformerConfigurationException e)
{
throw new TransformerErrorException(resource, e);
}
catch (TransformerException e)
{
throw new TransformerErrorException(resource, e);
}
catch (FactoryConfigurationError e)
{
throw new TransformerErrorException(resource, e);
}
catch (ParserConfigurationException e)
{
throw new TransformerErrorException(resource, e);
}
catch (SAXException e)
{
throw new TransformerErrorException(resource, e);
}
return stylesheets;
}
public String getEncoding()
{
if (mProperties != null &&
mProperties.containsKey("encoding"))
{
return mProperties.getProperty("encoding");
}
return null;
}
}