/* * * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */ /** * Transforms an XML file according to given XSL file. */ package com.sun.xml.transform; import java.io.*; import java.util.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.w3c.dom.*; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXParseException; import org.xml.sax.SAXException; /** * Represents transformation */ class Transformation { /** XML file name to apply transformation to */ public String xmlFileName = ""; /** XSL files to be applied */ public String xslFileName = null; /** Transformation parameters: names */ public Vector xslParamNames = new Vector(); /** Transformation parameters: values */ public Vector xslparamValues = new Vector(); /** Output file name */ public String outFileName = ""; /** Do input file validation */ public boolean validate = false; } /** * Driver class with main(). Parses command line arguments and invokes * CodeTransformerImpl instance that does all the transformation work. */ public class CodeTransformer { /** Transformer that does actual transformation */ private static CodeTransformerImpl transformer = null; /** Transformations to perform */ private static Vector transformations = new Vector(); /** Print debug output while running */ private static boolean debug = false; /** Print usage info and exit */ private static boolean printHelp = false; /** * Main method * * @param args Command line arguments */ public static void main(String[] args) { try { parseArgs(args); if (printHelp) { printHelp(); return; } transformer = new CodeTransformerImpl(debug); for (int i = 0; i < transformations.size(); ++i) { Transformation tr = (Transformation)transformations.elementAt(i); transformer.transform(tr); } } catch (SAXException e) { // error was already reported e.printStackTrace(); System.exit(1); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } /** * Parse command line arguments, adding Transformation objects to * <tt>transformations</tt> vector for each transformation specified. * * @param args command line arguments */ private static void parseArgs(String[] args) { Transformation tr = new Transformation(); for (int i = 0; i < args.length; ++i) { String arg = args[i]; if (debug) { System.err.println("arg: " + arg); } if (arg.equals("-xml")) { tr.xmlFileName = args[++i]; } else if (arg.equals("-xsl")) { tr.xslFileName = args[++i]; } else if (arg.equals("-params")) { int j = i + 1; for (; j < args.length; j += 2) { if ('-' == args[j].charAt(0)) { break; } if (debug) { System.err.println("pname : " + (String)args[j]); System.err.println("pvalue: " + (String)args[j + 1]); } tr.xslParamNames.add(args[j]); tr.xslparamValues.add(args[j + 1]); } i = j - 1; } else if (arg.equals("-validate")) { tr.validate = true; } else if (arg.equals("-out")) { tr.outFileName = args[++i]; // -out ends current transformation arguments, // i.e all agruments coming after it belong // to next transformation(s) transformations.add(tr); tr = new Transformation(); } else if (arg.equals("-debug")) { debug = true; } else { printHelp = true; } } } /** * Print usage information */ private static void printHelp() { /** * Following options are recognized: * -validate: Do validation of input XML file. * -xml: XML file to transform. * -xsl: XSL file to apply to given XML file. * -out: Output file. If empty, output will be to stdout. * -params: Transformations parameters in form of "Name" * "Value" pairs. * -help: Print usage information * -debug: Be verbose: print some debug info while running. * * In order to improve performance, CodeTransformer is capable of * doing multiple transformations per invocation. -out option marks * the end of arguments for single transformation. All arguments * after it belong to next transformation(s). */ System.err.println("Usage: java -jar <code_transformer_jar_file>" + "[-validate] " + "-xml <localXMLFile> " + "-xsl <localXSLFile> " + "-params <paramName> <paramValue>... " + "-out <localOutputFile> " + "-xml <localXMLFile> " + "... " + "[-debug] " + "[-help]"); } } /** * Perform the transformation */ class CodeTransformerImpl { /** Factory constructing Transformer objects */ private TransformerFactory transformerFactory = TransformerFactory.newInstance(); /** * Since most of transformations are applied to the same XML file, * we don't want to load it on each transformation, so we cache last * used XML file as DOMSource */ /** Last source used */ private DOMSource lastSource = null; /** Last document used */ private Document lastDoc = null; /** File name of the last used source */ private String lastSourceFileName = null; /** Be verbose: print some debug info while running */ private boolean debug = false; /** * Constructor * * @param dbg print some debug output while running */ public CodeTransformerImpl(boolean dbg) { debug = dbg; } /** * Converts errors. */ class TransformerErrorHandler implements ErrorHandler { /** * Handles errors. * @param e the parsing exception */ public void error(SAXParseException e) throws SAXParseException { reportError(e); // rethrow exception to stop processing on first error throw e; } /** * Handles fatal errors. * @param e the parsing exception */ public void fatalError(SAXParseException e) { reportError(e); } /** * Handles warnings. * @param e the parsing exception */ public void warning(SAXParseException e) { reportError(e); } /** * Outputs diagnostic messages. * @param e the parsing exception */ private void reportError(SAXParseException e) { String msg = e.getMessage(); String location = e.getSystemId(); int line = e.getLineNumber(); System.err.print("Error: URI=" + location); System.err.println(" Line=" + line + ": " + msg); } } /** * Do the actual transformation * * @param tr transformation to perform */ public void transform(Transformation tr) throws Exception { if (debug) { System.err.println("xml file: " + tr.xmlFileName); System.err.println("out file: " + tr.outFileName); System.err.println("prev xml: " + lastSourceFileName); } // source XML file DOMSource source = null; Document doc; if (lastSource != null && lastSourceFileName.equals(tr.xmlFileName)) { source = lastSource; doc = lastDoc; } else { // load XML file as DOM tree DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); if (tr.validate) { domFactory.setValidating(true); } DocumentBuilder domBuilder = domFactory.newDocumentBuilder(); domBuilder.setErrorHandler(new TransformerErrorHandler()); doc = domBuilder.parse(new File(tr.xmlFileName)); // make source from it source = new DOMSource(doc); } // if output and input files are the same, // we can't reuse cached input file since // it's going to change if ((tr.xmlFileName).equals(tr.outFileName)) { lastSource = null; lastDoc = null; lastSourceFileName = null; } else { lastSource = source; lastDoc = doc; lastSourceFileName = tr.xmlFileName; } // apply XSL stylesheet if (debug) { System.err.println("xsl file: " + tr.xslFileName); } // output file StreamResult outStream = null; if (tr.outFileName.length() == 0) { // send transformed output to the stdout outStream = new StreamResult(System.out); } else { // send transformed output to the file makeDirectoryTree(tr.outFileName); outStream = new StreamResult(new File(tr.outFileName)); } // create Transformer that will apply stylesheet StreamSource xslFile = new StreamSource(new File(tr.xslFileName)); Transformer transformer = transformerFactory.newTransformer(xslFile); // pass parameters to Transformer for (int j = 0; j < tr.xslParamNames.size(); ++j) { transformer.setParameter( (String)tr.xslParamNames.elementAt(j), tr.xslparamValues.elementAt(j)); } // finally, apply the stylesheet transformer.transform(source, outStream); } /** * Creates a directory structure. * * @param fullFileName Full path to the file to be created. If directory * in which file is to be created doesn't exists, it will be created * @exception IOException is thrown if directory couldn't be created */ private void makeDirectoryTree(String fullFileName) throws IOException { if (debug == true) { System.out.println("mkdir: " + fullFileName); } int index = fullFileName.lastIndexOf(File.separatorChar); if (index == -1) { // To be compatible with MKS-hosted build on win32, which // does not translate / to \. index = fullFileName.lastIndexOf('/'); } File outputDirectory = new File(fullFileName.substring(0, index)); if (!(outputDirectory).exists()) { if (!(outputDirectory).mkdirs()) { throw new IOException("failed to create output directory"); } } } }