git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270227 13f79535-47bb-0310-9956-ffa450edef68master
@@ -5,7 +5,7 @@ | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional; | |||
package org.apache.antlib.xml; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
@@ -19,9 +19,8 @@ import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.stream.StreamResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.tools.ant.taskdefs.XSLTLiaison; | |||
import org.apache.tools.ant.taskdefs.XSLTLogger; | |||
import org.apache.tools.ant.taskdefs.XSLTLoggerAware; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.logger.LogEnabled; | |||
/** | |||
* Concrete liaison for XSLT processor implementing TraX. (ie JAXP 1.1) | |||
@@ -30,30 +29,29 @@ import org.apache.tools.ant.taskdefs.XSLTLoggerAware; | |||
* @author <a href="mailto:dims@yahoo.com">Davanum Srinivas</a> | |||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
*/ | |||
public class TraXLiaison implements XSLTLiaison, ErrorListener, XSLTLoggerAware | |||
public class TraXLiaison | |||
extends AbstractLogEnabled | |||
implements XSLTLiaison, ErrorListener | |||
{ | |||
/** | |||
* The trax TransformerFactory | |||
*/ | |||
private TransformerFactory tfactory = null; | |||
private TransformerFactory tfactory; | |||
/** | |||
* stylesheet stream, close it asap | |||
*/ | |||
private FileInputStream xslStream = null; | |||
private FileInputStream xslStream; | |||
/** | |||
* Stylesheet template | |||
*/ | |||
private Templates templates = null; | |||
private Templates templates; | |||
/** | |||
* transformer | |||
*/ | |||
private Transformer transformer = null; | |||
private XSLTLogger logger; | |||
private Transformer transformer; | |||
public TraXLiaison() | |||
throws Exception | |||
@@ -62,11 +60,6 @@ public class TraXLiaison implements XSLTLiaison, ErrorListener, XSLTLoggerAware | |||
tfactory.setErrorListener( this ); | |||
} | |||
public void setLogger( XSLTLogger l ) | |||
{ | |||
logger = l; | |||
} | |||
public void setOutputtype( String type ) | |||
throws Exception | |||
{ | |||
@@ -214,7 +207,7 @@ public class TraXLiaison implements XSLTLiaison, ErrorListener, XSLTLoggerAware | |||
msg.append( " Cause: " + e.getCause() ); | |||
} | |||
logger.log( msg.toString() ); | |||
getLogger().info( msg.toString() ); | |||
} | |||
}//-- TraXLiaison |
@@ -5,7 +5,7 @@ | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional; | |||
package org.apache.antlib.xml; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
@@ -44,9 +44,9 @@ import org.xml.sax.helpers.ParserAdapter; | |||
* @author Raphael Pierquin <a href="mailto:raphael.pierquin@agisphere.com"> | |||
* raphael.pierquin@agisphere.com</a> | |||
*/ | |||
public class XMLValidateTask extends Task | |||
public class XMLValidateTask | |||
extends Task | |||
{ | |||
/** | |||
* The default implementation parser classname used by the task to process | |||
* validation. | |||
@@ -591,7 +591,7 @@ public class XMLValidateTask extends Task | |||
urlDTDs.put( publicId, urldtd ); | |||
} | |||
} | |||
catch( java.net.MalformedURLException e ) | |||
catch( MalformedURLException e ) | |||
{ | |||
//ignored | |||
} |
@@ -5,7 +5,7 @@ | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
package org.apache.antlib.xml; | |||
import java.io.File; | |||
@@ -18,7 +18,6 @@ import java.io.File; | |||
*/ | |||
public interface XSLTLiaison | |||
{ | |||
/** | |||
* the file protocol prefix for systemid. This file protocol must be | |||
* appended to an absolute path. Typically: <tt>FILE_PROTOCOL_PREFIX + |
@@ -0,0 +1,46 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.antlib.xml; | |||
import org.apache.myrmidon.api.TaskException; | |||
public class XSLTParam | |||
{ | |||
private String m_name; | |||
private String m_expression; | |||
public void setExpression( String expression ) | |||
{ | |||
m_expression = expression; | |||
} | |||
public void setName( String name ) | |||
{ | |||
m_name = name; | |||
} | |||
public String getExpression() | |||
throws TaskException | |||
{ | |||
if( m_expression == null ) | |||
{ | |||
throw new TaskException( "Expression attribute is missing." ); | |||
} | |||
return m_expression; | |||
} | |||
public String getName() | |||
throws TaskException | |||
{ | |||
if( m_name == null ) | |||
{ | |||
throw new TaskException( "Name attribute is missing." ); | |||
} | |||
return m_name; | |||
} | |||
} |
@@ -5,15 +5,18 @@ | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
package org.apache.antlib.xml; | |||
import java.io.File; | |||
import java.util.Enumeration; | |||
import java.util.Vector; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.AntClassLoader; | |||
import org.apache.tools.ant.DirectoryScanner; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.taskdefs.MatchingTask; | |||
import org.apache.tools.ant.types.Path; | |||
import org.apache.tools.ant.types.Reference; | |||
import org.apache.tools.ant.util.FileUtils; | |||
@@ -41,44 +44,28 @@ import org.apache.tools.ant.util.FileUtils; | |||
*/ | |||
public class XSLTProcess | |||
extends MatchingTask | |||
implements XSLTLogger | |||
{ | |||
private File destDir = null; | |||
private File baseDir = null; | |||
private String xslFile = null; | |||
private String targetExtension = ".html"; | |||
private Vector params = new Vector(); | |||
private File inFile = null; | |||
private File outFile = null; | |||
private Path classpath = null; | |||
private boolean stylesheetLoaded = false; | |||
private boolean force = false; | |||
private String outputtype = null; | |||
private FileUtils fileUtils; | |||
private XSLTLiaison liaison; | |||
private String processor; | |||
public void log( String msg ) | |||
{ | |||
getLogger().info( msg ); | |||
} | |||
private File m_destDir; | |||
private File m_baseDir; | |||
private String m_xslFile; | |||
private String m_targetExtension = ".html"; | |||
private ArrayList m_params = new ArrayList(); | |||
private File m_inFile; | |||
private File m_outFile; | |||
private Path m_classpath; | |||
private boolean m_stylesheetLoaded; | |||
private boolean m_force; | |||
private String m_outputtype; | |||
private FileUtils m_fileUtils; | |||
private XSLTLiaison m_liaison; | |||
private String m_processor; | |||
/** | |||
* Creates a new XSLTProcess Task. | |||
*/ | |||
public XSLTProcess() | |||
{ | |||
fileUtils = FileUtils.newFileUtils(); | |||
m_fileUtils = FileUtils.newFileUtils(); | |||
}//-- setForce | |||
/** | |||
@@ -88,7 +75,7 @@ public class XSLTProcess | |||
*/ | |||
public void setBasedir( File dir ) | |||
{ | |||
baseDir = dir; | |||
m_baseDir = dir; | |||
} | |||
/** | |||
@@ -112,7 +99,7 @@ public class XSLTProcess | |||
throws TaskException | |||
{ | |||
createClasspath().setRefid( r ); | |||
}//-- setSourceDir | |||
} | |||
/** | |||
* Set the destination directory into which the XSL result files should be | |||
@@ -122,8 +109,8 @@ public class XSLTProcess | |||
*/ | |||
public void setDestdir( File dir ) | |||
{ | |||
destDir = dir; | |||
}//-- setDestDir | |||
m_destDir = dir; | |||
} | |||
/** | |||
* Set the desired file extension to be used for the target | |||
@@ -132,8 +119,8 @@ public class XSLTProcess | |||
*/ | |||
public void setExtension( String name ) | |||
{ | |||
targetExtension = name; | |||
}//-- execute | |||
m_targetExtension = name; | |||
} | |||
/** | |||
* Set whether to check dependencies, or always generate. | |||
@@ -142,7 +129,7 @@ public class XSLTProcess | |||
*/ | |||
public void setForce( boolean force ) | |||
{ | |||
this.force = force; | |||
this.m_force = force; | |||
} | |||
/** | |||
@@ -152,7 +139,7 @@ public class XSLTProcess | |||
*/ | |||
public void setIn( File inFile ) | |||
{ | |||
this.inFile = inFile; | |||
this.m_inFile = inFile; | |||
} | |||
/** | |||
@@ -162,7 +149,7 @@ public class XSLTProcess | |||
*/ | |||
public void setOut( File outFile ) | |||
{ | |||
this.outFile = outFile; | |||
this.m_outFile = outFile; | |||
} | |||
/** | |||
@@ -174,12 +161,12 @@ public class XSLTProcess | |||
*/ | |||
public void setOutputtype( String type ) | |||
{ | |||
this.outputtype = type; | |||
this.m_outputtype = type; | |||
} | |||
public void setProcessor( String processor ) | |||
{ | |||
this.processor = processor; | |||
this.m_processor = processor; | |||
}//-- setDestDir | |||
/** | |||
@@ -190,7 +177,7 @@ public class XSLTProcess | |||
*/ | |||
public void setStyle( String xslFile ) | |||
{ | |||
this.xslFile = xslFile; | |||
this.m_xslFile = xslFile; | |||
} | |||
/** | |||
@@ -201,17 +188,17 @@ public class XSLTProcess | |||
public Path createClasspath() | |||
throws TaskException | |||
{ | |||
if( classpath == null ) | |||
if( m_classpath == null ) | |||
{ | |||
classpath = new Path( project ); | |||
m_classpath = new Path( project ); | |||
} | |||
return classpath.createPath(); | |||
return m_classpath.createPath(); | |||
} | |||
public Param createParam() | |||
public XSLTParam createParam() | |||
{ | |||
Param p = new Param(); | |||
params.addElement( p ); | |||
XSLTParam p = new XSLTParam(); | |||
m_params.add( p ); | |||
return p; | |||
}//-- XSLTProcess | |||
@@ -228,32 +215,28 @@ public class XSLTProcess | |||
String[] list; | |||
String[] dirs; | |||
if( xslFile == null ) | |||
if( m_xslFile == null ) | |||
{ | |||
throw new TaskException( "no stylesheet specified" ); | |||
} | |||
if( baseDir == null ) | |||
if( m_baseDir == null ) | |||
{ | |||
baseDir = getBaseDirectory(); | |||
m_baseDir = getBaseDirectory(); | |||
} | |||
liaison = getLiaison(); | |||
m_liaison = getLiaison(); | |||
// check if liaison wants to log errors using us as logger | |||
if( liaison instanceof XSLTLoggerAware ) | |||
{ | |||
( (XSLTLoggerAware)liaison ).setLogger( this ); | |||
} | |||
log( "Using " + liaison.getClass().toString(), Project.MSG_VERBOSE ); | |||
setupLogger( m_liaison ); | |||
File stylesheet = resolveFile( xslFile ); | |||
log( "Using " + m_liaison.getClass().toString(), Project.MSG_VERBOSE ); | |||
File stylesheet = resolveFile( m_xslFile ); | |||
// if we have an in file and out then process them | |||
if( inFile != null && outFile != null ) | |||
if( m_inFile != null && m_outFile != null ) | |||
{ | |||
process( inFile, outFile, stylesheet ); | |||
process( m_inFile, m_outFile, stylesheet ); | |||
return; | |||
} | |||
@@ -262,28 +245,28 @@ public class XSLTProcess | |||
* in batch processing mode. | |||
*/ | |||
//-- make sure Source directory exists... | |||
if( destDir == null ) | |||
if( m_destDir == null ) | |||
{ | |||
String msg = "destdir attributes must be set!"; | |||
throw new TaskException( msg ); | |||
} | |||
scanner = getDirectoryScanner( baseDir ); | |||
log( "Transforming into " + destDir, Project.MSG_INFO ); | |||
scanner = getDirectoryScanner( m_baseDir ); | |||
log( "Transforming into " + m_destDir, Project.MSG_INFO ); | |||
// Process all the files marked for styling | |||
list = scanner.getIncludedFiles(); | |||
for( int i = 0; i < list.length; ++i ) | |||
{ | |||
process( baseDir, list[ i ], destDir, stylesheet ); | |||
process( m_baseDir, list[ i ], m_destDir, stylesheet ); | |||
} | |||
// Process all the directoried marked for styling | |||
dirs = scanner.getIncludedDirectories(); | |||
for( int j = 0; j < dirs.length; ++j ) | |||
{ | |||
list = new File( baseDir, dirs[ j ] ).list(); | |||
list = new File( m_baseDir, dirs[ j ] ).list(); | |||
for( int i = 0; i < list.length; ++i ) | |||
process( baseDir, list[ i ], destDir, stylesheet ); | |||
process( m_baseDir, list[ i ], m_destDir, stylesheet ); | |||
} | |||
} | |||
@@ -292,13 +275,13 @@ public class XSLTProcess | |||
{ | |||
// if processor wasn't specified, see if TraX is available. If not, | |||
// default it to xslp or xalan, depending on which is in the classpath | |||
if( liaison == null ) | |||
if( m_liaison == null ) | |||
{ | |||
if( processor != null ) | |||
if( m_processor != null ) | |||
{ | |||
try | |||
{ | |||
resolveProcessor( processor ); | |||
resolveProcessor( m_processor ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
@@ -341,7 +324,7 @@ public class XSLTProcess | |||
} | |||
} | |||
} | |||
return liaison; | |||
return m_liaison; | |||
} | |||
/** | |||
@@ -353,26 +336,27 @@ public class XSLTProcess | |||
protected void configureLiaison( File stylesheet ) | |||
throws TaskException | |||
{ | |||
if( stylesheetLoaded ) | |||
if( m_stylesheetLoaded ) | |||
{ | |||
return; | |||
} | |||
stylesheetLoaded = true; | |||
m_stylesheetLoaded = true; | |||
try | |||
{ | |||
log( "Loading stylesheet " + stylesheet, Project.MSG_INFO ); | |||
liaison.setStylesheet( stylesheet ); | |||
for( Enumeration e = params.elements(); e.hasMoreElements(); ) | |||
getLogger().info( "Loading stylesheet " + stylesheet ); | |||
m_liaison.setStylesheet( stylesheet ); | |||
final Iterator params = m_params.iterator(); | |||
while( params.hasNext() ) | |||
{ | |||
Param p = (Param)e.nextElement(); | |||
liaison.addParam( p.getName(), p.getExpression() ); | |||
final XSLTParam param = (XSLTParam)params.next(); | |||
m_liaison.addParam( param.getName(), param.getExpression() ); | |||
} | |||
} | |||
catch( Exception ex ) | |||
catch( final Exception e ) | |||
{ | |||
log( "Failed to read stylesheet " + stylesheet, Project.MSG_INFO ); | |||
throw new TaskException( "Error", ex ); | |||
getLogger().info( "Failed to read stylesheet " + stylesheet ); | |||
throw new TaskException( "Error", e ); | |||
} | |||
} | |||
@@ -401,13 +385,13 @@ public class XSLTProcess | |||
private Class loadClass( String classname ) | |||
throws Exception | |||
{ | |||
if( classpath == null ) | |||
if( m_classpath == null ) | |||
{ | |||
return Class.forName( classname ); | |||
} | |||
else | |||
{ | |||
AntClassLoader al = new AntClassLoader( project, classpath ); | |||
AntClassLoader al = new AntClassLoader( project, m_classpath ); | |||
Class c = al.loadClass( classname ); | |||
AntClassLoader.initializeClass( c ); | |||
return c; | |||
@@ -429,7 +413,7 @@ public class XSLTProcess | |||
throws TaskException | |||
{ | |||
String fileExt = targetExtension; | |||
String fileExt = m_targetExtension; | |||
File outFile = null; | |||
File inFile = null; | |||
@@ -446,7 +430,7 @@ public class XSLTProcess | |||
{ | |||
outFile = new File( destDir, xmlFile + fileExt ); | |||
} | |||
if( force || | |||
if( m_force || | |||
inFile.lastModified() > outFile.lastModified() || | |||
styleSheetLastModified > outFile.lastModified() ) | |||
{ | |||
@@ -454,14 +438,14 @@ public class XSLTProcess | |||
getLogger().info( "Processing " + inFile + " to " + outFile ); | |||
configureLiaison( stylesheet ); | |||
liaison.transform( inFile, outFile ); | |||
m_liaison.transform( inFile, outFile ); | |||
} | |||
} | |||
catch( Exception ex ) | |||
{ | |||
// If failed to process document, must delete target document, | |||
// or it will not attempt to process it the second time | |||
log( "Failed to process " + inFile, Project.MSG_INFO ); | |||
getLogger().info( "Failed to process " + inFile ); | |||
if( outFile != null ) | |||
{ | |||
outFile.delete(); | |||
@@ -477,23 +461,24 @@ public class XSLTProcess | |||
{ | |||
try | |||
{ | |||
long styleSheetLastModified = stylesheet.lastModified(); | |||
log( "In file " + inFile + " time: " + inFile.lastModified(), Project.MSG_DEBUG ); | |||
log( "Out file " + outFile + " time: " + outFile.lastModified(), Project.MSG_DEBUG ); | |||
log( "Style file " + xslFile + " time: " + styleSheetLastModified, Project.MSG_DEBUG ); | |||
if( force || | |||
final long styleSheetLastModified = stylesheet.lastModified(); | |||
getLogger().debug( "In file " + inFile + " time: " + inFile.lastModified() ); | |||
getLogger().debug( "Out file " + outFile + " time: " + outFile.lastModified() ); | |||
getLogger().debug( "Style file " + m_xslFile + " time: " + styleSheetLastModified ); | |||
if( m_force || | |||
inFile.lastModified() > outFile.lastModified() || | |||
styleSheetLastModified > outFile.lastModified() ) | |||
{ | |||
ensureDirectoryFor( outFile ); | |||
log( "Processing " + inFile + " to " + outFile, Project.MSG_INFO ); | |||
getLogger().info( "Processing " + inFile + " to " + outFile ); | |||
configureLiaison( stylesheet ); | |||
liaison.transform( inFile, outFile ); | |||
m_liaison.transform( inFile, outFile ); | |||
} | |||
} | |||
catch( Exception ex ) | |||
{ | |||
log( "Failed to process " + inFile, Project.MSG_INFO ); | |||
getLogger().info( "Failed to process " + inFile ); | |||
if( outFile != null ) | |||
outFile.delete(); | |||
throw new TaskException( "Error", ex ); | |||
@@ -514,50 +499,18 @@ public class XSLTProcess | |||
{ | |||
final Class clazz = | |||
loadClass( "org.apache.tools.ant.taskdefs.optional.TraXLiaison" ); | |||
liaison = (XSLTLiaison)clazz.newInstance(); | |||
m_liaison = (XSLTLiaison)clazz.newInstance(); | |||
} | |||
else if( proc.equals( "xalan" ) ) | |||
{ | |||
final Class clazz = | |||
loadClass( "org.apache.tools.ant.taskdefs.optional.XalanLiaison" ); | |||
liaison = (XSLTLiaison)clazz.newInstance(); | |||
m_liaison = (XSLTLiaison)clazz.newInstance(); | |||
} | |||
else | |||
{ | |||
liaison = (XSLTLiaison)loadClass( proc ).newInstance(); | |||
} | |||
} | |||
public class Param | |||
{ | |||
private String name = null; | |||
private String expression = null; | |||
public void setExpression( String expression ) | |||
{ | |||
this.expression = expression; | |||
} | |||
public void setName( String name ) | |||
{ | |||
this.name = name; | |||
} | |||
public String getExpression() | |||
throws TaskException | |||
{ | |||
if( expression == null ) | |||
throw new TaskException( "Expression attribute is missing." ); | |||
return expression; | |||
} | |||
public String getName() | |||
throws TaskException | |||
{ | |||
if( name == null ) | |||
throw new TaskException( "Name attribute is missing." ); | |||
return name; | |||
m_liaison = (XSLTLiaison)loadClass( proc ).newInstance(); | |||
} | |||
} | |||
}//-- XSLTProcess | |||
} |
@@ -5,14 +5,13 @@ | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional; | |||
package org.apache.antlib.xml; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.taskdefs.XSLTLiaison; | |||
import org.apache.xalan.xslt.XSLTInputSource; | |||
import org.apache.xalan.xslt.XSLTProcessor; | |||
import org.apache.xalan.xslt.XSLTProcessorFactory; | |||
@@ -24,11 +23,11 @@ import org.apache.xalan.xslt.XSLTResultTarget; | |||
* @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
*/ | |||
public class XalanLiaison implements XSLTLiaison | |||
public class XalanLiaison | |||
implements XSLTLiaison | |||
{ | |||
protected XSLTProcessor processor; | |||
protected File stylesheet; | |||
private XSLTProcessor processor; | |||
private File stylesheet; | |||
public XalanLiaison() | |||
throws Exception |
@@ -1,18 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
public interface XSLTLogger | |||
{ | |||
/** | |||
* Log a message. | |||
* | |||
* @param msg Description of Parameter | |||
*/ | |||
void log( String msg ); | |||
} |
@@ -1,13 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
public interface XSLTLoggerAware | |||
{ | |||
void setLogger( XSLTLogger l ); | |||
} |
@@ -1,563 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
import java.io.File; | |||
import java.util.Enumeration; | |||
import java.util.Vector; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.AntClassLoader; | |||
import org.apache.tools.ant.DirectoryScanner; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.types.Path; | |||
import org.apache.tools.ant.types.Reference; | |||
import org.apache.tools.ant.util.FileUtils; | |||
/** | |||
* A Task to process via XSLT a set of XML documents. This is useful for | |||
* building views of XML based documentation. arguments: | |||
* <ul> | |||
* <li> basedir | |||
* <li> destdir | |||
* <li> style | |||
* <li> includes | |||
* <li> excludes | |||
* </ul> | |||
* Of these arguments, the <b>sourcedir</b> and <b>destdir</b> are required. <p> | |||
* | |||
* This task will recursively scan the sourcedir and destdir looking for XML | |||
* documents to process via XSLT. Any other files, such as images, or html files | |||
* in the source directory will be copied into the destination directory. | |||
* | |||
* @author <a href="mailto:kvisco@exoffice.com">Keith Visco</a> | |||
* @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
* @author <a href="mailto:russgold@acm.org">Russell Gold</a> | |||
* @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
*/ | |||
public class XSLTProcess | |||
extends MatchingTask | |||
implements XSLTLogger | |||
{ | |||
private File destDir = null; | |||
private File baseDir = null; | |||
private String xslFile = null; | |||
private String targetExtension = ".html"; | |||
private Vector params = new Vector(); | |||
private File inFile = null; | |||
private File outFile = null; | |||
private Path classpath = null; | |||
private boolean stylesheetLoaded = false; | |||
private boolean force = false; | |||
private String outputtype = null; | |||
private FileUtils fileUtils; | |||
private XSLTLiaison liaison; | |||
private String processor; | |||
public void log( String msg ) | |||
{ | |||
getLogger().info( msg ); | |||
} | |||
/** | |||
* Creates a new XSLTProcess Task. | |||
*/ | |||
public XSLTProcess() | |||
{ | |||
fileUtils = FileUtils.newFileUtils(); | |||
}//-- setForce | |||
/** | |||
* Set the base directory. | |||
* | |||
* @param dir The new Basedir value | |||
*/ | |||
public void setBasedir( File dir ) | |||
{ | |||
baseDir = dir; | |||
} | |||
/** | |||
* Set the classpath to load the Processor through (attribute). | |||
* | |||
* @param classpath The new Classpath value | |||
*/ | |||
public void setClasspath( Path classpath ) | |||
throws TaskException | |||
{ | |||
createClasspath().append( classpath ); | |||
} | |||
/** | |||
* Set the classpath to load the Processor through via reference | |||
* (attribute). | |||
* | |||
* @param r The new ClasspathRef value | |||
*/ | |||
public void setClasspathRef( Reference r ) | |||
throws TaskException | |||
{ | |||
createClasspath().setRefid( r ); | |||
}//-- setSourceDir | |||
/** | |||
* Set the destination directory into which the XSL result files should be | |||
* copied to | |||
* | |||
* @param dir The new Destdir value | |||
*/ | |||
public void setDestdir( File dir ) | |||
{ | |||
destDir = dir; | |||
}//-- setDestDir | |||
/** | |||
* Set the desired file extension to be used for the target | |||
* | |||
* @param name the extension to use | |||
*/ | |||
public void setExtension( String name ) | |||
{ | |||
targetExtension = name; | |||
}//-- execute | |||
/** | |||
* Set whether to check dependencies, or always generate. | |||
* | |||
* @param force The new Force value | |||
*/ | |||
public void setForce( boolean force ) | |||
{ | |||
this.force = force; | |||
} | |||
/** | |||
* Sets an input xml file to be styled | |||
* | |||
* @param inFile The new In value | |||
*/ | |||
public void setIn( File inFile ) | |||
{ | |||
this.inFile = inFile; | |||
} | |||
/** | |||
* Sets an out file | |||
* | |||
* @param outFile The new Out value | |||
*/ | |||
public void setOut( File outFile ) | |||
{ | |||
this.outFile = outFile; | |||
} | |||
/** | |||
* Set the output type to use for the transformation. Only "xml" (the | |||
* default) is guaranteed to work for all parsers. Xalan2 also supports | |||
* "html" and "text". | |||
* | |||
* @param type the output method to use | |||
*/ | |||
public void setOutputtype( String type ) | |||
{ | |||
this.outputtype = type; | |||
} | |||
public void setProcessor( String processor ) | |||
{ | |||
this.processor = processor; | |||
}//-- setDestDir | |||
/** | |||
* Sets the file to use for styling relative to the base directory of this | |||
* task. | |||
* | |||
* @param xslFile The new Style value | |||
*/ | |||
public void setStyle( String xslFile ) | |||
{ | |||
this.xslFile = xslFile; | |||
} | |||
/** | |||
* Set the classpath to load the Processor through (nested element). | |||
* | |||
* @return Description of the Returned Value | |||
*/ | |||
public Path createClasspath() | |||
throws TaskException | |||
{ | |||
if( classpath == null ) | |||
{ | |||
classpath = new Path( project ); | |||
} | |||
return classpath.createPath(); | |||
} | |||
public Param createParam() | |||
{ | |||
Param p = new Param(); | |||
params.addElement( p ); | |||
return p; | |||
}//-- XSLTProcess | |||
/** | |||
* Executes the task. | |||
* | |||
* @exception TaskException Description of Exception | |||
*/ | |||
public void execute() | |||
throws TaskException | |||
{ | |||
DirectoryScanner scanner; | |||
String[] list; | |||
String[] dirs; | |||
if( xslFile == null ) | |||
{ | |||
throw new TaskException( "no stylesheet specified" ); | |||
} | |||
if( baseDir == null ) | |||
{ | |||
baseDir = getBaseDirectory(); | |||
} | |||
liaison = getLiaison(); | |||
// check if liaison wants to log errors using us as logger | |||
if( liaison instanceof XSLTLoggerAware ) | |||
{ | |||
( (XSLTLoggerAware)liaison ).setLogger( this ); | |||
} | |||
log( "Using " + liaison.getClass().toString(), Project.MSG_VERBOSE ); | |||
File stylesheet = resolveFile( xslFile ); | |||
// if we have an in file and out then process them | |||
if( inFile != null && outFile != null ) | |||
{ | |||
process( inFile, outFile, stylesheet ); | |||
return; | |||
} | |||
/* | |||
* if we get here, in and out have not been specified, we are | |||
* in batch processing mode. | |||
*/ | |||
//-- make sure Source directory exists... | |||
if( destDir == null ) | |||
{ | |||
String msg = "destdir attributes must be set!"; | |||
throw new TaskException( msg ); | |||
} | |||
scanner = getDirectoryScanner( baseDir ); | |||
log( "Transforming into " + destDir, Project.MSG_INFO ); | |||
// Process all the files marked for styling | |||
list = scanner.getIncludedFiles(); | |||
for( int i = 0; i < list.length; ++i ) | |||
{ | |||
process( baseDir, list[ i ], destDir, stylesheet ); | |||
} | |||
// Process all the directoried marked for styling | |||
dirs = scanner.getIncludedDirectories(); | |||
for( int j = 0; j < dirs.length; ++j ) | |||
{ | |||
list = new File( baseDir, dirs[ j ] ).list(); | |||
for( int i = 0; i < list.length; ++i ) | |||
process( baseDir, list[ i ], destDir, stylesheet ); | |||
} | |||
} | |||
protected XSLTLiaison getLiaison() | |||
throws TaskException | |||
{ | |||
// if processor wasn't specified, see if TraX is available. If not, | |||
// default it to xslp or xalan, depending on which is in the classpath | |||
if( liaison == null ) | |||
{ | |||
if( processor != null ) | |||
{ | |||
try | |||
{ | |||
resolveProcessor( processor ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
throw new TaskException( "Error", e ); | |||
} | |||
} | |||
else | |||
{ | |||
try | |||
{ | |||
resolveProcessor( "trax" ); | |||
} | |||
catch( Throwable e1 ) | |||
{ | |||
try | |||
{ | |||
resolveProcessor( "xalan" ); | |||
} | |||
catch( Throwable e2 ) | |||
{ | |||
try | |||
{ | |||
resolveProcessor( "adaptx" ); | |||
} | |||
catch( Throwable e3 ) | |||
{ | |||
try | |||
{ | |||
resolveProcessor( "xslp" ); | |||
} | |||
catch( Throwable e4 ) | |||
{ | |||
e4.printStackTrace(); | |||
e3.printStackTrace(); | |||
e2.printStackTrace(); | |||
throw new TaskException( "Error", e1 ); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return liaison; | |||
} | |||
/** | |||
* Loads the stylesheet and set xsl:param parameters. | |||
* | |||
* @param stylesheet Description of Parameter | |||
* @exception TaskException Description of Exception | |||
*/ | |||
protected void configureLiaison( File stylesheet ) | |||
throws TaskException | |||
{ | |||
if( stylesheetLoaded ) | |||
{ | |||
return; | |||
} | |||
stylesheetLoaded = true; | |||
try | |||
{ | |||
log( "Loading stylesheet " + stylesheet, Project.MSG_INFO ); | |||
liaison.setStylesheet( stylesheet ); | |||
for( Enumeration e = params.elements(); e.hasMoreElements(); ) | |||
{ | |||
Param p = (Param)e.nextElement(); | |||
liaison.addParam( p.getName(), p.getExpression() ); | |||
} | |||
} | |||
catch( Exception ex ) | |||
{ | |||
log( "Failed to read stylesheet " + stylesheet, Project.MSG_INFO ); | |||
throw new TaskException( "Error", ex ); | |||
} | |||
} | |||
private void ensureDirectoryFor( File targetFile ) | |||
throws TaskException | |||
{ | |||
File directory = new File( targetFile.getParent() ); | |||
if( !directory.exists() ) | |||
{ | |||
if( !directory.mkdirs() ) | |||
{ | |||
throw new TaskException( "Unable to create directory: " | |||
+ directory.getAbsolutePath() ); | |||
} | |||
} | |||
} | |||
/** | |||
* Load named class either via the system classloader or a given custom | |||
* classloader. | |||
* | |||
* @param classname Description of Parameter | |||
* @return Description of the Returned Value | |||
* @exception Exception Description of Exception | |||
*/ | |||
private Class loadClass( String classname ) | |||
throws Exception | |||
{ | |||
if( classpath == null ) | |||
{ | |||
return Class.forName( classname ); | |||
} | |||
else | |||
{ | |||
AntClassLoader al = new AntClassLoader( project, classpath ); | |||
Class c = al.loadClass( classname ); | |||
AntClassLoader.initializeClass( c ); | |||
return c; | |||
} | |||
} | |||
/** | |||
* Processes the given input XML file and stores the result in the given | |||
* resultFile. | |||
* | |||
* @param baseDir Description of Parameter | |||
* @param xmlFile Description of Parameter | |||
* @param destDir Description of Parameter | |||
* @param stylesheet Description of Parameter | |||
* @exception TaskException Description of Exception | |||
*/ | |||
private void process( File baseDir, String xmlFile, File destDir, | |||
File stylesheet ) | |||
throws TaskException | |||
{ | |||
String fileExt = targetExtension; | |||
File outFile = null; | |||
File inFile = null; | |||
try | |||
{ | |||
long styleSheetLastModified = stylesheet.lastModified(); | |||
inFile = new File( baseDir, xmlFile ); | |||
int dotPos = xmlFile.lastIndexOf( '.' ); | |||
if( dotPos > 0 ) | |||
{ | |||
outFile = new File( destDir, xmlFile.substring( 0, xmlFile.lastIndexOf( '.' ) ) + fileExt ); | |||
} | |||
else | |||
{ | |||
outFile = new File( destDir, xmlFile + fileExt ); | |||
} | |||
if( force || | |||
inFile.lastModified() > outFile.lastModified() || | |||
styleSheetLastModified > outFile.lastModified() ) | |||
{ | |||
ensureDirectoryFor( outFile ); | |||
getLogger().info( "Processing " + inFile + " to " + outFile ); | |||
configureLiaison( stylesheet ); | |||
liaison.transform( inFile, outFile ); | |||
} | |||
} | |||
catch( Exception ex ) | |||
{ | |||
// If failed to process document, must delete target document, | |||
// or it will not attempt to process it the second time | |||
log( "Failed to process " + inFile, Project.MSG_INFO ); | |||
if( outFile != null ) | |||
{ | |||
outFile.delete(); | |||
} | |||
throw new TaskException( "Error", ex ); | |||
} | |||
}//-- processXML | |||
private void process( File inFile, File outFile, File stylesheet ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
long styleSheetLastModified = stylesheet.lastModified(); | |||
log( "In file " + inFile + " time: " + inFile.lastModified(), Project.MSG_DEBUG ); | |||
log( "Out file " + outFile + " time: " + outFile.lastModified(), Project.MSG_DEBUG ); | |||
log( "Style file " + xslFile + " time: " + styleSheetLastModified, Project.MSG_DEBUG ); | |||
if( force || | |||
inFile.lastModified() > outFile.lastModified() || | |||
styleSheetLastModified > outFile.lastModified() ) | |||
{ | |||
ensureDirectoryFor( outFile ); | |||
log( "Processing " + inFile + " to " + outFile, Project.MSG_INFO ); | |||
configureLiaison( stylesheet ); | |||
liaison.transform( inFile, outFile ); | |||
} | |||
} | |||
catch( Exception ex ) | |||
{ | |||
log( "Failed to process " + inFile, Project.MSG_INFO ); | |||
if( outFile != null ) | |||
outFile.delete(); | |||
throw new TaskException( "Error", ex ); | |||
} | |||
} | |||
/** | |||
* Load processor here instead of in setProcessor - this will be called from | |||
* within execute, so we have access to the latest classpath. | |||
* | |||
* @param proc Description of Parameter | |||
* @exception Exception Description of Exception | |||
*/ | |||
private void resolveProcessor( String proc ) | |||
throws Exception | |||
{ | |||
if( proc.equals( "trax" ) ) | |||
{ | |||
final Class clazz = | |||
loadClass( "org.apache.tools.ant.taskdefs.optional.TraXLiaison" ); | |||
liaison = (XSLTLiaison)clazz.newInstance(); | |||
} | |||
else if( proc.equals( "xalan" ) ) | |||
{ | |||
final Class clazz = | |||
loadClass( "org.apache.tools.ant.taskdefs.optional.XalanLiaison" ); | |||
liaison = (XSLTLiaison)clazz.newInstance(); | |||
} | |||
else | |||
{ | |||
liaison = (XSLTLiaison)loadClass( proc ).newInstance(); | |||
} | |||
} | |||
public class Param | |||
{ | |||
private String name = null; | |||
private String expression = null; | |||
public void setExpression( String expression ) | |||
{ | |||
this.expression = expression; | |||
} | |||
public void setName( String name ) | |||
{ | |||
this.name = name; | |||
} | |||
public String getExpression() | |||
throws TaskException | |||
{ | |||
if( expression == null ) | |||
throw new TaskException( "Expression attribute is missing." ); | |||
return expression; | |||
} | |||
public String getName() | |||
throws TaskException | |||
{ | |||
if( name == null ) | |||
throw new TaskException( "Name attribute is missing." ); | |||
return name; | |||
} | |||
} | |||
}//-- XSLTProcess |
@@ -1,75 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
import java.io.File; | |||
/** | |||
* Proxy interface for XSLT processors. | |||
* | |||
* @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
* @see XSLTProcess | |||
*/ | |||
public interface XSLTLiaison | |||
{ | |||
/** | |||
* the file protocol prefix for systemid. This file protocol must be | |||
* appended to an absolute path. Typically: <tt>FILE_PROTOCOL_PREFIX + | |||
* file.getAbsolutePath()</tt> This is not correct in specification terms | |||
* since an absolute url in Unix is file:// + file.getAbsolutePath() while | |||
* it is file:/// + file.getAbsolutePath() under Windows. Whatever, it | |||
* should not be a problem to put file:/// in every case since most parsers | |||
* for now incorrectly makes no difference between it.. and users also have | |||
* problem with that :) | |||
*/ | |||
String FILE_PROTOCOL_PREFIX = "file:///"; | |||
/** | |||
* set the stylesheet to use for the transformation. | |||
* | |||
* @param stylesheet the stylesheet to be used for transformation. | |||
* @exception Exception Description of Exception | |||
*/ | |||
void setStylesheet( File stylesheet ) | |||
throws Exception; | |||
/** | |||
* Add a parameter to be set during the XSL transformation. | |||
* | |||
* @param name the parameter name. | |||
* @param expression the parameter value as an expression string. | |||
* @throws Exception thrown if any problems happens. | |||
*/ | |||
void addParam( String name, String expression ) | |||
throws Exception; | |||
/** | |||
* set the output type to use for the transformation. Only "xml" (the | |||
* default) is guaranteed to work for all parsers. Xalan2 also supports | |||
* "html" and "text". | |||
* | |||
* @param type the output method to use | |||
* @exception Exception Description of Exception | |||
*/ | |||
void setOutputtype( String type ) | |||
throws Exception; | |||
/** | |||
* Perform the transformation of a file into another. | |||
* | |||
* @param infile the input file, probably an XML one. :-) | |||
* @param outfile the output file resulting from the transformation | |||
* @see #setStylesheet(File) | |||
* @throws Exception thrown if any problems happens. | |||
*/ | |||
void transform( File infile, File outfile ) | |||
throws Exception; | |||
}//-- XSLTLiaison |
@@ -1,18 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
public interface XSLTLogger | |||
{ | |||
/** | |||
* Log a message. | |||
* | |||
* @param msg Description of Parameter | |||
*/ | |||
void log( String msg ); | |||
} |
@@ -1,13 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
public interface XSLTLoggerAware | |||
{ | |||
void setLogger( XSLTLogger l ); | |||
} |
@@ -1,220 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import javax.xml.transform.ErrorListener; | |||
import javax.xml.transform.OutputKeys; | |||
import javax.xml.transform.Templates; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.stream.StreamResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.tools.ant.taskdefs.XSLTLiaison; | |||
import org.apache.tools.ant.taskdefs.XSLTLogger; | |||
import org.apache.tools.ant.taskdefs.XSLTLoggerAware; | |||
/** | |||
* Concrete liaison for XSLT processor implementing TraX. (ie JAXP 1.1) | |||
* | |||
* @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
* @author <a href="mailto:dims@yahoo.com">Davanum Srinivas</a> | |||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
*/ | |||
public class TraXLiaison implements XSLTLiaison, ErrorListener, XSLTLoggerAware | |||
{ | |||
/** | |||
* The trax TransformerFactory | |||
*/ | |||
private TransformerFactory tfactory = null; | |||
/** | |||
* stylesheet stream, close it asap | |||
*/ | |||
private FileInputStream xslStream = null; | |||
/** | |||
* Stylesheet template | |||
*/ | |||
private Templates templates = null; | |||
/** | |||
* transformer | |||
*/ | |||
private Transformer transformer = null; | |||
private XSLTLogger logger; | |||
public TraXLiaison() | |||
throws Exception | |||
{ | |||
tfactory = TransformerFactory.newInstance(); | |||
tfactory.setErrorListener( this ); | |||
} | |||
public void setLogger( XSLTLogger l ) | |||
{ | |||
logger = l; | |||
} | |||
public void setOutputtype( String type ) | |||
throws Exception | |||
{ | |||
transformer.setOutputProperty( OutputKeys.METHOD, type ); | |||
} | |||
//------------------- IMPORTANT | |||
// 1) Don't use the StreamSource(File) ctor. It won't work with | |||
// xalan prior to 2.2 because of systemid bugs. | |||
// 2) Use a stream so that you can close it yourself quickly | |||
// and avoid keeping the handle until the object is garbaged. | |||
// (always keep control), otherwise you won't be able to delete | |||
// the file quickly on windows. | |||
// 3) Always set the systemid to the source for imports, includes... | |||
// in xsl and xml... | |||
public void setStylesheet( File stylesheet ) | |||
throws Exception | |||
{ | |||
xslStream = new FileInputStream( stylesheet ); | |||
StreamSource src = new StreamSource( xslStream ); | |||
src.setSystemId( getSystemId( stylesheet ) ); | |||
templates = tfactory.newTemplates( src ); | |||
transformer = templates.newTransformer(); | |||
transformer.setErrorListener( this ); | |||
} | |||
public void addParam( String name, String value ) | |||
{ | |||
transformer.setParameter( name, value ); | |||
} | |||
public void error( TransformerException e ) | |||
{ | |||
logError( e, "Error" ); | |||
} | |||
public void fatalError( TransformerException e ) | |||
{ | |||
logError( e, "Fatal Error" ); | |||
} | |||
public void transform( File infile, File outfile ) | |||
throws Exception | |||
{ | |||
FileInputStream fis = null; | |||
FileOutputStream fos = null; | |||
try | |||
{ | |||
fis = new FileInputStream( infile ); | |||
fos = new FileOutputStream( outfile ); | |||
StreamSource src = new StreamSource( fis ); | |||
src.setSystemId( getSystemId( infile ) ); | |||
StreamResult res = new StreamResult( fos ); | |||
// not sure what could be the need of this... | |||
res.setSystemId( getSystemId( outfile ) ); | |||
transformer.transform( src, res ); | |||
} | |||
finally | |||
{ | |||
// make sure to close all handles, otherwise the garbage | |||
// collector will close them...whenever possible and | |||
// Windows may complain about not being able to delete files. | |||
try | |||
{ | |||
if( xslStream != null ) | |||
{ | |||
xslStream.close(); | |||
} | |||
} | |||
catch( IOException ignored ) | |||
{ | |||
} | |||
try | |||
{ | |||
if( fis != null ) | |||
{ | |||
fis.close(); | |||
} | |||
} | |||
catch( IOException ignored ) | |||
{ | |||
} | |||
try | |||
{ | |||
if( fos != null ) | |||
{ | |||
fos.close(); | |||
} | |||
} | |||
catch( IOException ignored ) | |||
{ | |||
} | |||
} | |||
} | |||
public void warning( TransformerException e ) | |||
{ | |||
logError( e, "Warning" ); | |||
} | |||
// make sure that the systemid is made of '/' and not '\' otherwise | |||
// crimson will complain that it cannot resolve relative entities | |||
// because it grabs the base uri via lastIndexOf('/') without | |||
// making sure it is really a /'ed path | |||
protected String getSystemId( File file ) | |||
{ | |||
String path = file.getAbsolutePath(); | |||
path = path.replace( '\\', '/' ); | |||
return FILE_PROTOCOL_PREFIX + path; | |||
} | |||
private void logError( TransformerException e, String type ) | |||
{ | |||
StringBuffer msg = new StringBuffer(); | |||
if( e.getLocator() != null ) | |||
{ | |||
if( e.getLocator().getSystemId() != null ) | |||
{ | |||
String url = e.getLocator().getSystemId(); | |||
if( url.startsWith( "file:///" ) ) | |||
url = url.substring( 8 ); | |||
msg.append( url ); | |||
} | |||
else | |||
{ | |||
msg.append( "Unknown file" ); | |||
} | |||
if( e.getLocator().getLineNumber() != -1 ) | |||
{ | |||
msg.append( ":" + e.getLocator().getLineNumber() ); | |||
if( e.getLocator().getColumnNumber() != -1 ) | |||
{ | |||
msg.append( ":" + e.getLocator().getColumnNumber() ); | |||
} | |||
} | |||
} | |||
msg.append( ": " + type + "! " ); | |||
msg.append( e.getMessage() ); | |||
if( e.getCause() != null ) | |||
{ | |||
msg.append( " Cause: " + e.getCause() ); | |||
} | |||
logger.log( msg.toString() ); | |||
} | |||
}//-- TraXLiaison |
@@ -1,654 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileNotFoundException; | |||
import java.io.FileReader; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.util.Enumeration; | |||
import java.util.Hashtable; | |||
import java.util.Vector; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.AntClassLoader; | |||
import org.apache.tools.ant.DirectoryScanner; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.types.FileSet; | |||
import org.apache.tools.ant.types.Path; | |||
import org.apache.tools.ant.types.Reference; | |||
import org.xml.sax.EntityResolver; | |||
import org.xml.sax.ErrorHandler; | |||
import org.xml.sax.InputSource; | |||
import org.xml.sax.Parser; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.SAXNotRecognizedException; | |||
import org.xml.sax.SAXNotSupportedException; | |||
import org.xml.sax.SAXParseException; | |||
import org.xml.sax.XMLReader; | |||
import org.xml.sax.helpers.ParserAdapter; | |||
/** | |||
* The <code>XMLValidateTask</code> checks that an XML document is valid, with a | |||
* SAX validating parser. | |||
* | |||
* @author Raphael Pierquin <a href="mailto:raphael.pierquin@agisphere.com"> | |||
* raphael.pierquin@agisphere.com</a> | |||
*/ | |||
public class XMLValidateTask extends Task | |||
{ | |||
/** | |||
* The default implementation parser classname used by the task to process | |||
* validation. | |||
*/ | |||
// The crimson implementation is shipped with ant. | |||
public static String DEFAULT_XML_READER_CLASSNAME = "org.apache.crimson.parser.XMLReaderImpl"; | |||
protected static String INIT_FAILED_MSG = "Could not start xml validation: "; | |||
// ant task properties | |||
// defaults | |||
protected boolean failOnError = true; | |||
protected boolean warn = true; | |||
protected boolean lenient = false; | |||
protected String readerClassName = DEFAULT_XML_READER_CLASSNAME; | |||
protected File file = null;// file to be validated | |||
protected Vector filesets = new Vector(); | |||
/** | |||
* the parser is viewed as a SAX2 XMLReader. If a SAX1 parser is specified, | |||
* it's wrapped in an adapter that make it behave as a XMLReader. a more | |||
* 'standard' way of doing this would be to use the JAXP1.1 SAXParser | |||
* interface. | |||
*/ | |||
protected XMLReader xmlReader = null;// XMLReader used to validation process | |||
protected ValidatorErrorHandler errorHandler | |||
= new ValidatorErrorHandler();// to report sax parsing errors | |||
protected Hashtable features = new Hashtable(); | |||
/** | |||
* The list of configured DTD locations | |||
*/ | |||
public Vector dtdLocations = new Vector();// sets of file to be validated | |||
protected Path classpath; | |||
/** | |||
* Specify the class name of the SAX parser to be used. (optional) | |||
* | |||
* @param className should be an implementation of SAX2 <code>org.xml.sax.XMLReader</code> | |||
* or SAX2 <code>org.xml.sax.Parser</code>. <p> | |||
* | |||
* if className is an implementation of <code>org.xml.sax.Parser</code> | |||
* , {@link #setLenient(boolean)}, will be ignored. <p> | |||
* | |||
* if not set, the default {@link #DEFAULT_XML_READER_CLASSNAME} will | |||
* be used. | |||
* @see org.xml.sax.XMLReader | |||
* @see org.xml.sax.Parser | |||
*/ | |||
public void setClassName( String className ) | |||
{ | |||
readerClassName = className; | |||
} | |||
/** | |||
* Specify the classpath to be searched to load the parser (optional) | |||
* | |||
* @param classpath The new Classpath value | |||
*/ | |||
public void setClasspath( Path classpath ) | |||
throws TaskException | |||
{ | |||
if( this.classpath == null ) | |||
{ | |||
this.classpath = classpath; | |||
} | |||
else | |||
{ | |||
this.classpath.append( classpath ); | |||
} | |||
} | |||
/** | |||
* @param r The new ClasspathRef value | |||
* @see #setClasspath | |||
*/ | |||
public void setClasspathRef( Reference r ) | |||
throws TaskException | |||
{ | |||
createClasspath().setRefid( r ); | |||
} | |||
/** | |||
* Specify how parser error are to be handled. <p> | |||
* | |||
* If set to <code>true</code> (default), throw a TaskException if the | |||
* parser yields an error. | |||
* | |||
* @param fail The new FailOnError value | |||
*/ | |||
public void setFailOnError( boolean fail ) | |||
{ | |||
failOnError = fail; | |||
} | |||
/** | |||
* specifify the file to be checked | |||
* | |||
* @param file The new File value | |||
*/ | |||
public void setFile( File file ) | |||
{ | |||
this.file = file; | |||
} | |||
/** | |||
* Specify whether the parser should be validating. Default is <code>true</code> | |||
* . <p> | |||
* | |||
* If set to false, the validation will fail only if the parsed document is | |||
* not well formed XML. <p> | |||
* | |||
* this option is ignored if the specified class with {@link | |||
* #setClassName(String)} is not a SAX2 XMLReader. | |||
* | |||
* @param bool The new Lenient value | |||
*/ | |||
public void setLenient( boolean bool ) | |||
{ | |||
lenient = bool; | |||
} | |||
/** | |||
* Specify how parser error are to be handled. <p> | |||
* | |||
* If set to <code>true | |||
*</true> | |||
*(default), log a warn message for each SAX warn event. | |||
* | |||
* @param bool The new Warn value | |||
*/ | |||
public void setWarn( boolean bool ) | |||
{ | |||
warn = bool; | |||
} | |||
/** | |||
* specifify a set of file to be checked | |||
* | |||
* @param set The feature to be added to the Fileset attribute | |||
*/ | |||
public void addFileset( FileSet set ) | |||
{ | |||
filesets.addElement( set ); | |||
} | |||
/** | |||
* @return Description of the Returned Value | |||
* @see #setClasspath | |||
*/ | |||
public Path createClasspath() | |||
throws TaskException | |||
{ | |||
if( this.classpath == null ) | |||
{ | |||
this.classpath = new Path( project ); | |||
} | |||
return this.classpath.createPath(); | |||
} | |||
/** | |||
* Create a DTD location record. This stores the location of a DTD. The DTD | |||
* is identified by its public Id. The location may either be a file | |||
* location or a resource location. | |||
* | |||
* @return Description of the Returned Value | |||
*/ | |||
public DTDLocation createDTD() | |||
{ | |||
DTDLocation dtdLocation = new DTDLocation(); | |||
dtdLocations.addElement( dtdLocation ); | |||
return dtdLocation; | |||
} | |||
public void execute() | |||
throws TaskException | |||
{ | |||
int fileProcessed = 0; | |||
if( file == null && ( filesets.size() == 0 ) ) | |||
{ | |||
throw new TaskException( "Specify at least one source - a file or a fileset." ); | |||
} | |||
initValidator(); | |||
if( file != null ) | |||
{ | |||
if( file.exists() && file.canRead() && file.isFile() ) | |||
{ | |||
doValidate( file ); | |||
fileProcessed++; | |||
} | |||
else | |||
{ | |||
String errorMsg = "File " + file + " cannot be read"; | |||
if( failOnError ) | |||
throw new TaskException( errorMsg ); | |||
else | |||
log( errorMsg, Project.MSG_ERR ); | |||
} | |||
} | |||
for( int i = 0; i < filesets.size(); i++ ) | |||
{ | |||
FileSet fs = (FileSet)filesets.elementAt( i ); | |||
DirectoryScanner ds = fs.getDirectoryScanner( project ); | |||
String[] files = ds.getIncludedFiles(); | |||
for( int j = 0; j < files.length; j++ ) | |||
{ | |||
File srcFile = new File( fs.getDir( project ), files[ j ] ); | |||
doValidate( srcFile ); | |||
fileProcessed++; | |||
} | |||
} | |||
getLogger().info( fileProcessed + " file(s) have been successfully validated." ); | |||
} | |||
protected EntityResolver getEntityResolver() | |||
{ | |||
LocalResolver resolver = new LocalResolver(); | |||
for( Enumeration i = dtdLocations.elements(); i.hasMoreElements(); ) | |||
{ | |||
DTDLocation location = (DTDLocation)i.nextElement(); | |||
resolver.registerDTD( location ); | |||
} | |||
return resolver; | |||
} | |||
/* | |||
* set a feature on the parser. | |||
* TODO: find a way to set any feature from build.xml | |||
*/ | |||
private boolean setFeature( String feature, boolean value, boolean warn ) | |||
{ | |||
boolean toReturn = false; | |||
try | |||
{ | |||
xmlReader.setFeature( feature, value ); | |||
toReturn = true; | |||
} | |||
catch( SAXNotRecognizedException e ) | |||
{ | |||
if( warn ) | |||
log( "Could not set feature '" | |||
+ feature | |||
+ "' because the parser doesn't recognize it", | |||
Project.MSG_WARN ); | |||
} | |||
catch( SAXNotSupportedException e ) | |||
{ | |||
if( warn ) | |||
log( "Could not set feature '" | |||
+ feature | |||
+ "' because the parser doesn't support it", | |||
Project.MSG_WARN ); | |||
} | |||
return toReturn; | |||
} | |||
/* | |||
* parse the file | |||
*/ | |||
private void doValidate( File afile ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
log( "Validating " + afile.getName() + "... ", Project.MSG_VERBOSE ); | |||
errorHandler.init( afile ); | |||
InputSource is = new InputSource( new FileReader( afile ) ); | |||
String uri = "file:" + afile.getAbsolutePath().replace( '\\', '/' ); | |||
for( int index = uri.indexOf( '#' ); index != -1; | |||
index = uri.indexOf( '#' ) ) | |||
{ | |||
uri = uri.substring( 0, index ) + "%23" + uri.substring( index + 1 ); | |||
} | |||
is.setSystemId( uri ); | |||
xmlReader.parse( is ); | |||
} | |||
catch( SAXException ex ) | |||
{ | |||
if( failOnError ) | |||
throw new TaskException( "Could not validate document " + afile ); | |||
} | |||
catch( IOException ex ) | |||
{ | |||
throw new TaskException( "Could not validate document " + afile, ex ); | |||
} | |||
if( errorHandler.getFailure() ) | |||
{ | |||
if( failOnError ) | |||
throw new TaskException( afile + " is not a valid XML document." ); | |||
else | |||
log( afile + " is not a valid XML document", Project.MSG_ERR ); | |||
} | |||
} | |||
/** | |||
* init the parser : load the parser class, and set features if necessary | |||
*/ | |||
private void initValidator() | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
// load the parser class | |||
// with JAXP, we would use a SAXParser factory | |||
Class readerClass = null; | |||
//Class readerImpl = null; | |||
//Class parserImpl = null; | |||
if( classpath != null ) | |||
{ | |||
AntClassLoader loader = new AntClassLoader( project, classpath ); | |||
// loader.addSystemPackageRoot("org.xml"); // needed to avoid conflict | |||
readerClass = loader.loadClass( readerClassName ); | |||
AntClassLoader.initializeClass( readerClass ); | |||
} | |||
else | |||
readerClass = Class.forName( readerClassName ); | |||
// then check it implements XMLReader | |||
if( XMLReader.class.isAssignableFrom( readerClass ) ) | |||
{ | |||
xmlReader = (XMLReader)readerClass.newInstance(); | |||
log( "Using SAX2 reader " + readerClassName, Project.MSG_VERBOSE ); | |||
} | |||
else | |||
{ | |||
// see if it is a SAX1 Parser | |||
if( Parser.class.isAssignableFrom( readerClass ) ) | |||
{ | |||
Parser parser = (Parser)readerClass.newInstance(); | |||
xmlReader = new ParserAdapter( parser ); | |||
log( "Using SAX1 parser " + readerClassName, Project.MSG_VERBOSE ); | |||
} | |||
else | |||
{ | |||
throw new TaskException( INIT_FAILED_MSG | |||
+ readerClassName | |||
+ " implements nor SAX1 Parser nor SAX2 XMLReader." ); | |||
} | |||
} | |||
} | |||
catch( ClassNotFoundException e ) | |||
{ | |||
throw new TaskException( INIT_FAILED_MSG + readerClassName, e ); | |||
} | |||
catch( InstantiationException e ) | |||
{ | |||
throw new TaskException( INIT_FAILED_MSG + readerClassName, e ); | |||
} | |||
catch( IllegalAccessException e ) | |||
{ | |||
throw new TaskException( INIT_FAILED_MSG + readerClassName, e ); | |||
} | |||
xmlReader.setEntityResolver( getEntityResolver() ); | |||
xmlReader.setErrorHandler( errorHandler ); | |||
if( !( xmlReader instanceof ParserAdapter ) ) | |||
{ | |||
// turn validation on | |||
if( !lenient ) | |||
{ | |||
boolean ok = setFeature( "http://xml.org/sax/features/validation", true, true ); | |||
if( !ok ) | |||
{ | |||
throw new TaskException( INIT_FAILED_MSG | |||
+ readerClassName | |||
+ " doesn't provide validation" ); | |||
} | |||
} | |||
// set other features | |||
Enumeration enum = features.keys(); | |||
while( enum.hasMoreElements() ) | |||
{ | |||
String featureId = (String)enum.nextElement(); | |||
setFeature( featureId, ( (Boolean)features.get( featureId ) ).booleanValue(), true ); | |||
} | |||
} | |||
} | |||
public static class DTDLocation | |||
{ | |||
private String publicId = null; | |||
private String location = null; | |||
public void setLocation( String location ) | |||
{ | |||
this.location = location; | |||
} | |||
public void setPublicId( String publicId ) | |||
{ | |||
this.publicId = publicId; | |||
} | |||
public String getLocation() | |||
{ | |||
return location; | |||
} | |||
public String getPublicId() | |||
{ | |||
return publicId; | |||
} | |||
} | |||
/* | |||
* ValidatorErrorHandler role : | |||
* <ul> | |||
* <li> log SAX parse exceptions, | |||
* <li> remember if an error occured | |||
* </ul> | |||
*/ | |||
protected class ValidatorErrorHandler implements ErrorHandler | |||
{ | |||
protected File currentFile = null; | |||
protected String lastErrorMessage = null; | |||
protected boolean failed = false; | |||
// did an error happen during last parsing ? | |||
public boolean getFailure() | |||
{ | |||
return failed; | |||
} | |||
public void error( SAXParseException exception ) | |||
{ | |||
failed = true; | |||
doLog( exception, Project.MSG_ERR ); | |||
} | |||
public void fatalError( SAXParseException exception ) | |||
{ | |||
failed = true; | |||
doLog( exception, Project.MSG_ERR ); | |||
} | |||
public void init( File file ) | |||
{ | |||
currentFile = file; | |||
failed = false; | |||
} | |||
public void warning( SAXParseException exception ) | |||
{ | |||
// depending on implementation, XMLReader can yield hips of warning, | |||
// only output then if user explicitely asked for it | |||
if( warn ) | |||
doLog( exception, Project.MSG_WARN ); | |||
} | |||
private String getMessage( SAXParseException e ) | |||
{ | |||
String sysID = e.getSystemId(); | |||
if( sysID != null ) | |||
{ | |||
try | |||
{ | |||
int line = e.getLineNumber(); | |||
int col = e.getColumnNumber(); | |||
return new URL( sysID ).getFile() + | |||
( line == -1 ? "" : ( ":" + line + | |||
( col == -1 ? "" : ( ":" + col ) ) ) ) + | |||
": " + e.getMessage(); | |||
} | |||
catch( MalformedURLException mfue ) | |||
{ | |||
} | |||
} | |||
return e.getMessage(); | |||
} | |||
private void doLog( SAXParseException e, int logLevel ) | |||
{ | |||
log( getMessage( e ), logLevel ); | |||
} | |||
} | |||
private class LocalResolver | |||
implements EntityResolver | |||
{ | |||
private Hashtable fileDTDs = new Hashtable(); | |||
private Hashtable resourceDTDs = new Hashtable(); | |||
private Hashtable urlDTDs = new Hashtable(); | |||
public LocalResolver() | |||
{ | |||
} | |||
public void registerDTD( String publicId, String location ) | |||
{ | |||
if( location == null ) | |||
{ | |||
return; | |||
} | |||
File fileDTD = new File( location ); | |||
if( fileDTD.exists() ) | |||
{ | |||
if( publicId != null ) | |||
{ | |||
fileDTDs.put( publicId, fileDTD ); | |||
log( "Mapped publicId " + publicId + " to file " + fileDTD, Project.MSG_VERBOSE ); | |||
} | |||
return; | |||
} | |||
if( LocalResolver.this.getClass().getResource( location ) != null ) | |||
{ | |||
if( publicId != null ) | |||
{ | |||
resourceDTDs.put( publicId, location ); | |||
log( "Mapped publicId " + publicId + " to resource " + location, Project.MSG_VERBOSE ); | |||
} | |||
} | |||
try | |||
{ | |||
if( publicId != null ) | |||
{ | |||
URL urldtd = new URL( location ); | |||
urlDTDs.put( publicId, urldtd ); | |||
} | |||
} | |||
catch( java.net.MalformedURLException e ) | |||
{ | |||
//ignored | |||
} | |||
} | |||
public void registerDTD( DTDLocation location ) | |||
{ | |||
registerDTD( location.getPublicId(), location.getLocation() ); | |||
} | |||
public InputSource resolveEntity( String publicId, String systemId ) | |||
throws SAXException | |||
{ | |||
File dtdFile = (File)fileDTDs.get( publicId ); | |||
if( dtdFile != null ) | |||
{ | |||
try | |||
{ | |||
log( "Resolved " + publicId + " to local file " + dtdFile, Project.MSG_VERBOSE ); | |||
return new InputSource( new FileInputStream( dtdFile ) ); | |||
} | |||
catch( FileNotFoundException ex ) | |||
{ | |||
// ignore | |||
} | |||
} | |||
String dtdResourceName = (String)resourceDTDs.get( publicId ); | |||
if( dtdResourceName != null ) | |||
{ | |||
InputStream is = this.getClass().getResourceAsStream( dtdResourceName ); | |||
if( is != null ) | |||
{ | |||
log( "Resolved " + publicId + " to local resource " + dtdResourceName, Project.MSG_VERBOSE ); | |||
return new InputSource( is ); | |||
} | |||
} | |||
URL dtdUrl = (URL)urlDTDs.get( publicId ); | |||
if( dtdUrl != null ) | |||
{ | |||
try | |||
{ | |||
InputStream is = dtdUrl.openStream(); | |||
log( "Resolved " + publicId + " to url " + dtdUrl, Project.MSG_VERBOSE ); | |||
return new InputSource( is ); | |||
} | |||
catch( IOException ioe ) | |||
{ | |||
//ignore | |||
} | |||
} | |||
log( "Could not resolve ( publicId: " + publicId + ", systemId: " + systemId + ") to a local entity", | |||
Project.MSG_INFO ); | |||
return null; | |||
} | |||
} | |||
} |
@@ -1,114 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE file. | |||
*/ | |||
package org.apache.tools.ant.taskdefs.optional; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.taskdefs.XSLTLiaison; | |||
import org.apache.xalan.xslt.XSLTInputSource; | |||
import org.apache.xalan.xslt.XSLTProcessor; | |||
import org.apache.xalan.xslt.XSLTProcessorFactory; | |||
import org.apache.xalan.xslt.XSLTResultTarget; | |||
/** | |||
* Concrete liaison for Xalan 1.x API. | |||
* | |||
* @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
*/ | |||
public class XalanLiaison implements XSLTLiaison | |||
{ | |||
protected XSLTProcessor processor; | |||
protected File stylesheet; | |||
public XalanLiaison() | |||
throws Exception | |||
{ | |||
processor = XSLTProcessorFactory.getProcessor(); | |||
} | |||
public void setOutputtype( String type ) | |||
throws Exception | |||
{ | |||
if( !type.equals( "xml" ) ) | |||
throw new TaskException( "Unsupported output type: " + type ); | |||
} | |||
public void setStylesheet( File stylesheet ) | |||
throws Exception | |||
{ | |||
this.stylesheet = stylesheet; | |||
} | |||
public void addParam( String name, String value ) | |||
{ | |||
processor.setStylesheetParam( name, value ); | |||
} | |||
public void transform( File infile, File outfile ) | |||
throws Exception | |||
{ | |||
FileInputStream fis = null; | |||
FileOutputStream fos = null; | |||
FileInputStream xslStream = null; | |||
try | |||
{ | |||
xslStream = new FileInputStream( stylesheet ); | |||
fis = new FileInputStream( infile ); | |||
fos = new FileOutputStream( outfile ); | |||
// systemid such as file:/// + getAbsolutePath() are considered | |||
// invalid here... | |||
XSLTInputSource xslSheet = new XSLTInputSource( xslStream ); | |||
xslSheet.setSystemId( stylesheet.getAbsolutePath() ); | |||
XSLTInputSource src = new XSLTInputSource( fis ); | |||
src.setSystemId( infile.getAbsolutePath() ); | |||
XSLTResultTarget res = new XSLTResultTarget( fos ); | |||
processor.process( src, xslSheet, res ); | |||
} | |||
finally | |||
{ | |||
// make sure to close all handles, otherwise the garbage | |||
// collector will close them...whenever possible and | |||
// Windows may complain about not being able to delete files. | |||
try | |||
{ | |||
if( xslStream != null ) | |||
{ | |||
xslStream.close(); | |||
} | |||
} | |||
catch( IOException ignored ) | |||
{ | |||
} | |||
try | |||
{ | |||
if( fis != null ) | |||
{ | |||
fis.close(); | |||
} | |||
} | |||
catch( IOException ignored ) | |||
{ | |||
} | |||
try | |||
{ | |||
if( fos != null ) | |||
{ | |||
fos.close(); | |||
} | |||
} | |||
catch( IOException ignored ) | |||
{ | |||
} | |||
} | |||
} | |||
}//-- XalanLiaison |