/* * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ //package org.apache.tools.ant.taskdefs; import org.apache.tools.ant.Task; import java.net.*; import java.io.*; import java.util.*; import org.apache.xalan.xslt.*; import org.w3c.dom.*; import org.xml.sax.SAXException; /** * Task to call the XSLT processor Xalan (part of xml.apache.org), which converts xml files * from a source to an output using a stylesheet file * *

* This task can take the following arguments: *

*

* Of these arguments, infile, outfile and xsltfile are required. *

smart defaults to 'no'. The other allowed value is 'yes'. If smart is set to 'yes' *

* xalan is only called if either the outfile is older than the infile or the stylesheet * or the outfile doesn't exist. *

*

dependent defaults to 'none'. Other possible values: a comma delimited list of file names * which date is checked against the output file. This way you can name files which, if * they have been modified, initiate a restart of the xslt process, like external entities etc. *

* @author Fotis Jannidis fotis@jannidis.de * @author Kelly A. Campbell camk@camk.net */ public class Xslt extends Task { private String infile, outfile, xsltfile, mergefile; private String smart = "no"; //defaults to do conversion everytime task is called private String dependent = "none"; //defaults to no dependencies private boolean startXslt = false; /** * Sets the input file * */ public void setInfile (String infile) { this.infile = infile; } public void setMergefile (String mergefile) { this.mergefile = mergefile; } /** * Sets the stylesheet file * */ public void setXsltfile (String xsltfile) { this.xsltfile = xsltfile; } /** * Sets the output file * */ public void setOutfile (String outfile) { this.outfile = outfile; } /** * Sets the value for smart * * @param option valid values: *

*/ public void setSmart (String smart) { this.smart = smart; } /** * Sets the value for dependent * * @param option valid values: * */ public void setDependent (String dependent) { this.dependent = dependent; } /** * Builds a document from the given file, merging the mergefile onto the end of the root node */ private org.w3c.dom.Document buildDocument(String xmlFile) throws IOException, SAXException { try { javax.xml.parsers.DocumentBuilder docBuilder = javax.xml.parsers.DocumentBuilderFactory.newInstance(). newDocumentBuilder(); Document doc = docBuilder.parse(new FileInputStream(xmlFile)); if (mergefile != null && !mergefile.equals("")) { File mergefileF = new File(mergefile); Document mergedoc = docBuilder.parse(new FileInputStream(mergefileF)); Node mergenode = doc.importNode(mergedoc.getDocumentElement(), true); doc.getDocumentElement().appendChild(mergenode); } return doc; } catch (javax.xml.parsers.ParserConfigurationException e) { System.out.println("Task xslt - SAX ERROR:\n " + e.getMessage()); } return null; } /** * Calls Xalan and does the transformation * */ private void transform(String xmlSourceURL, String xslURL, String outputURL) throws java.io.IOException, java.net.MalformedURLException, org.xml.sax.SAXException { StylesheetRoot stylesheet = StylesheetCache.getStylesheet(xsltfile); org.w3c.dom.Document source = buildDocument(infile); // Create the 3 objects the XSLTProcessor needs to perform the transformation. org.apache.xalan.xslt.XSLTInputSource xmlSource = new org.apache.xalan.xslt.XSLTInputSource (source); org.apache.xalan.xslt.XSLTResultTarget xmlResult = new org.apache.xalan.xslt.XSLTResultTarget (outfile); // Perform the transformation. System.out.println("============================"); System.out.println("xslt \nin: " + infile + "\nstyle: " + xsltfile + "\nout: " + outfile); System.out.println("============================"); stylesheet.process(XSLTProcessorFactory.getProcessor(new org.apache.xalan.xpath.xdom.XercesLiaison()), xmlSource, xmlResult); } //end transform /** * Catches the errors transform() can throw and * returns meaningfull error messages */ private void startTransform () { try { transform (infile, xsltfile, outfile); } catch (org.xml.sax.SAXException saxerror) { System.out.println("Task xslt - SAX ERROR:\n " + saxerror); } catch (MalformedURLException urlerror) { System.out.println("Task xslt - URL ERROR:\n " + urlerror); } catch (IOException ioerror) { System.out.println("Task xslt - IO ERROR:\n " + ioerror); } } //end startTransform /** * Checks for existence of output file and compares * dates with input and stylesheet file */ private boolean smartCheck (File outfileF, long outfileLastModified, File infileF, File xsltfileF) { if (outfileF.exists()) { //checks whether output file is older than input file or xslt stylesheet file if ((outfileLastModified < infileF.lastModified()) | (outfileLastModified < xsltfileF.lastModified())) { return true; } } else { //if output file does not exist, start xslt process return true; } return false; } //end smartCheck /** * Checks for existence and date of dependent files * This could be folded together with smartCheck by using * a general routine but it wouldn't be as fast as now */ private boolean dependenciesCheck(File outfileF, long outfileLastModified) { String dependentFileName; File dependentFile; StringTokenizer tokens = new StringTokenizer(dependent, ","); while (tokens.hasMoreTokens()) { dependentFileName = (String) tokens.nextToken(); dependentFile = new File (dependentFileName); //check: does dependent file exist if (dependentFile.exists()) { //check dates if ((outfileLastModified < dependentFile.lastModified())) { return true; } } else { System.err.println( "Task xslt - ERROR in attribute 'dependent':\n file " + dependentFileName + " does not exist."); } } return false; } //end dependenciesCheck /** * Main method, which is called by ant. * Checks for the value of smart and calls startTransform accordingly */ public void execute () throws org.apache.tools.ant.BuildException { File outfileF = new File (outfile); File infileF = new File(infile); File xsltfileF = new File (xsltfile); long outfileLastModified = outfileF.lastModified(); boolean startFileExist = true; //checks whether input and stylesheet exist. //this could be left to the parser, but this solution does make problems if smart is set to yes if (!infileF.exists()) { System.err.println( "Task xslt - ERROR:\n Input file " + infile + " does not exist!"); startFileExist = false; } else if (!xsltfileF.exists()) { System.err.println( "Task xslt - ERROR:\n Stylesheet file " + xsltfile + " does not exist!"); startFileExist = false; } //checks attribute 'smart' if (smart.equals("no")) { startXslt = true; //if attribute smart = 'yes' } else if (smart.equals("yes")) { startXslt = smartCheck (outfileF, outfileLastModified, infileF, xsltfileF); //checks dependent files against output file, makes only sense if smartCheck returns false if (!dependent.equals("none") & (startXslt == false)) { startXslt = dependenciesCheck(outfileF, outfileLastModified); } //returns error message, if smart has another value as 'yes' or 'no' } else { System.err.println("Task xslt - ERROR: Allowed values for the attribute smart are 'yes' or 'no'"); } if (startFileExist & startXslt) { startTransform(); } } //end execute //quick access for debugging //usage XSLT infile xsltfile outfile (smart is 'yes') /* public static void main (String args[]) { Xslt xslt = new Xslt(); xslt.setInfile(args[0]); xslt.setXsltfile(args[1]); xslt.setOutfile(args[2]); xslt.setSmart("yes"); xslt.setDependent("test1,test2"); xslt.execute(); } */ /** * Cache for stylesheets we've already processed */ protected static class StylesheetCache { /** Cache of compiled stylesheets (filename, StylesheetRoot) */ private static Hashtable _stylesheetCache = new Hashtable(); /** * Returns a compiled StylesheetRoot object for a given filename */ public static StylesheetRoot getStylesheet(String xsltFilename) throws org.xml.sax.SAXException { if (_stylesheetCache.containsKey(xsltFilename)) { return (StylesheetRoot)_stylesheetCache.get(xsltFilename); } // Use XSLTProcessor to instantiate an XSLTProcessor. org.apache.xalan.xslt.XSLTProcessor processor = org.apache.xalan.xslt.XSLTProcessorFactory.getProcessor( new org.apache.xalan.xpath.xdom.XercesLiaison()); org.apache.xalan.xslt.XSLTInputSource xslSheet = new org.apache.xalan.xslt.XSLTInputSource ( xsltFilename); // Perform the transformation. System.out.println("****************************"); System.out.println("xslt compile \nin: " + xsltFilename); System.out.println("****************************"); StylesheetRoot compiledSheet = processor.processStylesheet(xslSheet); _stylesheetCache.put(xsltFilename, compiledSheet); return compiledSheet; } } }