Java tutorial
/* * $Id$ * $URL$ * * ============================================================================= * Ikasan Enterprise Integration Platform * * Distributed under the Modified BSD License. * Copyright notice: The copyright for this software and a full listing * of individual contributors are as shown in the packaged copyright.txt * file. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - 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. * * - Neither the name of the ORGANIZATION nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS 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 COPYRIGHT HOLDER OR 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. * ============================================================================= */ package org.ikasan.filetransfer.xml.transform; // Imported java classes import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import java.util.Properties; import javax.xml.transform.ErrorListener; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.URIResolver; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import org.ikasan.filetransfer.CommonXSLTransformer; import org.w3c.dom.Document; /** * This class wraps TrAX API for ease of transformation. * It also provides XSLTC implementation of transformation. * <p> * XSLTC is typically used for * one-compilation-multiple-concurrent-transformations. * Once a new <code>DefaultXSLTransformer</code> instance is created, * a given object (holding stylesheet) will be compiled into a translet * (i.e. <code>javax.xml.transform.Templates</code> that contains a set of Java * class(es) and the translet be stored into an internal static hash table. * This enables us to create new <code>javax.xml.transform.Transformer</code> * instances for multiple transformations. * <p> * <pre> * Usage Example: * * String stylesheet = "/a/b/c/myStylesheet.xsl"; * * DefaultXSLTransformer xslt = null; * try * { * // Compile the stylesheet into a translet * // and keep it in the internal static table * xslt = new DefaultXSLTransformer(stylesheet); * * // Set parameters and perform the transformation * xslt.setURIResolver(uriXMLMaps); * xslt.setParameters(paramMap); * xslt.setParameter("name1", "value1"); * String xmlStringOut = xslt.transformToString(xmlDOMIn); * } * catch (Exception e) * { * e.printStackTrace(); * } * </pre> * * @author Ikasan Development Team * */ public class DefaultXSLTransformer implements CommonXSLTransformer { /** * The logger instance. */ private static Logger logger = Logger.getLogger(DefaultXSLTransformer.class); /** * The quite handy debugging flag to get more information * about XSLT processing. */ public static String XSLT_DEBUG = "ikasan.xslt.debug"; /** * The TransformerFactory system property key to generate a translator. */ protected static final String TX_FACTORY_KEY = "javax.xml.transform.TransformerFactory"; /** * The TransformerFactory system property value to generate a translator. */ protected static final String TX_FACTORY_VALUE = "org.apache.xalan.xsltc.trax.TransformerFactoryImpl"; /** * The mapping table that maps stylesheet names * to <code>Templates</code> instances. */ static Hashtable<String, Templates> translets = null; /** * This flag indicating whether this instance has been initialized. */ static boolean isInitialized = false; /** * The default file encoding. */ private final static String FILE_ENCODING = System.getProperty("file.encoding"); /** * The Transformer instance to perform the transformation with. * It will be rest after the transformation. */ private Transformer transformer = null; /** * Creates a new <code>DefaultXSLTransformer</code> instance * with the XSLTC flag on. This currently has no stylesheet associated. */ public DefaultXSLTransformer() { this.init(); } /** * Creates a new <code>DefaultXSLTransformer</code> instance * with the specified XSL stylesheet and XSLTC flag on. * * @param xslURI - an XSL stylesheet to apply to. * * @throws TransformerConfigurationException */ public DefaultXSLTransformer(String xslURI) throws TransformerConfigurationException { this(xslURI, true); } /** * Creates a new <code>DefaultXSLTransformer</code> instance * with the specified XSL stylesheet and default trace level. * * @param xslURI - an XSL stylesheet to apply to. * @param useXSLTC - the flag indicating whether to use XSLTC. * * @throws TransformerConfigurationException */ public DefaultXSLTransformer(String xslURI, Boolean useXSLTC) throws TransformerConfigurationException { this.init(); this.registerTemplates(xslURI, this.createSource(xslURI), useXSLTC.booleanValue()); } /** * Creates a new <code>DefaultXSLTransformer</code> instance * with the specified source holding XSL stylesheet and XSLTC flag on. * * @param name - the unique name being mapped to this source instance * holding XSL stylesheet in the internal mapping table. * @param xslSource - the <code>Source</code> object that holds * an XSL stylesheet URI, input stream, etc. * * @throws TransformerConfigurationException */ public DefaultXSLTransformer(String name, Source xslSource) throws TransformerConfigurationException { this(name, xslSource, true); } /** * Creates a new <code>DefaultXSLTransformer</code> instance * with the specified source holding XSL stylesheet * and default trace level. * * @param name - the unique name being mapped to this source instance * holding XSL stylesheet in the internal mapping table. * @param xslSource - the <code>Source</code> object that holds * an XSL stylesheet URI, input stream, etc. * @param useXSLTC - the flag indicating whether to use XSLTC. * * @throws TransformerConfigurationException */ public DefaultXSLTransformer(String name, Source xslSource, boolean useXSLTC) throws TransformerConfigurationException { this.init(); this.registerTemplates(name, xslSource, useXSLTC); } /** * Specifies the stylesheet URL to apply. By default this method will * compile the stylesheet to a translet. * @param xslURI * @throws TransformerConfigurationException */ public void setStylesheet(String xslURI) throws TransformerConfigurationException { this.init(); this.registerTemplates(xslURI, this.createSource(xslURI), true); } /** * Specifies the stylesheet URL to apply and also whether the stylesheet * should be compiled to a translet. * @param xslURI * @param useXSLTC * @throws TransformerConfigurationException */ public void setStylesheet(String xslURI, boolean useXSLTC) throws TransformerConfigurationException { this.init(); this.registerTemplates(xslURI, this.createSource(xslURI), useXSLTC); } /** * Initializes the internal structures. */ private synchronized void init() { // Only do this process once if (isInitialized == true) { return; } // Initialize the hash table logger.debug("Initializing translet mapping table..."); translets = new Hashtable<String, Templates>(); isInitialized = true; } /** * Creates and returns a new instance of <code>StreamSource</code> * based on the specified stylesheet. * * @param xslURI is the XSL stylesheet to apply to. * @return Source */ private Source createSource(String xslURI) { if (xslURI == null) throw new NullPointerException("XSL stylesheet URI can't be null"); Source xslSource = new StreamSource(xslURI); // If we don't do this, the transformer won't know how to // resolve relative URLs in the stylesheet. xslSource.setSystemId(xslURI); return xslSource; } /** * Compiles the specified XSL stylesheet into translets and * registers them using the internal mapping table. * * @param name - the unique name being mapped to the source instance * holding XSL stylesheet in the internal * mapping table. * @param xslSource - the source object that holds an XSL stylesheet URI, * input stream, etc. * @param useXSLTC - the flag indicating whether to use XSLTC. * @throws TransformerConfigurationException */ private synchronized void registerTemplates(String name, Source xslSource, boolean useXSLTC) throws TransformerConfigurationException { if (name == null) throw new NullPointerException("Translet reference name can't be null"); if (name.trim().length() == 0) throw new IllegalArgumentException("Translet reference name can't be empty"); if (xslSource == null) throw new NullPointerException("XSL stylesheet source can't be null"); if (useXSLTC == true) { // Try to get the translet instance associated with // the stylesheet name from the translet mapping table logger.debug("Trying to get translet for [" + name + "]."); Templates translet = translets.get(name); // First time, compile the stylesheet to create a new translet // Add it to the internal mapping table for the later use if (translet == null) { logger.debug("First time, compiling stylesheet..."); logger.debug("XSL stylesheet URI =[" + xslSource.getSystemId() + "]."); translet = this.newTemplates(xslSource); translets.put(new String(name), translet); logger.debug("Name:[" + name + "] => XSLTC:[" + translet + "]."); } else { // Log it to ensure we are using the same translet logger.debug("Name:[" + name + "] => XSLTC:[" + translet + "]."); } // Create a new transformation context for this translet object // Set it as current Transformer instance this.transformer = translet.newTransformer(); } else { // Get a new TransformerFactory instance TransformerFactory tFactory = this.newTransformerFactory(); this.transformer = tFactory.newTransformer(xslSource); } // Also clear all parameters just in case logger.debug("Got a new Transformer."); this.transformer.clearParameters(); } /** * Creates a new <code>Templates</code> instance based on * the specified stylesheet. * * @param xslSource - the source object that holds an XSL stylesheet URI, * input stream, etc. * @return Templates * @throws TransformerConfigurationException */ private Templates newTemplates(Source xslSource) throws TransformerConfigurationException { // Set the TransformerFactory system property to utilise translets // For more flexibility, load properties from a properties file // This will do the job for the time being logger.debug("Current TransformerFactory =[" + System.getProperty(TX_FACTORY_KEY) + "]."); logger.debug("Setting a new TransformerFactory [" + TX_FACTORY_VALUE + "]."); Properties props = System.getProperties(); props.put(TX_FACTORY_KEY, TX_FACTORY_VALUE); System.setProperties(props); logger.debug("New TransformerFactory =[" + System.getProperty(TX_FACTORY_KEY) + "]."); // Get a new TransformerFactory instance TransformerFactory tFactory = this.newTransformerFactory(); // Create a new translet as a Templates object return tFactory.newTemplates(xslSource); } /** * Creates a new <code>TransformerFactory</code> instance, * sets the default error listener, sets debugging flag on if necessary * and finally returns the instance. * * @return new TransformerFactory instance */ private TransformerFactory newTransformerFactory() { // Get a new TransformerFactory instance TransformerFactory tFactory = TransformerFactory.newInstance(); //logger.debug("Setting auto-translet to true..."); //tFactory.setAttribute("auto-translet", Boolean.TRUE); if (System.getProperty(XSLT_DEBUG, "false").equalsIgnoreCase("true")) tFactory.setAttribute("debug", Boolean.TRUE); logger.debug("Setting error event listener to ErrorListener..."); tFactory.setErrorListener(new DefaultErrorListener()); return tFactory; } /** * Sets the error event listener in effect for the transformation. * * @param listener - a new error listener. */ public void setErrorListener(ErrorListener listener) { // No need to scream as we've already got ErrorListener if (listener == null) return; this.transformer.setErrorListener(listener); } /** * Sets an object that will be used to resolve URIs used in * a stylesheet later using <code>xsl:include</code> or * <code>xsl:import</code> or <code>document()</code> function. * This method is called from <code>transform()</code> method. * * @param resolver - an object that implements the <code>URIResolver</code> * interface or null. */ // This method is to conform to the way javax.xml.transform.Transformer // sets URIResolver public void setURIResolver(URIResolver resolver) { this.transformer.setURIResolver(resolver); } /** * Creates a new <code>URIResolver</code> instance * (if not already created) that maps each URI to its corresponding * XML document. * This allows us to access any xml documents loaded in memory * by referring to corresponding URIs in a stylesheet later * using <code>xsl:include</code> or <code>xsl:import</code> or * <code>document()</code> function. * This method is called from <code>transform()</code> method. * * @param resolverMap - the mapping table containing a set of * URI-to-XML mappings. */ public void setURIResolver(Map<String, Source> resolverMap) { if (resolverMap == null || resolverMap.isEmpty()) return; // Operation error, possibly setURIResolver() method has been called // with different implementation of URIResolver URIResolver resolver = this.transformer.getURIResolver(); if ((resolver != null) && !(resolver instanceof DefaultURIResolver)) { throw new IllegalArgumentException("Operation error! " + "The following URIResolver instance has been already set to " + "this transformer '" + resolver.getClass().getName() + "'." + "Ensure to call either setURIResolver(URIResolver) or " + "setURIResolver(Map)/setURIResolver(String, Source) method"); } DefaultURIResolver uriResolver = (resolver == null) ? new DefaultURIResolver() : (DefaultURIResolver) this.transformer.getURIResolver(); // Grab each URI and its corresponding source object // (that is representing XML document) // then register the mapping through URIResolver String uri = null; Source xmlSource = null; for (Map.Entry<String, Source> entry : resolverMap.entrySet()) { uri = entry.getKey(); if (uri == null || uri.trim().length() == 0) { logger.warn("URI is null or empty, skipping..."); continue; } xmlSource = entry.getValue(); if (xmlSource != null) uriResolver.mapURIToSource(uri, xmlSource); else logger.warn("XML source object for URI [" + uri + "] is null, skipping..."); } this.transformer.setURIResolver(uriResolver); } /** * Creates a new <code>URIResolver</code> instance * (if not already created) to map the specified URI to * the object representing XML document. * * @param uri - the unique URI name. * @param xml - the XML document. */ public void setURIResolver(String uri, Source xml) { if (uri == null || uri.trim().length() == 0) return; if (xml == null) return; Map<String, Source> resolverMap = new HashMap<String, Source>(1); resolverMap.put(uri, xml); this.setURIResolver(resolverMap); } /** * Adds an output property for the transformation. * @param name * @param value * */ public void setOutputProperty(String name, String value) { if (name == null || value == null) return; this.transformer.setOutputProperty(name, value); } /** * Sets the output properties for the transformation. * * @param outputProps - the set of output properties that will be used to * override any of the same properties in affect * for the transformation. */ public void setOutputProperties(Properties outputProps) { if (outputProps == null || outputProps.isEmpty()) return; this.transformer.setOutputProperties(outputProps); } /** * Sets a parameter for the transformation. * @param name * @param value */ public void setParameter(String name, String value) { if (name == null) throw new NullPointerException("The parameter name can't be null"); if (value == null) throw new NullPointerException("The parameter value can't be null"); this.transformer.setParameter(name, value); } /** * Sets parameters for the transformation. * * @param parameterMap - parameter mappings. */ public void setParameters(Map<String, String> parameterMap) { if (parameterMap == null || parameterMap.isEmpty()) { return; } String name = null, value = null; for (Map.Entry<String, String> entry : parameterMap.entrySet()) { name = entry.getKey(); value = entry.getValue(); if (name == null || name.length() == 0) { logger.warn("Parameter name is null or empty, skipping..."); continue; } if (value != null) { this.setParameter(name, value); } else { logger.warn("Parameter value is null, skipping..."); } } } /** * Performs the transformation. * * @param in - the XML document. * @param out - the transformation result. * @throws TransformerException */ public void transform(Source in, Result out) throws TransformerException { if (in == null) throw new NullPointerException("XML source can't be null"); if (out == null) throw new NullPointerException("Output target can't be null"); // Perform the transformation from the source XML to the Result logger.debug("Transforming..."); this.transformer.transform(in, out); logger.debug("Transformation completed."); // Reset the Transformer instance // for the next transformation // JM - 21/7/08 // commented out as this doesn't allow re-use of the transformer instance // this.transformer = null; } /** * Performs the transformation to the output result as String. * * @param in - the XML document. * @return String * @throws TransformerException * @throws IOException */ public String transformToString(Source in) throws TransformerException, IOException { // Create a Writer instance to hold transformation result StringWriter writer = new StringWriter(); StreamResult out = new StreamResult(writer); // Transformation this.transform(in, out); // Flush and close the stream writer.flush(); writer.close(); // Here is the newly transformed string return new String(writer.getBuffer().toString()); } /** * Given the DOM object, performs the transformation * and returns the output result as String. * * @param xmlIn - the XML document as DOM object. * @return String * @throws TransformerException * @throws IOException */ public String transformToString(Document xmlIn) throws TransformerException, IOException { Source in = new DOMSource(xmlIn); return this.transformToString(in); } /** * Given the XML string, performs the transformation * and returns the output result as String. * * @param xmlIn - the XML document as <code>String</code> object. * @return String * @throws TransformerException * @throws IOException */ public String transformToString(String xmlIn) throws TransformerException, IOException { Source in = new StreamSource(new StringReader(xmlIn)); return this.transformToString(in); } /** * Performs the transformation to the output result as Document. * * @param in - the XML document as <code>Source</code>. * @return String * @throws TransformerException * @throws IOException */ public Document transformToDocument(Source in) throws TransformerException, IOException { // Create a Writer instance to hold transformation result DOMResult out = new DOMResult(); // Transformation this.transform(in, out); // Here is the newly transformed document return (Document) out.getNode(); } /** * Given the DOM object, performs the transformation * and returns the output result as Document. * * @param xmlIn - the XML document as DOM object. * @return String * @throws TransformerException * @throws IOException */ public Document transformToDocument(Document xmlIn) throws TransformerException, IOException { Source in = new DOMSource(xmlIn); return this.transformToDocument(in); } /** * Given the XML string, performs the transformation * and returns the output result as Document. * * @param xmlIn - the XML document as <code>String</code> object. * @return String * @throws TransformerException * @throws IOException */ public Document transformToDocument(String xmlIn) throws TransformerException, IOException { Source in = new StreamSource(new StringReader(xmlIn)); return this.transformToDocument(in); } // main() method /////////////////////////////////////////////////////////////////////////////// /** * Runs this class for testing. * TODO Unit Test * @param args */ public static void main(String args[]) { String dummyXML = "<?xml version='1.0'?><doc/>"; String xmlInURI = null; String xslInURI = null; String xmlOutURI = null; Map<String, String> params = new HashMap<String, String>(); Map<String, InputStream> uriResolverMap = new HashMap<String, InputStream>(); InputStream xmlIn = new ByteArrayInputStream("<?xml version='1.0'?><AAA><BBB id='b1'/></AAA>".getBytes()); uriResolverMap.put("ref.xml", xmlIn); boolean useXSLTC = true; boolean indent = false; int numOfXforms = 1; int maxNumOfXforms = 9999; boolean diffOutXml = false; // Parse the command-line parameters for (int i = 0; i < args.length; i++) { if (args[i].equalsIgnoreCase("-help")) { usage(); System.exit(1); } // Input XML URI else if (args[i].equalsIgnoreCase("-in")) { xmlInURI = args[++i].trim(); } // Input XSL URI else if (args[i].equalsIgnoreCase("-xsl")) { xslInURI = args[++i].trim(); } // Output file name else if (args[i].equalsIgnoreCase("-out")) { xmlOutURI = args[++i].trim(); } // Parameters to stylesheet else if (args[i].equalsIgnoreCase("-param")) { params.put(new String(args[++i].trim()), new String(args[++i].trim())); } // Parameters to stylesheet // Its parameter value is read from the specified file else if (args[i].equalsIgnoreCase("-fileParam")) { String name = new String(args[++i].trim()); String filename = new String(args[++i].trim()); try { String fileContentStr = FileUtils.readFileToString(new File(filename), FILE_ENCODING); params.put(name, fileContentStr); } catch (Exception e) { System.err.println("Error while reading file [" + filename + "], skipping..."); e.printStackTrace(System.err); } } // URI resolver mappings used to get in-memory XML from stylesheet // via document() function // Set URI name and XML filename else if (args[i].equalsIgnoreCase("-uriResolver")) { String uri = new String(args[++i].trim()); String filename = new String(args[++i].trim()); try { String fileContentStr = FileUtils.readFileToString(new File(filename), FILE_ENCODING); InputStream is = new ByteArrayInputStream(fileContentStr.getBytes()); uriResolverMap.put(uri, is); } catch (Exception e) { System.err.println("Error while reading file [" + filename + "], skipping..."); e.printStackTrace(System.err); } } // Use XSLTC? else if (args[i].equalsIgnoreCase("-usexsltc")) { String value = args[++i].trim(); useXSLTC = (value.equalsIgnoreCase("true")) ? true : false; } // Generate output XML with indentation else if (args[i].equalsIgnoreCase("-indent")) { indent = true; } // A number of loop to generate output XML files else if (args[i].equalsIgnoreCase("-loop")) { try { numOfXforms = Integer.parseInt(args[++i].trim()); if (numOfXforms > maxNumOfXforms) numOfXforms = maxNumOfXforms; } catch (Exception e) { numOfXforms = 1; } } // Generate different output XML files // when a number of loop > 0 else if (args[i].equalsIgnoreCase("-diff")) { diffOutXml = true; } // Set XSLT debuging flag on else if (args[i].equalsIgnoreCase("-debug")) { System.setProperty(XSLT_DEBUG, "true"); } // Don't know what to do else { System.err.println("Invalid option - [" + args[i] + "]."); usage(); System.exit(1); } } System.out.println(""); System.out.println("XML input file =[" + xmlInURI + "]."); System.out.println("XSL input file =[" + xslInURI + "]."); System.out.println("XML output file =[" + xmlOutURI + "]."); System.out.println("XSL parameters =[" + params + "]."); System.out.println("Use XSLTC =[" + useXSLTC + "]."); System.out.println("XML output indent =[" + indent + "]."); System.out.println("No. of transforms =[" + numOfXforms + "]."); System.out.println("Diff output XML =[" + diffOutXml + "]."); System.out.println(""); boolean isXSLInURI = (xslInURI != null && xslInURI.length() > 0); boolean isXMLInURI = (xmlInURI != null && xmlInURI.length() > 0); boolean isXmlOutURI = (xmlOutURI != null && xmlOutURI.length() > 0); String xmlOutURIPrefix = (isXmlOutURI && xmlOutURI != null && xmlOutURI.indexOf('.') > 0) ? xmlOutURI.substring(0, xmlOutURI.indexOf('.')) : xmlOutURI; String xmlOutURISuffix = (isXmlOutURI && xmlOutURI != null && xmlOutURI.indexOf('.') > 0) ? xmlOutURI.substring(xmlOutURI.indexOf('.')) : ""; try { // Use connection pool instance to query database // via the specified stylesheet int counter = 0; while (counter++ < numOfXforms) { // Create a new DefaultXSLTransformer instance // No matter how many times we create the instance // using the same stylesheet, no harm at all DefaultXSLTransformer xslt = null; if (isXSLInURI) xslt = new DefaultXSLTransformer(xslInURI, useXSLTC); else xslt = new DefaultXSLTransformer("default.xsl", new StreamSource(new StringReader(defaultXSLStr.toString())), useXSLTC); // Set URIResolver for the transformation // e.g. 1 String //InputStream xmlIn = new ByteArrayInputStream( // "<?xml version='1.0'?><AAA><BBB id='b1'/></AAA>".getBytes()); //xslt.setURIResolver("ref.xml", new StreamSource(xmlIn)); // e.g. 2 File // xslt.setURIResolver("ref.xml", // new StreamSource(new File("test.xml"))); // e.g. 3 InputSource // xslt.setURIResolver("ref.xml", new InputSource("test.xml")); for (Map.Entry<String, InputStream> entry : uriResolverMap.entrySet()) { String uri = entry.getKey(); InputStream is = entry.getValue(); xslt.setURIResolver(uri, new StreamSource(is)); } // Set output properties for the transformation if (indent) { xslt.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes"); xslt.setOutputProperty("{http://xml.apache.org/xalan}:indent-amount", "2"); } // Set parameters for the transformation if any xslt.setParameter("param1", "data" + counter); xslt.setParameters(params); if (isXmlOutURI && diffOutXml && numOfXforms > 1) xmlOutURI = xmlOutURIPrefix + intToString(counter, maxNumOfXforms) + xmlOutURISuffix; StreamSource xmlSource = (isXMLInURI) ? new StreamSource(xmlInURI) : new StreamSource(new StringReader(dummyXML)); StreamResult xmlResult = (isXmlOutURI) ? new StreamResult(xmlOutURI) : new StreamResult(System.out); System.out.println("\n[" + counter + "] Transforming..."); xslt.transform(xmlSource, xmlResult); if (xmlOutURI != null && xmlOutURI.length() > 0) System.out.println("Generated [" + xmlOutURI + "]."); } } catch (Exception e) { e.printStackTrace(System.err); } System.exit(0); } /** * Turns the specified integer into a <code>String</code> * in <code>dddd</code> format, where a number of <code>d</code>s varies * based on the number of digits passed in, * for example, intToString(1, 4) returns '0001'. * * @param integer * @param numOfDigits * @return String version of the integer */ private static String intToString(int integer, int numOfDigits) { int intLength = String.valueOf(integer).length(); int maxLength = String.valueOf(numOfDigits).length(); String intStr = new String(""); for (int i = intLength; i < maxLength; i++) intStr += "0"; return (intStr + String.valueOf(integer)); } /** * Displays the usage for main() method. * */ private static void usage() { String fqClassName = DefaultXSLTransformer.class.getName(); System.err.println(""); System.err.println("Usage:"); System.err.println("java " + fqClassName + " [-options]"); System.err.println(""); System.err.println("where options include:"); System.err.println(" -in <input XML>"); System.err.println(" to specify input XML file name (empty XML)"); System.err.println(" -xsl <input XSL>"); System.err.println(" to specify input stylesheet file name"); System.err.println(" (See below for default XSL)"); System.err.println(" -out <output> to specify output file name (System.out)"); System.err.println(" -param <name> <value>"); System.err.println(" to set a name-value paired parameter"); System.err.println(" The pair must be delimited by a space"); System.err.println(" Set parameters as many as you can"); System.err.println(" -fileParam <name> <filename>"); System.err.println(" to set a name-value paired parameter"); System.err.println(" The pair must be delimited by a space"); System.err.println( " The parameter value is read from the specified file location in string format"); System.err.println(" Set parameters as many as you can"); System.err.println(" -uriResolver <uri> <filename>"); System.err.println(" to set a URI resolver mapping"); System.err.println(" The pair must be delimited by a space"); System.err.println( " URI can be anything as long as it is matched to the one in the stylesheet"); System.err.println(" Specify an XML document file location in string format"); System.err.println(" Set as many URI resolver mappings as you can"); System.err.println(" -useXSLTC <true|false>"); System.err.println(" to use XSLTC - stylesheet compilation (true)"); System.err.println(" -indent to generate output XML with indentation (false)"); System.err.println(" -loop <number> to specify number of times you want to loop"); System.err.println(" while applying styleshhet (1)"); System.err.println(" -diff if you want to generate different output files (false)"); System.err.println(" This is only valid if the loop number > 1"); System.err.println(" -debug to set XSLT debugging flag on"); System.err.println(""); System.err.println( "Note that the following default XSL stylesheet will be used if XSL URI is not specified:-"); System.err.println(defaultXSLStr.toString()); System.err.println(""); } /** Default XSL stylesheet used in main() method */ private static StringBuffer defaultXSLStr = new StringBuffer(""); static { defaultXSLStr.append("<?xml version='1.0'?>\n"); defaultXSLStr.append("<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>\n"); defaultXSLStr.append(" <xsl:output method='xml' indent='yes'/>\n"); defaultXSLStr.append(" <xsl:variable name='myDoc' select=\"document('ref.xml')\"/>\n"); defaultXSLStr.append(" <xsl:template match='/'>\n"); defaultXSLStr.append(" <xsl:element name='out'>\n"); defaultXSLStr.append(" <xsl:copy-of select='$myDoc'/>\n"); defaultXSLStr.append(" </xsl:element>\n"); defaultXSLStr.append(" </xsl:template>\n"); defaultXSLStr.append("</xsl:stylesheet>\n"); } } /*********************************************************************************** =============================== in.xsl =============================== <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xalan" version="1.0" exclude-result-prefixes="xalan"> <xsl:output method="xml" encoding="UTF-8" indent="yes" xalan:indent-amount="2"/> <xsl:param name="param1" select="'data'"/> <!-- <xsl:variable name="myDoc" select="document('ref.xml')"/> --> <xsl:template match="/"> <xsl:element name="out"> <xsl:element name="tag1"> <xsl:value-of select="'content1'"/> </xsl:element> <xsl:element name="tag2"> <xsl:value-of select="'content2'"/> </xsl:element> <xsl:element name="tag3"> <xsl:attribute name="ATTR3"> <xsl:value-of select="'ATTR3_DATA'"/> </xsl:attribute> <xsl:value-of select="$param1"/> </xsl:element> <!-- <xsl:copy-of select="$myDoc"/> --> </xsl:element> </xsl:template> </xsl:stylesheet> =============================== test.xml =============================== <?xml version="1.0" encoding="UTF-8"?> <AAA> <BBB id="b1"/> <BBB name="bbb"/> <BBB name="bbb"/> </AAA> ************************************************************************************/