通过ktr文件写交换代码
目录
问题、没有设置fileMask和excludeFileMask
一、ktr文件生成
定义一个简单的Excel交换,如下图,保存为ktr文件,ktr的内容放在最后了。
二、分析ktr文件
大概浏览一遍ktr文件,有info,notepads,order,step,step_error_handling等节点,
看节点中内容,大概能知道order定义节点顺序,从输入到输出,
解析类
通过分析这个step,能确定我们要找什么Meta对象,需要设置什么参数。
通过红线处的type去kettle的源码中搜索,能在pentaho-kettle-->engine工程中找到一个kettle-steps.xml的文件,通过type确定如下内容,能确定需要使用的是ExcelInputMeta。
<step id="ExcelInput">
<description>i18n:org.pentaho.di.trans.step:BaseStep.TypeLongDesc.ExcelInput</description>
<classname>org.pentaho.di.trans.steps.excelinput.ExcelInputMeta</classname>
<category>i18n:org.pentaho.di.trans.step:BaseStep.Category.Input</category>
<tooltip>i18n:org.pentaho.di.trans.step:BaseStep.TypeTooltipDesc.ExcelInput</tooltip>
<iconfile>ui/images/XLI.svg</iconfile>
<documentation_url>Products/Microsoft_Excel_Input</documentation_url>
<cases_url/>
<forum_url/>
</step>
同理可以找到ExcelOutputMeta这个类。
那么基本就能确定这两个类就是图形化界面的两个节点。
文件路径
在界面进行了两步操作,第一步选择文件,第二步获取文件列,
此处是定义了POI解析,同时设置了文件路径,对应到ktr文件中就是如下内容,
<file>
<name>F:\kette_test\input\person.xlsx</name>
<filemask/>
<exclude_filemask/>
<file_required>N</file_required>
<include_subfolders>N</include_subfolders>
</file>
<spreadsheet_type>POI</spreadsheet_type>
通过上面ktr中xml的节点名称,可以在ExcelInputMeta中找到对应的属性,如下所示,后续就可以通过这些对象属性设值。
/**
* The filenames to load or directory in case a filemask was set.
*/
@Injection( name = "FILENAME", group = "FILENAME_LINES" )
private String[] fileName;
/**
* The regular expression to use (null means: no mask)
*/
@Injection( name = "FILEMASK", group = "FILENAME_LINES" )
private String[] fileMask;
/**
* Wildcard or filemask to exclude (regular expression)
*/
@Injection( name = "EXCLUDE_FILEMASK", group = "FILENAME_LINES" )
private String[] excludeFileMask;
@Injection( name = "FILE_REQUIRED", group = "FILENAME_LINES" )
private String[] fileRequired;
@Injection( name = "SPREADSHEET_TYPE" )
private SpreadSheetType spreadSheetType;
/**
* Array of boolean values as string, indicating if we need to fetch sub folders.
*/
@Injection( name = "INCLUDE_SUBFOLDERS", group = "FILENAME_LINES" )
private String[] includeSubFolders;
其中关于includeSubFolders是一个数组,那么就是同fileName这个数组对应的,此字段的含义是是否包含子目录。
includeSubFolders是设置什么值,是Y或者N?从源码中看到这个字段的判断,能看到是设置Y或者N。
在代码运行时,报错jxl的解析类找不到,所以能确定ExcelOutputMeta使用的是jxl写excel,此内容后面有详细报错。
文件字段
无论是输入,还是输出,都定义了列名,而这个列名对应到ktr文件中就是fields节点,如下所示,
<fields>
<field>
<name>id</name>
<type>String</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
<field>
<name>name</name>
<type>String</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
<field>
<name>age</name>
<type>Integer</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
</fields>
而上述Fields也可以在ExcelInputMeta中找到,这是一个数组ExcelInputField[],
/**
* The fields to read in the range. Note: the number of columns in the range has to match field.length
*/
@InjectionDeep
private ExcelInputField[] field;
查看ExcelInputField对象,里面的属性是和ktr的xml相似,同时还有构造方法,里面关于type和trimtype是有常量设置,可以用作参考。
public ExcelInputField( String fieldname, int position, int length ) {
this.name = fieldname;
this.length = length;
this.type = ValueMetaInterface.TYPE_STRING;
this.format = "";
this.trimtype = ExcelInputMeta.TYPE_TRIM_NONE;
this.groupSymbol = "";
this.decimalSymbol = "";
this.currencySymbol = "";
this.precision = -1;
this.repeat = false;
}
图形化信息
<GUI>
<xloc>416</xloc>
<yloc>176</yloc>
<draw>Y</draw>
</GUI>
如上GUI节点就能看到在图形化界面展示的信息。
输出节点
输出(ExcelOutputMeta)大部分是和ExcelInputMeta相似,其中有一些需要特殊设置,比如是否需要Excel的头,尾,是否追加文件等。
<header>Y</header>
<footer>N</footer>
<encoding/>
<append>N</append>
从ExcelOutputMeta中也能看到对应的属性,如下所示,
/** Add a header at the top of the file? */
@Injection( name = "HEADER_ENABLED", group = "CONTENT" )
private boolean headerEnabled;
/** Add a footer at the bottom of the file? */
@Injection( name = "FOOTER_ENABLED", group = "CONTENT" )
private boolean footerEnabled;
/** Flag : append workbook? */
@Injection( name = "APPEND", group = "CONTENT" )
private boolean append;
至此关于Ktr文件的分析和对应代码就找到了,那么就可以尝试写Excel交换代码。
三、交换代码
初始化环境
@Before
public void before() {
try {
//初始化环境
EnvUtil.environmentInit();
KettleEnvironment.init();
} catch (KettleException e) {
log.error("", e);
}
}
输入节点
/*
1.excel输入
*/
ExcelInputMeta inputMeta = new ExcelInputMeta();
//文件路径
String filePath = "F:\\kette_test\\input\\person.xlsx";
String[] fileName = new String[]{filePath};
inputMeta.setFileName(fileName);
String[] fileMasks = new String[1];
inputMeta.setFileMask(fileMasks);
String[] fileExcludeMasks = new String[1];
inputMeta.setExcludeFileMask(fileExcludeMasks);
String[] filerequireds = new String[]{"N"};
inputMeta.setFileRequired(filerequireds);
String[] subFolders = new String[]{"N"};
inputMeta.setIncludeSubFolders(subFolders);
inputMeta.setSpreadSheetType(SpreadSheetType.POI);
//第二行开始
int[] startRow = new int[]{1};
inputMeta.setStartRow(startRow);
//第一列开始
int[] startColumn = new int[]{0};
inputMeta.setStartColumn(startColumn);
输入字段列设置
//字段列
ExcelInputField[] excelInputFields = new ExcelInputField[3];
excelInputFields[0] = new ExcelInputField();
excelInputFields[0].setName("id");
excelInputFields[0].setType(ValueMetaInterface.TYPE_STRING);
excelInputFields[0].setTrimType(ExcelInputMeta.TYPE_TRIM_NONE);
excelInputFields[0].setRepeated(false);
excelInputFields[1] = new ExcelInputField();
excelInputFields[1].setName("name");
excelInputFields[1].setType(ValueMetaInterface.TYPE_STRING);
excelInputFields[1].setTrimType(ExcelInputMeta.TYPE_TRIM_NONE);
excelInputFields[1].setRepeated(false);
excelInputFields[2] = new ExcelInputField();
excelInputFields[2].setName("age");
excelInputFields[2].setType(ValueMetaInterface.TYPE_INTEGER);
excelInputFields[2].setTrimType(ExcelInputMeta.TYPE_TRIM_NONE);
excelInputFields[2].setRepeated(false);
inputMeta.setField(excelInputFields);
输出节点
/*
2. excel输出
*/
ExcelOutputMeta outputMeta = new ExcelOutputMeta();
outputMeta.setAppend(false);
outputMeta.setHeaderEnabled(true);
outputMeta.setFooterEnabled(false);
outputMeta.setFileName("F:\\kette_test\\output\\excel输出.xls");
outputMeta.setDoNotOpenNewFileInit(false);
outputMeta.setCreateParentFolder(false);
输出节点列设置
ExcelField[] excelFields = new ExcelField[3];
excelFields[0] = new ExcelField();
excelFields[0].setName("id");
excelFields[0].setType(ValueMetaInterface.TYPE_STRING);
excelFields[1] = new ExcelField();
excelFields[1].setName("name");
excelFields[1].setType(ValueMetaInterface.TYPE_STRING);
excelFields[2] = new ExcelField();
excelFields[2].setName("age");
excelFields[2].setType(ValueMetaInterface.TYPE_INTEGER);
excelFields[2].setFormat("0");
outputMeta.setOutputFields(excelFields);
设置Trans
TransMeta transMeta = new TransMeta();
transMeta.setName("excel交换");
PluginRegistry registry = PluginRegistry.getInstance();
将步骤添加到Trans
/*
3. 添加步骤
*/
String inputPluginId = registry.getPluginId(StepPluginType.class, inputMeta);
StepMeta inputStep = new StepMeta(inputPluginId, "excel-input", (StepMetaInterface) inputMeta);
//给步骤添加在spoon工具中的显示位置
inputStep.setDraw(true);
inputStep.setLocation(200, 200);
//将步骤添加进去
transMeta.addStep(inputStep);
String outPluginId = registry.getPluginId(StepPluginType.class, outputMeta);
StepMeta outputStep = new StepMeta(outPluginId, "excel-output", (StepMetaInterface) outputMeta);
//给步骤添加在spoon工具中的显示位置
outputStep.setDraw(true);
outputStep.setLocation(300, 200);
transMeta.addStep(outputStep);
步骤关联
/*
4. 关联步骤
*/
transMeta.addTransHop(new TransHopMeta(inputStep, outputStep));
交换执行
/*
5.执行
*/
Trans trans = new Trans(transMeta);
//执行转换
trans.execute(null);
//等待完成
trans.waitUntilFinished();
if (trans.getErrors() > 0) {
System.out.println("交换出错.");
return;
}
四、问题点
在写出上述代码前,也是运行了碰到很多坑,现在将问题一一罗列出来。
问题、no class found 没有jxl包和poi包
解决方式:
将pdi-ce-8.2.0.0-342\data-integration\lib 中的包拷贝过来并加入到idea中,
问题、 没有设置includeSubFolders属性
如上,告诉你空指针,然后报错是ExcelInputMeta对象的includeSubFolderBoolean方法,跟踪源码发现如下判断,
解决方式:
String[] subFolders = new String[]{"N"};
inputMeta.setIncludeSubFolders(subFolders);
问题、没有设置fileMask和excludeFileMask
继续看源码,跟踪,fileName,fileMask,excludeFileMask是要设值的。
解决方式:
//文件路径
String filePath = "F:\\kette_test\\input\\person.xlsx";
String[] fileName = new String[]{filePath};
inputMeta.setFileName(fileName);
String[] fileMasks = new String[1];
inputMeta.setFileMask(fileMasks);
String[] fileExcludeMasks = new String[1];
inputMeta.setExcludeFileMask(fileExcludeMasks);
问题、没有设置fileRequired
解决方式:
String[] filerequireds = new String[]{"N"};
inputMeta.setFileRequired(filerequireds);
问题、没有设置startRow和startColumn
这两个属性在ktr文件中是没有的,但是运行报错,通过跟踪源码发现,需要设置这两个属性,否则就是空指针异常了。
解决方式:
默认从0开始读取,这个数组长度和fileName是相匹配的。
//第二行开始
int[] startRow = new int[]{1};
inputMeta.setStartRow(startRow);
//第一列开始
int[] startColumn = new int[]{0};
inputMeta.setStartColumn(startColumn);
问题、少包
解决方式:
pom.xml中加入相应包,
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
运行成功
一个简单看ktr写代码就完了,好不容易。
完整交换代码
@Before
public void before() {
try {
//初始化环境
EnvUtil.environmentInit();
KettleEnvironment.init();
} catch (KettleException e) {
log.error("", e);
}
}
/**
* excel之间交换
*/
@Test
public void exchangeExcel2Excel() throws KettleException {
TransMeta transMeta = new TransMeta();
transMeta.setName("excel交换");
PluginRegistry registry = PluginRegistry.getInstance();
/*
1.excel输入
*/
ExcelInputMeta inputMeta = new ExcelInputMeta();
//文件路径
String filePath = "F:\\kette_test\\input\\person.xlsx";
String[] fileName = new String[]{filePath};
inputMeta.setFileName(fileName);
String[] fileMasks = new String[1];
inputMeta.setFileMask(fileMasks);
String[] fileExcludeMasks = new String[1];
inputMeta.setExcludeFileMask(fileExcludeMasks);
String[] filerequireds = new String[]{"N"};
inputMeta.setFileRequired(filerequireds);
String[] subFolders = new String[]{"N"};
inputMeta.setIncludeSubFolders(subFolders);
inputMeta.setSpreadSheetType(SpreadSheetType.POI);
//第二行开始
int[] startRow = new int[]{1};
inputMeta.setStartRow(startRow);
//第一列开始
int[] startColumn = new int[]{0};
inputMeta.setStartColumn(startColumn);
//字段列
ExcelInputField[] excelInputFields = new ExcelInputField[3];
excelInputFields[0] = new ExcelInputField();
excelInputFields[0].setName("id");
excelInputFields[0].setType(ValueMetaInterface.TYPE_STRING);
excelInputFields[0].setTrimType(ExcelInputMeta.TYPE_TRIM_NONE);
excelInputFields[0].setRepeated(false);
excelInputFields[1] = new ExcelInputField();
excelInputFields[1].setName("name");
excelInputFields[1].setType(ValueMetaInterface.TYPE_STRING);
excelInputFields[1].setTrimType(ExcelInputMeta.TYPE_TRIM_NONE);
excelInputFields[1].setRepeated(false);
excelInputFields[2] = new ExcelInputField();
excelInputFields[2].setName("age");
excelInputFields[2].setType(ValueMetaInterface.TYPE_INTEGER);
excelInputFields[2].setTrimType(ExcelInputMeta.TYPE_TRIM_NONE);
excelInputFields[2].setRepeated(false);
inputMeta.setField(excelInputFields);
/*
2. excel输出
*/
ExcelOutputMeta outputMeta = new ExcelOutputMeta();
outputMeta.setAppend(false);
outputMeta.setHeaderEnabled(true);
outputMeta.setFooterEnabled(false);
outputMeta.setFileName("F:\\kette_test\\output\\excel输出.xls");
outputMeta.setDoNotOpenNewFileInit(false);
outputMeta.setCreateParentFolder(false);
ExcelField[] excelFields = new ExcelField[3];
excelFields[0] = new ExcelField();
excelFields[0].setName("id");
excelFields[0].setType(ValueMetaInterface.TYPE_STRING);
excelFields[1] = new ExcelField();
excelFields[1].setName("name");
excelFields[1].setType(ValueMetaInterface.TYPE_STRING);
excelFields[2] = new ExcelField();
excelFields[2].setName("age");
excelFields[2].setType(ValueMetaInterface.TYPE_INTEGER);
excelFields[2].setFormat("0");
outputMeta.setOutputFields(excelFields);
/*
3. 添加步骤
*/
String inputPluginId = registry.getPluginId(StepPluginType.class, inputMeta);
StepMeta inputStep = new StepMeta(inputPluginId, "excel-input", (StepMetaInterface) inputMeta);
//给步骤添加在spoon工具中的显示位置
inputStep.setDraw(true);
inputStep.setLocation(200, 200);
//将步骤添加进去
transMeta.addStep(inputStep);
String outPluginId = registry.getPluginId(StepPluginType.class, outputMeta);
StepMeta outputStep = new StepMeta(outPluginId, "excel-output", (StepMetaInterface) outputMeta);
//给步骤添加在spoon工具中的显示位置
outputStep.setDraw(true);
outputStep.setLocation(300, 200);
transMeta.addStep(outputStep);
/*
4. 关联步骤
*/
transMeta.addTransHop(new TransHopMeta(inputStep, outputStep));
/*
5.执行
*/
Trans trans = new Trans(transMeta);
//执行转换
trans.execute(null);
//等待完成
trans.waitUntilFinished();
if (trans.getErrors() > 0) {
System.out.println("交换出错.");
return;
}
}
ktr内容
<?xml version="1.0" encoding="UTF-8"?>
<transformation>
<info>
<name>excel交换</name>
<description/>
<extended_description/>
<trans_version/>
<trans_type>Normal</trans_type>
<directory>/</directory>
<parameters>
</parameters>
<log>
<trans-log-table>
<connection/>
<schema/>
<table/>
<size_limit_lines/>
<interval/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>CHANNEL_ID</id>
<enabled>Y</enabled>
<name>CHANNEL_ID</name>
</field>
<field>
<id>TRANSNAME</id>
<enabled>Y</enabled>
<name>TRANSNAME</name>
</field>
<field>
<id>STATUS</id>
<enabled>Y</enabled>
<name>STATUS</name>
</field>
<field>
<id>LINES_READ</id>
<enabled>Y</enabled>
<name>LINES_READ</name>
<subject/>
</field>
<field>
<id>LINES_WRITTEN</id>
<enabled>Y</enabled>
<name>LINES_WRITTEN</name>
<subject/>
</field>
<field>
<id>LINES_UPDATED</id>
<enabled>Y</enabled>
<name>LINES_UPDATED</name>
<subject/>
</field>
<field>
<id>LINES_INPUT</id>
<enabled>Y</enabled>
<name>LINES_INPUT</name>
<subject/>
</field>
<field>
<id>LINES_OUTPUT</id>
<enabled>Y</enabled>
<name>LINES_OUTPUT</name>
<subject/>
</field>
<field>
<id>LINES_REJECTED</id>
<enabled>Y</enabled>
<name>LINES_REJECTED</name>
<subject/>
</field>
<field>
<id>ERRORS</id>
<enabled>Y</enabled>
<name>ERRORS</name>
</field>
<field>
<id>STARTDATE</id>
<enabled>Y</enabled>
<name>STARTDATE</name>
</field>
<field>
<id>ENDDATE</id>
<enabled>Y</enabled>
<name>ENDDATE</name>
</field>
<field>
<id>LOGDATE</id>
<enabled>Y</enabled>
<name>LOGDATE</name>
</field>
<field>
<id>DEPDATE</id>
<enabled>Y</enabled>
<name>DEPDATE</name>
</field>
<field>
<id>REPLAYDATE</id>
<enabled>Y</enabled>
<name>REPLAYDATE</name>
</field>
<field>
<id>LOG_FIELD</id>
<enabled>Y</enabled>
<name>LOG_FIELD</name>
</field>
<field>
<id>EXECUTING_SERVER</id>
<enabled>N</enabled>
<name>EXECUTING_SERVER</name>
</field>
<field>
<id>EXECUTING_USER</id>
<enabled>N</enabled>
<name>EXECUTING_USER</name>
</field>
<field>
<id>CLIENT</id>
<enabled>N</enabled>
<name>CLIENT</name>
</field>
</trans-log-table>
<perf-log-table>
<connection/>
<schema/>
<table/>
<interval/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>SEQ_NR</id>
<enabled>Y</enabled>
<name>SEQ_NR</name>
</field>
<field>
<id>LOGDATE</id>
<enabled>Y</enabled>
<name>LOGDATE</name>
</field>
<field>
<id>TRANSNAME</id>
<enabled>Y</enabled>
<name>TRANSNAME</name>
</field>
<field>
<id>STEPNAME</id>
<enabled>Y</enabled>
<name>STEPNAME</name>
</field>
<field>
<id>STEP_COPY</id>
<enabled>Y</enabled>
<name>STEP_COPY</name>
</field>
<field>
<id>LINES_READ</id>
<enabled>Y</enabled>
<name>LINES_READ</name>
</field>
<field>
<id>LINES_WRITTEN</id>
<enabled>Y</enabled>
<name>LINES_WRITTEN</name>
</field>
<field>
<id>LINES_UPDATED</id>
<enabled>Y</enabled>
<name>LINES_UPDATED</name>
</field>
<field>
<id>LINES_INPUT</id>
<enabled>Y</enabled>
<name>LINES_INPUT</name>
</field>
<field>
<id>LINES_OUTPUT</id>
<enabled>Y</enabled>
<name>LINES_OUTPUT</name>
</field>
<field>
<id>LINES_REJECTED</id>
<enabled>Y</enabled>
<name>LINES_REJECTED</name>
</field>
<field>
<id>ERRORS</id>
<enabled>Y</enabled>
<name>ERRORS</name>
</field>
<field>
<id>INPUT_BUFFER_ROWS</id>
<enabled>Y</enabled>
<name>INPUT_BUFFER_ROWS</name>
</field>
<field>
<id>OUTPUT_BUFFER_ROWS</id>
<enabled>Y</enabled>
<name>OUTPUT_BUFFER_ROWS</name>
</field>
</perf-log-table>
<channel-log-table>
<connection/>
<schema/>
<table/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>CHANNEL_ID</id>
<enabled>Y</enabled>
<name>CHANNEL_ID</name>
</field>
<field>
<id>LOG_DATE</id>
<enabled>Y</enabled>
<name>LOG_DATE</name>
</field>
<field>
<id>LOGGING_OBJECT_TYPE</id>
<enabled>Y</enabled>
<name>LOGGING_OBJECT_TYPE</name>
</field>
<field>
<id>OBJECT_NAME</id>
<enabled>Y</enabled>
<name>OBJECT_NAME</name>
</field>
<field>
<id>OBJECT_COPY</id>
<enabled>Y</enabled>
<name>OBJECT_COPY</name>
</field>
<field>
<id>REPOSITORY_DIRECTORY</id>
<enabled>Y</enabled>
<name>REPOSITORY_DIRECTORY</name>
</field>
<field>
<id>FILENAME</id>
<enabled>Y</enabled>
<name>FILENAME</name>
</field>
<field>
<id>OBJECT_ID</id>
<enabled>Y</enabled>
<name>OBJECT_ID</name>
</field>
<field>
<id>OBJECT_REVISION</id>
<enabled>Y</enabled>
<name>OBJECT_REVISION</name>
</field>
<field>
<id>PARENT_CHANNEL_ID</id>
<enabled>Y</enabled>
<name>PARENT_CHANNEL_ID</name>
</field>
<field>
<id>ROOT_CHANNEL_ID</id>
<enabled>Y</enabled>
<name>ROOT_CHANNEL_ID</name>
</field>
</channel-log-table>
<step-log-table>
<connection/>
<schema/>
<table/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>CHANNEL_ID</id>
<enabled>Y</enabled>
<name>CHANNEL_ID</name>
</field>
<field>
<id>LOG_DATE</id>
<enabled>Y</enabled>
<name>LOG_DATE</name>
</field>
<field>
<id>TRANSNAME</id>
<enabled>Y</enabled>
<name>TRANSNAME</name>
</field>
<field>
<id>STEPNAME</id>
<enabled>Y</enabled>
<name>STEPNAME</name>
</field>
<field>
<id>STEP_COPY</id>
<enabled>Y</enabled>
<name>STEP_COPY</name>
</field>
<field>
<id>LINES_READ</id>
<enabled>Y</enabled>
<name>LINES_READ</name>
</field>
<field>
<id>LINES_WRITTEN</id>
<enabled>Y</enabled>
<name>LINES_WRITTEN</name>
</field>
<field>
<id>LINES_UPDATED</id>
<enabled>Y</enabled>
<name>LINES_UPDATED</name>
</field>
<field>
<id>LINES_INPUT</id>
<enabled>Y</enabled>
<name>LINES_INPUT</name>
</field>
<field>
<id>LINES_OUTPUT</id>
<enabled>Y</enabled>
<name>LINES_OUTPUT</name>
</field>
<field>
<id>LINES_REJECTED</id>
<enabled>Y</enabled>
<name>LINES_REJECTED</name>
</field>
<field>
<id>ERRORS</id>
<enabled>Y</enabled>
<name>ERRORS</name>
</field>
<field>
<id>LOG_FIELD</id>
<enabled>N</enabled>
<name>LOG_FIELD</name>
</field>
</step-log-table>
<metrics-log-table>
<connection/>
<schema/>
<table/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>CHANNEL_ID</id>
<enabled>Y</enabled>
<name>CHANNEL_ID</name>
</field>
<field>
<id>LOG_DATE</id>
<enabled>Y</enabled>
<name>LOG_DATE</name>
</field>
<field>
<id>METRICS_DATE</id>
<enabled>Y</enabled>
<name>METRICS_DATE</name>
</field>
<field>
<id>METRICS_CODE</id>
<enabled>Y</enabled>
<name>METRICS_CODE</name>
</field>
<field>
<id>METRICS_DESCRIPTION</id>
<enabled>Y</enabled>
<name>METRICS_DESCRIPTION</name>
</field>
<field>
<id>METRICS_SUBJECT</id>
<enabled>Y</enabled>
<name>METRICS_SUBJECT</name>
</field>
<field>
<id>METRICS_TYPE</id>
<enabled>Y</enabled>
<name>METRICS_TYPE</name>
</field>
<field>
<id>METRICS_VALUE</id>
<enabled>Y</enabled>
<name>METRICS_VALUE</name>
</field>
</metrics-log-table>
</log>
<maxdate>
<connection/>
<table/>
<field/>
<offset>0.0</offset>
<maxdiff>0.0</maxdiff>
</maxdate>
<size_rowset>10000</size_rowset>
<sleep_time_empty>50</sleep_time_empty>
<sleep_time_full>50</sleep_time_full>
<unique_connections>N</unique_connections>
<feedback_shown>Y</feedback_shown>
<feedback_size>50000</feedback_size>
<using_thread_priorities>Y</using_thread_priorities>
<shared_objects_file/>
<capture_step_performance>N</capture_step_performance>
<step_performance_capturing_delay>1000</step_performance_capturing_delay>
<step_performance_capturing_size_limit>100</step_performance_capturing_size_limit>
<dependencies>
</dependencies>
<partitionschemas>
</partitionschemas>
<slaveservers>
</slaveservers>
<clusterschemas>
</clusterschemas>
<created_user>-</created_user>
<created_date>2021/11/18 16:00:56.529</created_date>
<modified_user>-</modified_user>
<modified_date>2021/11/18 16:00:56.529</modified_date>
<key_for_session_key/>
<is_key_private>N</is_key_private>
</info>
<notepads>
</notepads>
<order>
<hop>
<from>Excel输入</from>
<to>Excel输出</to>
<enabled>Y</enabled>
</hop>
</order>
<step>
<name>Excel输入</name>
<type>ExcelInput</type>
<description/>
<distribute>Y</distribute>
<custom_distribution/>
<copies>1</copies>
<partitioning>
<method>none</method>
<schema_name/>
</partitioning>
<header>Y</header>
<noempty>Y</noempty>
<stoponempty>N</stoponempty>
<filefield/>
<sheetfield/>
<sheetrownumfield/>
<rownumfield/>
<sheetfield/>
<filefield/>
<limit>0</limit>
<encoding/>
<add_to_result_filenames>Y</add_to_result_filenames>
<accept_filenames>N</accept_filenames>
<accept_field/>
<accept_stepname/>
<file>
<name>F:\kette_test\input\person.xlsx</name>
<filemask/>
<exclude_filemask/>
<file_required>N</file_required>
<include_subfolders>N</include_subfolders>
</file>
<fields>
<field>
<name>id</name>
<type>String</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
<field>
<name>name</name>
<type>String</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
<field>
<name>age</name>
<type>Integer</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
</fields>
<sheets>
</sheets>
<strict_types>N</strict_types>
<error_ignored>N</error_ignored>
<error_line_skipped>N</error_line_skipped>
<bad_line_files_destination_directory/>
<bad_line_files_extension>warning</bad_line_files_extension>
<error_line_files_destination_directory/>
<error_line_files_extension>error</error_line_files_extension>
<line_number_files_destination_directory/>
<line_number_files_extension>line</line_number_files_extension>
<shortFileFieldName/>
<pathFieldName/>
<hiddenFieldName/>
<lastModificationTimeFieldName/>
<uriNameFieldName/>
<rootUriNameFieldName/>
<extensionFieldName/>
<sizeFieldName/>
<spreadsheet_type>POI</spreadsheet_type>
<attributes/>
<cluster_schema/>
<remotesteps>
<input>
</input>
<output>
</output>
</remotesteps>
<GUI>
<xloc>416</xloc>
<yloc>176</yloc>
<draw>Y</draw>
</GUI>
</step>
<step>
<name>Excel输出</name>
<type>ExcelOutput</type>
<description/>
<distribute>Y</distribute>
<custom_distribution/>
<copies>1</copies>
<partitioning>
<method>none</method>
<schema_name/>
</partitioning>
<header>Y</header>
<footer>N</footer>
<encoding/>
<append>N</append>
<add_to_result_filenames>Y</add_to_result_filenames>
<file>
<name>F:\kette_test\output\excel输出.xls</name>
<extention/>
<do_not_open_newfile_init>N</do_not_open_newfile_init>
<create_parent_folder>N</create_parent_folder>
<split>N</split>
<add_date>N</add_date>
<add_time>N</add_time>
<SpecifyFormat>N</SpecifyFormat>
<date_time_format/>
<sheetname>Sheet1</sheetname>
<autosizecolums>N</autosizecolums>
<nullisblank>N</nullisblank>
<protect_sheet>N</protect_sheet>
<password>Encrypted </password>
<splitevery>0</splitevery>
<usetempfiles>N</usetempfiles>
<tempdirectory/>
</file>
<template>
<enabled>N</enabled>
<append>N</append>
<filename>template.xls</filename>
</template>
<fields>
<field>
<name>id</name>
<type>String</type>
<format/>
</field>
<field>
<name>name</name>
<type>String</type>
<format/>
</field>
<field>
<name>age</name>
<type>Integer</type>
<format>0</format>
</field>
</fields>
<custom>
<header_font_name>arial</header_font_name>
<header_font_size>10</header_font_size>
<header_font_bold>N</header_font_bold>
<header_font_italic>N</header_font_italic>
<header_font_underline>no</header_font_underline>
<header_font_orientation>horizontal</header_font_orientation>
<header_font_color>black</header_font_color>
<header_background_color>none</header_background_color>
<header_row_height>255</header_row_height>
<header_alignment>left</header_alignment>
<header_image/>
<row_font_name>arial</row_font_name>
<row_font_size>10</row_font_size>
<row_font_color>black</row_font_color>
<row_background_color>none</row_background_color>
</custom>
<attributes/>
<cluster_schema/>
<remotesteps>
<input>
</input>
<output>
</output>
</remotesteps>
<GUI>
<xloc>544</xloc>
<yloc>176</yloc>
<draw>Y</draw>
</GUI>
</step>
<step_error_handling>
</step_error_handling>
<slave-step-copy-partition-distribution>
</slave-step-copy-partition-distribution>
<slave_transformation>N</slave_transformation>
<attributes/>
</transformation>