用Smooks读取CSV

时间:2012-01-27 19:48:17

标签: java csv etl smooks

使用Smooks(1.4)读取CSV并将其转换为Person POJO。

CSV由每行上的逗号分隔记录组成,每条记录都有竖线分隔的字段:

  

史密斯|约翰| 45 |男性|尊| JSMITH | JSmizzle,

     

史密斯|简| 43 |女性|詹尼

等。因此,每一行代表一个不同的人创造。首先,POJO:

public class Person
{
    private String lastName;
    private String firstName;
    private int age;
    private boolean isMale;
    private List<String> aliases;
}

我的问题在于List个别名。以下是我的XML配置中的重要部分:

<reader class="org.milyn.csv.CSVReader">
    <param name="fields">lastName,fristName,age,gender,aliases</param>
    <param name="separator">&#124;</param>
    <param name="strict">false</param>
</reader>

<core:filterSettings type="SAX"/>

<jb:bean beanId="person" class="net.me.myproject.app.Person" createOnElement="csv-set/csv-record/">
    <jb:value property="lastName" data="csv-set/csv-record/lastName"/>
    <jb:value property="firstName" data="csv-set/csv-record/firstName"/>
    <jb:value property="isMale" data="csv-set/csv-record/gender"/>
    <jb:value property="age" data="csv-set/csv-record/age"/>
    <jb:wiring property="aliases" beanRefId="aliases"/>
</jb:bean>

<jb:bean beanId="aliases" class="java.util.ArrayList" createOnElement="???">
    <jb:wiring beanRefId="alias"/>
</jb:bean>

<jb:bean beanId="alias" class="java.util.String" createOnElement="???">
    ???
</jb:bean>

所以我窒息的地方是为createOnElement ArrayList以及每个aliases字符串正确配置alias。提前感谢任何能够朝着正确的方向推动我的人!

2 个答案:

答案 0 :(得分:4)

首先,您的CSVReader的“字段”属性将成为CSV文件中包含的所有字段的大杂烩,无论哪个POJO,列表或类型如何回到地图。因此,某些字段将是Person属性,而某些字段将是实际属于单独aliases bean的别名,其类型为java.util.ArrayList<String>

你的工作是告诉Smooks如何将每个字段映射到相应的bean / list / component / type / etc,这意味着告诉它在遇到每个字段时该怎么做。

Smooks不支持这种“动态”字段绑定,您可以将0 + CSV字段映射回ArrayList,它本身将为空或填充。您必须枚举CSVReader中的每个字段,这意味着拥有ArrayList具有固定大小的别名。

因此,您必须确定可与每个Person关联的最大别名数,并在字段列表中对其进行说明:

<reader class="org.milyn.csv.CSVReader">
    <param name="fields">lastName,fristName,age,gender,alias1,alias2,alias3</param>
    <param name="separator">&#124;</param>
    <param name="strict">false</param>
</reader>

这意味着每个CSV记录必须具有3个别名的可靠值。我建议使用“忽略”值,例如“%%%IGNORE%%%”,这样你的app逻辑就无法删除包含该值的列表项(在Smooks完成转换之后)。

您可能还想查看Smooks的内置$ignore$令牌,该令牌可能已经执行此操作或类似内容。

在我们可以在一个完整的代码示例中将所有内容组合在一起之前的最后一部分是简单地接受Smooks在这种示例中没有(或不公开记录)任何使用List<String>的能力的可悲事实。您必须转换POJO以使用List<StringBuffer>List<StringBuilder>作为别名,以便我们可以优先使用名为value的Smooks-JavaBean setterMethod元素属性。

现在:

<jb:bean beanId="aliases" class="java.util.ArrayList" createOnElement="csv-set/csv-record">
    <jb:wiring beanRefId="alias1"/>
    <jb:wiring beanRefId="alias2"/>
    <jb:wiring beanRefId="alias3"/>
</jb:bean>

<jb:bean beanId="alias1" class="java.util.StringBuffer" createOnElement="csv-set/csv-record/alias1">
    <jb:value data="csv-set/csv-record/alias1" setterMethod="append" />
</jb:bean>

<jb:bean beanId="alias2" class="java.util.StringBuffer" createOnElement="csv-set/csv-record/alias2">
    <jb:value data="csv-set/csv-record/alias2" setterMethod="append" />
</jb:bean>

<jb:bean beanId="alias3" class="java.util.StringBuffer" createOnElement="csv-set/csv-record/alias3">
    <jb:value data="csv-set/csv-record/alias3" setterMethod="append" />
</jb:bean>

因此,每次我们开始解析新的csv-record时,我们都会创建一个person bean(因为您的初始代码示例完美展示)以及一个aliases bean。然后,在解析此记录的过程中,我们会找到Person属性以及alias1alias3aliasN字段存储到aliases bean中,同时另一个Person字段存储到person bean中。最后,Smooks知道将personaliases bean“连接”在一起以创建Java Person对象。

答案 1 :(得分:0)

好的答复亚当。

在你最后提出的名单问题上......我还没有尝试过,但是我有以下情况应该有效......

<jb:bean beanId="aliases" class="java.util.ArrayList" createOnElement="csv-set/csv-record">
    <jb:value data="csv-set/csv-record/alias1" decoder="String"/>
    <jb:value data="csv-set/csv-record/alias2" decoder="String"/>
    <jb:value data="csv-set/csv-record/alias3" decoder="String"/>
</jb:bean>