blob: 45d48d0b9c2267c775bf472837c612f93f94bc2d [file] [log] [blame]
/************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0. You can also
* obtain a copy of the License at http://odftoolkit.org/docs/license.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
************************************************************************/
package org.odftoolkit.odfxsltrunner;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.odftoolkit.odfdom.pkg.OdfPackage;
import org.odftoolkit.odfdom.pkg.manifest.OdfFileEntry;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
/**
* Class for applying style sheets to ODF documents.
*/
public class ODFXSLTRunner {
/**
* Input file is a plain XML file.
*/
public static final int INPUT_MODE_FILE = 0;
/**
* Input file is an ODF package. The style sheet is applied to the
* specified sub file.
*/
public static final int INPUT_MODE_PACKAGE = 1;
/**
* Output file is a plain XML or text file.
*/
public static final int OUTPUT_MODE_FILE = 0;
/**
* Output is stdout.
*/
public static final int OUTPUT_MODE_STDOUT = 1;
/**
* The transformation replaces the specified path within
* the input file.
*/
public static final int OUTPUT_MODE_REPLACE_INPUT_PACKAGE = 2;
/**
* The input package is copied and the result of the transformation
* is stored in the specified path within the copied package.
*/
public static final int OUTPUT_MODE_COPY_INPUT_PACKAGE = 3;
/**
* The result of the transformation is stored in the specified path within
* the output package.
*/
public static final int OUTPUT_MODE_TEMPLATE_PACKAGE = 4;
private static final int FILE_COPY_BUFFER_SIZE = 4096;
/**
* Create new instance of ODFXSLTRunner.
*/
public ODFXSLTRunner()
{
}
/**
* Apply a style sheeet.
*
* @param aStyleSheet Path of the style sheet
* @param aParams Parameters that are passed to the XSLT processor
* @param aInputFile Path of the input file
* @param aInputMode Input mode
* @param aOutputFile Path of the output file
* @param aOutputMode Output mode
* @param aTransformerFactoryClassName XSLT transformer factory to use
* @param aExtractFileNames A list of files or directory that shell be extracted from the package
* @param aPathInPackage Path within the package. Default is "content.xml"
* @param aLogger Logger object
*
* @return true if an error occured.
*/
public boolean runXSLT( String aStyleSheet, List<XSLTParameter> aParams,
String aInputFile, int aInputMode,
String aOutputFile, int aOutputMode,
String aPathInPackage,
String aTransformerFactoryClassName,
List<String> aExtractFileNames,
Logger aLogger )
{
return runXSLT( new File( aStyleSheet ), aParams,
new File( aInputFile), aInputMode,
aOutputFile != null ? new File(aOutputFile) : null, aOutputMode,
aPathInPackage, aTransformerFactoryClassName,
aExtractFileNames, aLogger );
}
/**
* Apply a style sheeet.
*
* @param aStyleSheetFile Style sheet
* @param aParams Parameters that are passed to the XSLT processor
* @param aInputFile Input file
* @param aInputMode Input mode
* @param aOutputFile Output file
* @param aOutputMode Output mode
* @param aPathInPackage Path within the package. Default is "content.xml"
* @param aTransformerFactoryClassName XSLT transformer factory to use
* @param aExtractFileNames A list of files or directory that shell be extracted from the package
* @param aLogger Logger object
*
* @return true if an error occured.
*/
public boolean runXSLT( File aStyleSheetFile, List<XSLTParameter> aParams,
File aInputFile, int aInputMode,
File aOutputFile, int aOutputMode,
String aPathInPackage,
String aTransformerFactoryClassName,
List<String> aExtractFileNames,
Logger aLogger )
{
boolean bError = false;
URIResolver aURIResolver = null;
InputSource aInputSource = null;
OdfPackage aInputPkg = null;
String aMediaType ="text/xml";
aLogger.setName( aInputFile.getAbsolutePath() );
try
{
if( INPUT_MODE_FILE == aInputMode )
{
aInputSource = new InputSource( new FileInputStream(aInputFile) );
}
else
{
aInputPkg = OdfPackage.loadPackage( aInputFile );
aLogger.setName( aInputFile.getAbsolutePath(), aPathInPackage );
aInputSource = new InputSource( aInputPkg.getInputStream(aPathInPackage) );
aInputSource.setSystemId( aInputFile.toURI().toString() + '/' + aPathInPackage );
OdfFileEntry aFileEntry = aInputPkg.getFileEntry(aPathInPackage);
if( aFileEntry != null )
aMediaType = aFileEntry.getMediaTypeString();
aURIResolver =
new ODFURIResolver( aInputPkg, aInputFile.toURI().toString(), aPathInPackage, aLogger );
}
}
catch( Exception e )
{
aLogger.logFatalError(e.getMessage());
return true;
}
String aInputName = aLogger.getName();
Result aOutputResult = null;
OdfPackage aOutputPkg = null;
OutputStream aOutputStream = null;
aLogger.setName( aOutputFile != null ? aOutputFile.getAbsolutePath() : "(none)" );
boolean bMkOutputDirs = false;
try
{
switch( aOutputMode )
{
case OUTPUT_MODE_FILE:
bMkOutputDirs = true;
aOutputResult = new StreamResult( aOutputFile );
break;
case OUTPUT_MODE_STDOUT:
aOutputResult = new StreamResult( System.out );
break;
case OUTPUT_MODE_REPLACE_INPUT_PACKAGE:
aOutputPkg = aInputPkg;
aOutputFile = aInputFile;
break;
case OUTPUT_MODE_COPY_INPUT_PACKAGE:
bMkOutputDirs = true;
aOutputPkg = aInputPkg;
break;
case OUTPUT_MODE_TEMPLATE_PACKAGE:
aOutputPkg = OdfPackage.loadPackage( aOutputFile );
break;
}
if( aOutputResult == null )
{
aLogger.setName( aOutputFile.getAbsolutePath(), aPathInPackage );
aOutputStream =
aOutputPkg.insertOutputStream(aPathInPackage, aMediaType );
aOutputResult = new StreamResult( aOutputStream );
}
}
catch( Exception e )
{
aLogger.logFatalError(e.getMessage());
return true;
}
if( bMkOutputDirs )
{
File aOutputDir = aOutputFile.getParentFile();
if( aOutputDir != null )
aOutputDir.mkdirs();
}
String aOutputName = aLogger.getName();
aLogger.setName( aStyleSheetFile.getAbsolutePath() );
aLogger.logInfo( "Applying stylesheet to '" + aInputName + "'");
bError = runXSLT( aStyleSheetFile, aParams, aInputSource, aOutputResult,
aTransformerFactoryClassName, aURIResolver, aLogger );
if( bError )
return true;
aLogger.setName( aOutputFile != null ? aOutputFile.getAbsolutePath() : "(none)" );
try
{
aLogger.logInfo( "Storing transformation result to '" + aOutputName + "'");
if( !bError && aOutputStream != null )
aOutputStream.close();
if( !bError && aOutputPkg != null )
aOutputPkg.save(aOutputFile);
if( aOutputMode == OUTPUT_MODE_FILE && aExtractFileNames != null && aInputPkg != null )
{
File aTargetDir = aOutputFile.getParentFile();
extractFiles( aInputPkg, aTargetDir, aExtractFileNames, aLogger );
}
}
catch( Exception e )
{
aLogger.logFatalError(e.getMessage());
return true;
}
return false;
}
private boolean runXSLT( File aStyleSheetFile,
List<XSLTParameter> aParams,
InputSource aInputInputSource, Result aOutputTarget,
String aTransformerFactoryClassName,
URIResolver aURIResolver,
Logger aLogger )
{
InputStream aStyleSheetInputStream = null;
try
{
aStyleSheetInputStream = new FileInputStream(aStyleSheetFile);
}
catch( FileNotFoundException e )
{
aLogger.logFatalError(e.getMessage());
return true;
}
InputSource aStyleSheetInputSource = new InputSource(aStyleSheetInputStream);
aStyleSheetInputSource.setSystemId(aStyleSheetFile.getAbsolutePath());
XMLReader aStyleSheetXMLReader = null;
XMLReader aInputXMLReader = null;
try
{
aStyleSheetXMLReader = XMLReaderFactory.createXMLReader();
aInputXMLReader = XMLReaderFactory.createXMLReader();
}
catch( SAXException e )
{
aLogger.logFatalError(e.getMessage());
return true;
}
aStyleSheetXMLReader.setErrorHandler(new SAXErrorHandler(aLogger));
aInputXMLReader.setErrorHandler(new SAXErrorHandler(aLogger));
aInputXMLReader.setEntityResolver(new ODFEntityResolver(aLogger));
Source aStyleSheetSource = new SAXSource( aStyleSheetXMLReader, aStyleSheetInputSource );
Source aInputSource = new SAXSource( aInputXMLReader, aInputInputSource );
if( aTransformerFactoryClassName!=null )
aLogger.logInfo( "Requesting transformer factory class: " + aTransformerFactoryClassName );
TransformerFactory aFactory = null;
if(aTransformerFactoryClassName==null)
{
aFactory = TransformerFactory.newInstance();
}
else
{
try
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null)
cl = ClassLoader.getSystemClassLoader();
Class classInstance = cl.loadClass(aTransformerFactoryClassName);
aFactory = (TransformerFactory)classInstance.newInstance();
}
catch( ClassNotFoundException ce )
{
aLogger.logFatalError(ce.getMessage());
return true;
}
catch( InstantiationException ie )
{
aLogger.logFatalError(ie.getMessage());
return true;
}
catch( IllegalAccessException ile )
{
aLogger.logFatalError(ile.getMessage());
return true;
}
}
ErrorListener aErrorListener = new TransformerErrorListener( aLogger );
aLogger.logInfo( "Using transformer factory class: " + aFactory.getClass().getName() );
aFactory.setErrorListener(aErrorListener);
try
{
Transformer aTransformer = aFactory.newTransformer(aStyleSheetSource);
if( aParams != null )
{
Iterator<XSLTParameter> aIter = aParams.iterator();
while( aIter.hasNext() )
{
XSLTParameter aParam = aIter.next();
aTransformer.setParameter(aParam.getName(), aParam.getValue());
aLogger.logInfo("Using parameter: "+aParam.getName()+"="+aParam.getValue());
}
}
aTransformer.setErrorListener(aErrorListener);
if( aURIResolver != null )
aTransformer.setURIResolver(aURIResolver);
aTransformer.transform(aInputSource, aOutputTarget);
}
catch( TransformerException e )
{
aLogger.logFatalError(e);
return true;
}
return false;
}
private boolean extractFiles( OdfPackage aInputPkg,
File aTargetDir,
List<String> aExtractFileNames,
Logger aLogger )
{
Set<String> aInputPkgEntries = aInputPkg.getFilePaths();
Iterator<String> aInputPkgEntryIter = aInputPkgEntries.iterator();
while( aInputPkgEntryIter.hasNext() )
{
String aInputFileName = aInputPkgEntryIter.next();
Iterator<String> aExtractFileNameIter = aExtractFileNames.iterator();
while( aExtractFileNameIter.hasNext() )
{
String aExtractFileName = aExtractFileNameIter.next();
if( !aInputFileName.endsWith("/") &&
(aInputFileName.equals(aExtractFileName) ||
(aExtractFileName.endsWith("/") ? aInputFileName.startsWith(aExtractFileName)
: aInputFileName.startsWith(aExtractFileName+"/")) ) )
{
try
{
File aTargetFile = new File( aTargetDir, aInputFileName );
File aTargetFileDir = aTargetFile.getParentFile();
if( aTargetFileDir != null )
aTargetFileDir.mkdirs();
aLogger.logInfo( "Extracting file " + aInputFileName + " to " + aTargetFile.getAbsolutePath() );
InputStream aInputStream = aInputPkg.getInputStream(aInputFileName);
OutputStream aTargetStream = new FileOutputStream( aTargetFile );
byte[] aBuffer = new byte[FILE_COPY_BUFFER_SIZE];
int n = 0;
while ((n = aInputStream.read(aBuffer, 0, FILE_COPY_BUFFER_SIZE)) > -1)
{
aTargetStream.write(aBuffer, 0, n);
}
aTargetStream.close();
aInputStream.close();
}
catch(java.lang.Exception e)
{
aLogger.logError(e.getMessage());
}
break;
}
}
}
return false;
}
}