/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id$ */ package org.apache.qetest.xslwrapper; import java.io.File; import java.net.URL; import java.util.Hashtable; import java.util.Properties; import org.xml.sax.InputSource; /** * Implementation of TransformWrapper that uses the simplest method * possible to use James Clark's XT processor. * * @author Shane Curcuru * @version $Id$ */ public class XTWrapper extends TransformWrapperHelper { /** * Get a general description of this wrapper itself. * * @return Uses XT in simplest manner possible */ public String getDescription() { return "Uses XT in simplest manner possible"; } /** No-op Ctor for the Xalan-J 1.x wrapper. */ public XTWrapper(){} /** Reference to current processor - XT flavor - convenience method. */ protected com.jclark.xsl.sax.XSLProcessorImpl processor = null; /** * Cached copy of newProcessor() Hashtable. */ protected Hashtable newProcessorOpts = null; /** * Get a specific description of the wrappered processor. * * @return specific description of the underlying processor or * transformer implementation: this should include both the * general product name, as well as specific version info. If * possible, should be implemented without actively creating * an underlying processor. */ public Properties getProcessorInfo() { Properties p = new Properties(); p.put("traxwrapper.method", "simple"); p.put("traxwrapper.desc", getDescription()); //@todo call XT to find version info return p; } /** * Actually create/initialize an underlying processor or factory. * This creates a com.jclark.xsl.sax.XSLProcessorImpl. * * @param options Hashtable of options, unused. * * @return (Object)getProcessor() as a side-effect, this will * be null if there was any problem creating the processor OR * if the underlying implementation doesn't use this * * @throws Exception covers any underlying exceptions thrown * by the actual implementation */ public Object newProcessor(Hashtable options) throws Exception { newProcessorOpts = options; // Cleanup any prior objects reset(false); processor = new com.jclark.xsl.sax.XSLProcessorImpl(); String liaisonClassName = "com.jclark.xml.sax.CommentDriver"; // default try { Object parserObj = Class.forName(liaisonClassName).newInstance(); if (parserObj instanceof XMLProcessorEx) processor.setParser((XMLProcessorEx) parserObj); else processor.setParser((org.xml.sax.Parser) parserObj); } catch (Exception e) { System.err.println("createNewProcesor(xt) threw: " + e.toString()); e.printStackTrace(); processor = null; } return (Object)processor; } /** * Transform supplied xmlName file with the stylesheet in the * xslName file into a resultName file using XT. * * @param xmlName local path\filename of XML file to transform * @param xslName local path\filename of XSL stylesheet to use * @param resultName local path\filename to put result in * * @return array of longs denoting timing of all parts of * our operation: IDX_OVERALL, IDX_XSLREAD, IDX_XSLBUILD, * IDX_TRANSFORM, IDX_RESULTWRITE * * @throws Exception any underlying exceptions from the * wrappered processor are simply allowed to propagate; throws * a RuntimeException if any other problems prevent us from * actually completing the operation */ public long[] transform(String xmlName, String xslName, String resultName) throws Exception { // Declare variables ahead of time to minimize latency long startTime = 0; long endTime = 0; // Create XT-specific sources OutputMethodHandlerImpl outHandler = new OutputMethodHandlerImpl(processor); outHandler.setDestination(new FileDestination(new File(resultName))); InputSource xmlIS = xtInputSourceFromString(xmlName); InputSource xslIS = xtInputSourceFromString(xslName); // Begin timing the process: stylesheet, output, and process startTime = System.currentTimeMillis(); processor.loadStylesheet(xslIS); processor.setOutputMethodHandler(outHandler); processor.parse(xmlIS); endTime = System.currentTimeMillis(); long[] times = getTimeArray(); times[IDX_OVERALL] = endTime - startTime; return times; } /** * Pre-build/pre-compile a stylesheet. * * Although the actual mechanics are implementation-dependent, * most processors have some method of pre-setting up the data * needed by the stylesheet itself for later use in transforms. * In TrAX/javax.xml.transform, this equates to creating a * Templates object. * * Sets isStylesheetReady() to true if it succeeds. Users can * then call transformWithStylesheet(xmlName, resultName) to * actually perform a transformation with this pre-built * stylesheet. * * @param xslName local path\filename of XSL stylesheet to use * * @return array of longs denoting timing of all parts of * our operation: IDX_OVERALL, IDX_XSLBUILD * * @throws Exception any underlying exceptions from the * wrappered processor are simply allowed to propagate; throws * a RuntimeException if any other problems prevent us from * actually completing the operation * * @see #transformWithStylesheet(String xmlName, String resultName) */ public long[] buildStylesheet(String xslName) throws Exception { // Declare variables ahead of time to minimize latency long startTime = 0; long endTime = 0; // Create XT-specific source InputSource xslIS = xtInputSourceFromString(xslName); // Begin timing loading the stylesheet startTime = System.currentTimeMillis(); processor.loadStylesheet(xslIS); // side effect: also sets the stylesheet endTime = System.currentTimeMillis(); m_stylesheetReady = true; long[] times = getTimeArray(); times[IDX_OVERALL] = endTime - startTime; return times; } /** * Transform supplied xmlName file with a pre-built/pre-compiled * stylesheet into a resultName file. * * User must have called buildStylesheet(xslName) beforehand, * obviously. * Names are assumed to be local path\filename references, and * will be converted to URLs as needed. * * @param xmlName local path\filename of XML file to transform * @param resultName local path\filename to put result in * * @return array of longs denoting timing of all parts of * our operation: IDX_OVERALL, * IDX_XMLREAD, IDX_TRANSFORM, IDX_RESULTWRITE * * @throws Exception any underlying exceptions from the * wrappered processor are simply allowed to propagate; throws * a RuntimeException if any other problems prevent us from * actually completing the operation; throws an * IllegalStateException if isStylesheetReady() == false. * * @see #buildStylesheet(String xslName) */ public long[] transformWithStylesheet(String xmlName, String resultName) throws Exception { if (!isStylesheetReady()) throw new IllegalStateException("transformWithStylesheet() when isStylesheetReady() == false"); // Declare variables ahead of time to minimize latency long startTime = 0; long endTime = 0; // Create XT-specific sources OutputMethodHandlerImpl outHandler = new OutputMethodHandlerImpl(processor); outHandler.setDestination(new FileDestination(new File(resultName))); InputSource xmlIS = xtInputSourceFromString(xmlName); // Begin timing the process: stylesheet, output, and process startTime = System.currentTimeMillis(); processor.setOutputMethodHandler(outHandler); processor.parse(xmlIS); endTime = System.currentTimeMillis(); long[] times = getTimeArray(); times[IDX_OVERALL] = endTime - startTime; return times; } /** * Transform supplied xmlName file with a stylesheet found in an * xml-stylesheet PI into a resultName file. * * Names are assumed to be local path\filename references, and * will be converted to URLs as needed. Implementations will * use whatever facilities exist in their wrappered processor * to fetch and build the stylesheet to use for the transform. * * @param xmlName local path\filename of XML file to transform * @param resultName local path\filename to put result in * * @return array of longs denoting timing of only these parts of * our operation: IDX_OVERALL, IDX_XSLREAD (time to find XSL * reference from the xml-stylesheet PI), IDX_XSLBUILD, (time * to then build the Transformer therefrom), IDX_TRANSFORM * * @throws Exception any underlying exceptions from the * wrappered processor are simply allowed to propagate; throws * a RuntimeException if any other problems prevent us from * actually completing the operation */ public long[] transformEmbedded(String xmlName, String resultName) throws Exception { throw new RuntimeException("XTWrapper.transformEmbedded not implemented yet!"); } /** * Worker method for using XT to process. * * @param name local name of file * * @return InputSource for XT after munging name as needed */ private InputSource xtInputSourceFromString(String name) { File file = new File(name); String path = file.getAbsolutePath(); // Add absolute / to beginning if needed if (path.charAt(0) != '/') path = '/' + path; try { java.net.URL temp = new URL("file", "", path); return (new InputSource(temp.toString())); } catch (Exception e) { System.err.println("xtInputSourceFromString(xt) of: " + name + " threw: " + e.toString()); e.printStackTrace(); return (null); } } /** * Reset our parameters and wrapper state, and optionally * force creation of a new underlying processor implementation. * * This always clears our built stylesheet and any parameters * that have been set. If newProcessor is true, also forces a * re-creation of our underlying processor as if by calling * newProcessor(). * * @param newProcessor if we should reset our underlying * processor implementation as well */ public void reset(boolean newProcessor) { super.reset(newProcessor); // clears indent and parameters m_stylesheetReady = false; if (newProcessor) { try { newProcessor(newProcessorOpts); } catch (Exception e) { //@todo Hmm: what should we do here? } } } /** * Apply a single parameter to a Transformer. * * Overridden for XT to call setParameter(). * * @param passThru to be passed to each applyParameter() method * call - for TrAX, you might pass a Transformer object. * @param namespace for the parameter, may be null * @param name for the parameter, should not be null * @param value for the parameter, may be null */ protected void applyParameter(Object passThru, String namespace, String name, Object value) { try { XSLProcessorImpl p = (XSLProcessorImpl)passThru; //@todo: HACK: smash the namespace in - not sure if this is correct if (null != namespace) { name = namespace + ":" + name; } p.setParameter(name, value); } catch (Exception e) { throw new IllegalArgumentException("applyParameter threw: " + e.toString()); } } } // end of class XTWrapper