You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by do...@apache.org on 2001/12/16 13:04:44 UTC

cvs commit: jakarta-ant/proposal/myrmidon/src/java/org/apache/antlib/xml TraXLiaison.java XMLValidateTask.java XSLTLiaison.java XSLTParam.java XSLTProcess.java XalanLiaison.java

donaldp     01/12/16 04:04:44

  Added:       proposal/myrmidon/src/java/org/apache/antlib/xml
                        TraXLiaison.java XMLValidateTask.java
                        XSLTLiaison.java XSLTParam.java XSLTProcess.java
                        XalanLiaison.java
  Log:
  Start to move the non-deprecated XML files into new antlib - making sure they are compatible with myrmidon
  
  Revision  Changes    Path
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/antlib/xml/TraXLiaison.java
  
  Index: TraXLiaison.java
  ===================================================================
  /*
   * 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.antlib.xml;
  
  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.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.LogEnabled;
  
  /**
   * 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
      extends AbstractLogEnabled
      implements XSLTLiaison, ErrorListener
  {
      /**
       * The trax TransformerFactory
       */
      private TransformerFactory tfactory;
  
      /**
       * stylesheet stream, close it asap
       */
      private FileInputStream xslStream;
  
      /**
       * Stylesheet template
       */
      private Templates templates;
  
      /**
       * transformer
       */
      private Transformer transformer;
  
      public TraXLiaison()
          throws Exception
      {
          tfactory = TransformerFactory.newInstance();
          tfactory.setErrorListener( this );
      }
  
      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() );
          }
  
          getLogger().info( msg.toString() );
      }
  
  }//-- TraXLiaison
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/antlib/xml/XMLValidateTask.java
  
  Index: XMLValidateTask.java
  ===================================================================
  /*
   * 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.antlib.xml;
  
  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( 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.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/antlib/xml/XSLTLiaison.java
  
  Index: XSLTLiaison.java
  ===================================================================
  /*
   * 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.antlib.xml;
  
  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.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/antlib/xml/XSLTParam.java
  
  Index: XSLTParam.java
  ===================================================================
  /*
   * 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;
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/antlib/xml/XSLTProcess.java
  
  Index: XSLTProcess.java
  ===================================================================
  /*
   * 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.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;
  
  /**
   * 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
  {
      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()
      {
          m_fileUtils = FileUtils.newFileUtils();
      }//-- setForce
  
      /**
       * Set the base directory.
       *
       * @param dir The new Basedir value
       */
      public void setBasedir( File dir )
      {
          m_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 );
      }
  
      /**
       * 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 )
      {
          m_destDir = dir;
      }
  
      /**
       * Set the desired file extension to be used for the target
       *
       * @param name the extension to use
       */
      public void setExtension( String name )
      {
          m_targetExtension = name;
      }
  
      /**
       * Set whether to check dependencies, or always generate.
       *
       * @param force The new Force value
       */
      public void setForce( boolean force )
      {
          this.m_force = force;
      }
  
      /**
       * Sets an input xml file to be styled
       *
       * @param inFile The new In value
       */
      public void setIn( File inFile )
      {
          this.m_inFile = inFile;
      }
  
      /**
       * Sets an out file
       *
       * @param outFile The new Out value
       */
      public void setOut( File outFile )
      {
          this.m_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.m_outputtype = type;
      }
  
      public void setProcessor( String processor )
      {
          this.m_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.m_xslFile = xslFile;
      }
  
      /**
       * Set the classpath to load the Processor through (nested element).
       *
       * @return Description of the Returned Value
       */
      public Path createClasspath()
          throws TaskException
      {
          if( m_classpath == null )
          {
              m_classpath = new Path( project );
          }
          return m_classpath.createPath();
      }
  
      public XSLTParam createParam()
      {
          XSLTParam p = new XSLTParam();
          m_params.add( p );
          return p;
      }//-- XSLTProcess
  
      /**
       * Executes the task.
       *
       * @exception TaskException Description of Exception
       */
  
      public void execute()
          throws TaskException
      {
          DirectoryScanner scanner;
          String[] list;
          String[] dirs;
  
          if( m_xslFile == null )
          {
              throw new TaskException( "no stylesheet specified" );
          }
  
          if( m_baseDir == null )
          {
              m_baseDir = getBaseDirectory();
          }
  
          m_liaison = getLiaison();
  
          // check if liaison wants to log errors using us as logger
          setupLogger( m_liaison );
  
          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( m_inFile != null && m_outFile != null )
          {
              process( m_inFile, m_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( m_destDir == null )
          {
              String msg = "destdir attributes must be set!";
              throw new TaskException( msg );
          }
          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( 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( m_baseDir, dirs[ j ] ).list();
              for( int i = 0; i < list.length; ++i )
                  process( m_baseDir, list[ i ], m_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( m_liaison == null )
          {
              if( m_processor != null )
              {
                  try
                  {
                      resolveProcessor( m_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 m_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( m_stylesheetLoaded )
          {
              return;
          }
          m_stylesheetLoaded = true;
  
          try
          {
              getLogger().info( "Loading stylesheet " + stylesheet );
              m_liaison.setStylesheet( stylesheet );
              final Iterator params = m_params.iterator();
              while( params.hasNext() )
              {
                  final XSLTParam param = (XSLTParam)params.next();
                  m_liaison.addParam( param.getName(), param.getExpression() );
              }
          }
          catch( final Exception e )
          {
              getLogger().info( "Failed to read stylesheet " + stylesheet );
              throw new TaskException( "Error", e );
          }
      }
  
      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( m_classpath == null )
          {
              return Class.forName( classname );
          }
          else
          {
              AntClassLoader al = new AntClassLoader( project, m_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 = m_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( m_force ||
                  inFile.lastModified() > outFile.lastModified() ||
                  styleSheetLastModified > outFile.lastModified() )
              {
                  ensureDirectoryFor( outFile );
                  getLogger().info( "Processing " + inFile + " to " + outFile );
  
                  configureLiaison( stylesheet );
                  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
              getLogger().info( "Failed to process " + inFile );
              if( outFile != null )
              {
                  outFile.delete();
              }
  
              throw new TaskException( "Error", ex );
          }
  
      }//-- processXML
  
      private void process( File inFile, File outFile, File stylesheet )
          throws TaskException
      {
          try
          {
              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 );
                  getLogger().info( "Processing " + inFile + " to " + outFile );
                  configureLiaison( stylesheet );
                  m_liaison.transform( inFile, outFile );
              }
          }
          catch( Exception ex )
          {
              getLogger().info( "Failed to process " + inFile );
              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" );
              m_liaison = (XSLTLiaison)clazz.newInstance();
          }
          else if( proc.equals( "xalan" ) )
          {
              final Class clazz =
                  loadClass( "org.apache.tools.ant.taskdefs.optional.XalanLiaison" );
              m_liaison = (XSLTLiaison)clazz.newInstance();
          }
          else
          {
              m_liaison = (XSLTLiaison)loadClass( proc ).newInstance();
          }
      }
  
  }
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/antlib/xml/XalanLiaison.java
  
  Index: XalanLiaison.java
  ===================================================================
  /*
   * 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.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.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
  {
      private XSLTProcessor processor;
      private 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
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>