/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed 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. * ******************************************************************************/ package org.pentaho.di.trans.steps.xslt; import java.io.StringReader; import java.io.StringWriter; import java.util.Properties; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.commons.vfs2.FileObject; import org.apache.commons.vfs2.FileType; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.exception.KettleStepException; import org.pentaho.di.core.row.RowDataUtil; import org.pentaho.di.core.vfs.KettleVFS; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.step.BaseStep; import org.pentaho.di.trans.step.StepDataInterface; import org.pentaho.di.trans.step.StepInterface; import org.pentaho.di.trans.step.StepMeta; import org.pentaho.di.trans.step.StepMetaInterface; /** * Executes a XSL Transform on the values in the input stream. * * @author Samatar * @since 15-Oct-2007 * */ public class Xslt extends BaseStep implements StepInterface { private static Class<?> PKG = XsltMeta.class; // for i18n purposes, needed by Translator2!! private XsltMeta meta; private XsltData data; static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; public Xslt( StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr, TransMeta transMeta, Trans trans ) { super( stepMeta, stepDataInterface, copyNr, transMeta, trans ); } public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException { meta = (XsltMeta) smi; data = (XsltData) sdi; Object[] row = getRow(); if ( row == null ) { // no more input to be expected... setOutputDone(); return false; } if ( first ) { first = false; data.outputRowMeta = getInputRowMeta().clone(); meta.getFields( data.outputRowMeta, getStepname(), null, null, this, repository, metaStore ); // Check if The result field is given if ( Utils.isEmpty( meta.getResultfieldname() ) ) { // Result Field is missing ! logError( BaseMessages.getString( PKG, "Xslt.Log.ErrorResultFieldMissing" ) ); throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.Exception.ErrorResultFieldMissing" ) ); } // Check if The XML field is given if ( Utils.isEmpty( meta.getFieldname() ) ) { // Result Field is missing ! logError( BaseMessages.getString( PKG, "Xslt.Exception.ErrorXMLFieldMissing" ) ); throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.Exception.ErrorXMLFieldMissing" ) ); } // Try to get XML Field index data.fieldposition = getInputRowMeta().indexOfValue( meta.getFieldname() ); // Let's check the Field if ( data.fieldposition < 0 ) { // The field is unreachable ! logError( BaseMessages.getString( PKG, "Xslt.Log.ErrorFindingField" ) + "[" + meta.getFieldname() + "]" ); throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.Exception.CouldnotFindField", meta .getFieldname() ) ); } // Check if the XSL Filename is contained in a column if ( meta.useXSLField() ) { if ( Utils.isEmpty( meta.getXSLFileField() ) ) { // The field is missing // Result field is missing ! logError( BaseMessages.getString( PKG, "Xslt.Log.ErrorXSLFileFieldMissing" ) ); throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.Exception.ErrorXSLFileFieldMissing" ) ); } // Try to get Field index data.fielxslfiledposition = getInputRowMeta().indexOfValue( meta.getXSLFileField() ); // Let's check the Field if ( data.fielxslfiledposition < 0 ) { // The field is unreachable ! logError( BaseMessages.getString( PKG, "Xslt.Log.ErrorXSLFileFieldFinding" ) + "[" + meta.getXSLFileField() + "]" ); throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.Exception.ErrorXSLFileFieldFinding", meta .getXSLFileField() ) ); } } else { if ( Utils.isEmpty( meta.getXslFilename() ) ) { logError( BaseMessages.getString( PKG, "Xslt.Log.ErrorXSLFile" ) ); throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.Exception.ErrorXSLFile" ) ); } // Check if XSL File exists! data.xslfilename = environmentSubstitute( meta.getXslFilename() ); FileObject file = null; try { file = KettleVFS.getFileObject( data.xslfilename ); if ( !file.exists() ) { logError( BaseMessages.getString( PKG, "Xslt.Log.ErrorXSLFileNotExists", data.xslfilename ) ); throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.Exception.ErrorXSLFileNotExists", data.xslfilename ) ); } if ( file.getType() != FileType.FILE ) { logError( BaseMessages.getString( PKG, "Xslt.Log.ErrorXSLNotAFile", data.xslfilename ) ); throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.Exception.ErrorXSLNotAFile", data.xslfilename ) ); } } catch ( Exception e ) { throw new KettleStepException( e ); } finally { try { if ( file != null ) { file.close(); } } catch ( Exception e ) { /* Ignore */ } } } // Check output parameters int nrOutputProps = meta.getOutputPropertyName() == null ? 0 : meta.getOutputPropertyName().length; if ( nrOutputProps > 0 ) { data.outputProperties = new Properties(); for ( int i = 0; i < nrOutputProps; i++ ) { data.outputProperties.put( meta.getOutputPropertyName()[i], environmentSubstitute( meta .getOutputPropertyValue()[i] ) ); } data.setOutputProperties = true; } // Check parameters data.nrParams = meta.getParameterField() == null ? 0 : meta.getParameterField().length; if ( data.nrParams > 0 ) { data.indexOfParams = new int[data.nrParams]; data.nameOfParams = new String[data.nrParams]; for ( int i = 0; i < data.nrParams; i++ ) { String name = environmentSubstitute( meta.getParameterName()[i] ); String field = environmentSubstitute( meta.getParameterField()[i] ); if ( Utils.isEmpty( field ) ) { throw new KettleStepException( BaseMessages .getString( PKG, "Xslt.Exception.ParameterFieldMissing", name, i ) ); } data.indexOfParams[i] = getInputRowMeta().indexOfValue( field ); if ( data.indexOfParams[i] < 0 ) { throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.Exception.ParameterFieldNotFound", name ) ); } data.nameOfParams[i] = name; } data.useParameters = true; } data.factory = TransformerFactory.newInstance(); if ( meta.getXSLFactory().equals( "SAXON" ) ) { // Set the TransformerFactory to the SAXON implementation. data.factory = new net.sf.saxon.TransformerFactoryImpl(); } } // end if first // Get the field value String xmlValue = getInputRowMeta().getString( row, data.fieldposition ); if ( meta.useXSLField() ) { // Get the value data.xslfilename = getInputRowMeta().getString( row, data.fielxslfiledposition ); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "Xslt.Log.XslfileNameFromFied", data.xslfilename, meta .getXSLFileField() ) ); } } try { if ( log.isDetailed() ) { if ( meta.isXSLFieldIsAFile() ) { logDetailed( BaseMessages.getString( PKG, "Xslt.Log.Filexsl" ) + data.xslfilename ); } else { logDetailed( BaseMessages.getString( PKG, "Xslt.Log.XslStream", data.xslfilename ) ); } } // Get the template from the cache Transformer transformer = data.getTemplate( data.xslfilename, data.xslIsAfile ); // Do we need to set output properties? if ( data.setOutputProperties ) { transformer.setOutputProperties( data.outputProperties ); } // Do we need to pass parameters? if ( data.useParameters ) { for ( int i = 0; i < data.nrParams; i++ ) { transformer.setParameter( data.nameOfParams[i], row[data.indexOfParams[i]] ); } } Source source = new StreamSource( new StringReader( xmlValue ) ); // Prepare output stream StreamResult result = new StreamResult( new StringWriter() ); // transform xml source transformer.transform( source, result ); String xmlString = result.getWriter().toString(); if ( log.isDetailed() ) { logDetailed( BaseMessages.getString( PKG, "Xslt.Log.FileResult" ) ); logDetailed( xmlString ); } Object[] outputRowData = RowDataUtil.addValueData( row, getInputRowMeta().size(), xmlString ); if ( log.isRowLevel() ) { logRowlevel( BaseMessages.getString( PKG, "Xslt.Log.ReadRow" ) + " " + getInputRowMeta().getString( row ) ); } // add new values to the row. putRow( data.outputRowMeta, outputRowData ); // copy row to output rowset(s); } catch ( Exception e ) { String errorMessage = e.getClass().toString() + ": " + e.getMessage(); if ( getStepMeta().isDoingErrorHandling() ) { // Simply add this row to the error row putError( getInputRowMeta(), row, 1, errorMessage, meta.getResultfieldname(), "XSLT01" ); } else { logError( BaseMessages.getString( PKG, "Xslt.ErrorProcesing" + " : " + errorMessage ), e ); throw new KettleStepException( BaseMessages.getString( PKG, "Xslt.ErrorProcesing" ), e ); } } return true; } public boolean init( StepMetaInterface smi, StepDataInterface sdi ) { meta = (XsltMeta) smi; data = (XsltData) sdi; if ( super.init( smi, sdi ) ) { // Specify weither or not we have to deal with XSL filename data.xslIsAfile = ( meta.useXSLField() && meta.isXSLFieldIsAFile() ) || ( !meta.useXSLField() ); // Add init code here. return true; } return false; } public void dispose( StepMetaInterface smi, StepDataInterface sdi ) { meta = (XsltMeta) smi; data = (XsltData) sdi; data.dispose(); super.dispose( smi, sdi ); } }