Kettle使用备忘录1-生成xml文件

最近被抓壮丁去弄一个ETL的项目,要求用开源的kettle去替代原来平台上的datastage。
本文主要是记录下在使用kettle过程中碰到的头疼的问题和解决方案。。。

1. 利用 excel中的数据生成xml文件

kettle中的xml文件输出组件的功能其实是很弱的,所以要生成较为复杂的xml文件时需要使用组件:
add xml, xml join, placeholder,js script 等等
如下是一个例子:

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件
使用merge join主要是为了减少在xml join中需要匹配的结果集合(因为xml join中的匹配功能其实是很弱的)。
在merge join之前记录必须先排序。
placeholder 组件是往记录流中添加一个常量,这个常量在 add xml中通常不被设为属性,而是在xml join中用于放置需要被组装进去的xml元素。
生成如下简单的xml文件为例:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<section name="foo">
<p>
Hello from section foo
</p>
</section>
<section name="bar">
<p>
Hello from section bar
</p>
</section>
</document>
对应的kettle 转换为:

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件

首先需要从excel文件中读取数据,excel文件中的内容

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件
利用读取到的内容生成xml元素,如下是add xml中的设置:

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件
这一步主要生成了如下的xml元素:
<section name="foo">
<p>
Hello from section foo
</p>
</section>
<section name="bar">
<p>
Hello from section bar
</p>
</section>
接下来要生成 <document>元素,因为该元素没有对应的数据,所以使用“生成记录”组件生成一条空记录用于与之前的xml元素进行xml join。它的功能有点类似与之前提到的placeholder,不同的是这个可以作为起始输入,而placeholder是一个转换步骤。

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件
然后是利用这条生成的记录生成xml元素document,注意属性选否:

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件

接着就是进行xml join了,source stream中的xml元素会被拼接到target stream的xml元素中。怎么拼接有join condition properties决定,它是使用xpath来定位要拼接的位置,例如//doc 就是把source stream的元素拼接到每个doc元素中。需要注意的是,由于这次xml join之后xml文件生成好了,所以不能把omit xml header选上。

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件
当然通过xpath也可以做复杂的条件join,如下是个例子:

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件

可以通过xpath指定在所有target stream的area元素中如果area的属性STATIONID的值与source stream中STATIONID的值(这个值不一定要在source的xml元素中,但必须在source stream中,例如可以是一开始从excel读入的流中)相同,那么把source stream中的xml元素放到 orderlinecomments元素中。

这步之后生成的xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<doc>
<section name="foo">
<p>
Hello from section foo
</p>
</section>
<section name="bar">
<p>
Hello from section bar
</p>
</section>
</doc>
</document>
和我们预期的多了<doc>和</doc>,这是我们使用js脚本进行替换:

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件

js脚本处理好之后,输出流的名字就换成 xmlOderLinesNew了。
最后把这个流输出文件中,需要注意的是在内容中不要使用“分割符”,“封闭符”,和“头部”:

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件


--关于kettle生成xml文件性能问题
各个步骤中addxml的效率不错,但是xmljoin在大数据量的情况下效率实在太低。。。,按照我的理解,kettle通过addxml生成一个xml内容的字符串,然后xmljoin其实是对两个大字符串进行重构,这个重构过程还涉及到字符子串的定位,拷贝,比较,甚至是字符串子串级别的join。。。效率很难能高,所以在数据量比较大的时候应该避免使用xmljoin。
其实我们使用xmljoin主要是为了生成层次化的xml文件。作为替代方案,首先在使用addxml生成xml字符串之前,先使用merge join把目标xml文件中所需的数据先生成出来,这个时候生成的xml字符串中的xml是几乎没有层次的:
例如
<?xml version="1.0" encoding="ISO-8859-1"?>
<Users>
<User id="2" name="ABC" Division="HR" country="C"/>
<User id="3" name="xyz" Division="Admin" country="D"/>
<User id="4" name="LMN" Division="Admin" country="D"/>
<User id="5" name="PQR" Division="HR" country="C"/>
</Users>
然后我们可以通过xslt进行xml文件结构的重构,xsl文件的示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes" />

<xsl:key name="division" match="User" use="concat(@Division,',@country)" />

<xsl:template match="Users">
<AllUsers>
<xsl:apply-templates select="User[generate-id()=generate-id(key('division',concat(@Division,@country))[1])]"/>
</AllUsers>
</xsl:template>

<xsl:template match="User">
<Division value="{@Division}" country="{@country}">
<xsl:for-each select="key('division',@country))">
<User id="{@id}" name="{@name}"/>
</xsl:for-each>
</Division>
</xsl:template>

</xsl:stylesheet>
生成的目标xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<AllUsers>
<Division country="C" value="HR">
<User name="ABC" id="2"/>
<User name="PQR" id="5"/>
</Division>
<Division country="D" value="Admin">
<User name="xyz" id="3"/>
</Division>
<Division country="D" value="Payroll">
<User name="LMN" id="4"/>
</Division>
</AllUsers>

具体到kettle中我们可以使用xsl transformation组件来进行转换:

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件
其中的xsl 转换:

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件

理想的状态是我们直接使用转换中的XSL Transformation组件,在转换级别就解决问题,但事与愿违,这个步骤老是报错。。。

Kettle<wbr></p>使用备忘录<wbr>1-<wbr><a href=生成xml文件" title="Kettle使用备忘录1-生成xml文件" src="http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif">
只好使用job级别的XSL Transformation组件,这样会比较麻烦,要先通过一个转换生成中间xml文件保存到磁盘,然后在调用XSL Transformation组件读取这个中间xml文件以及定义好的xsl文件生成目标xml文件。。

Kettle<wbr></p>使用备忘录<wbr>1-<wbr>生成xml文件 还有一种思路是不使用kettle的xsl transformation组件,而是直接在kettle的User Define Java Class组件中通过java代码调用xsl文件进行转换,java代码调用xsl文件和xml文件进行转换的代码可以参考: http://www.blogjava.net/yangxiang/archive/2009/08/11/290688.html 关于xsl文件的编写可以参考 http://stackoverflow.com/questions/2146648/how-to-apply-group-by-on-xslt-elements

相关文章

引言 NOKIA 有句著名的广告语:“科技以人为本”。任何技术都是为了满足人的生产生活需要而产生的。具体...
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Reprint it anywhere u want. 文章...
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Reprint it anywhere u want. 文章...
http://blog.jobbole.com/79252/ 引言 NOKIA 有句著名的广告语:“科技以人为本”。任何技术都是为了满...
(点击上方公众号,可快速关注) 公众号:smart_android 作者:耿广龙|loonggg 点击“阅读原文”,可查看...
一、xml与xslt 相信所有人对xml都不陌生,其被广泛的应用于数据数据传输、保存与序列化中,是一种极为强...