Apache Camel:使用多行值解析csv文件

时间:2014-08-30 18:52:41

标签: csv apache-camel

我有一个单行csv,第二个值由多行组成:

field1,"this

is still

field2","field3"

我希望使用Apache Camel,它是一个像这样的json(解析文件后):

{"field1":"field1","field2":"this

is still

field2","field3":"field3"}

但使用以下代码:

from('something...')
    .transform(simple('/path/demooneline.csv', File.class))
        .unmarshal().bindy(BindyType.Csv, Demo.class)
        .marshal().json(JsonLibrary.Jackson).log('${body}')

@CsvRecord(separator = ',')
class Demo {

    @JsonView
    @DataField(pos = 1)
    private String field1

    @JsonView
    @DataField(pos = 2)
    private String field2

    @JsonView
    @DataField(pos = 3)
    private String field3

}

我回来了:

{"field1":"field1","field2":"this","field3":null},
{"field1":"is still","field2":null,"field3":null},
{"field1":null,"field2":"field3","field3":null}

看起来csv分为3行,而不是1行,其中一些字段用引号分隔。 @CsvRecord有"引用"作为默认值。有没有办法用Camel解析那种CSV(使用或不使用bindy)?

1 个答案:

答案 0 :(得分:3)

问题是您的CSV文件不是典型的"。来自Wikipidia

  

" CSV"不是单一的,定义良好的格式(尽管通常使用的是一个定义的RFC 4180)。相反,在实践中,术语" CSV"指任何文件:

     
      
  1. 是使用ASCII,Unicode,EBCDIC或Shift JIS等字符集的纯文本,
  2.   
  3. 由记录(通常每行一条记录)
  4. 组成   
  5. 将记录划分为由分隔符分隔的字段(通常是单个保留字符,如逗号,分号或制表符;有时分隔符可能包含可选空格),
  6.   
  7. 其中每条记录都有相同的字段序列。
  8.   

在你的情况下,你的记录跨越多行,这就是为什么Camel没有像你期望的那样解析它,Camel假设每行都是不同的记录。

修改

正如我在评论中提到的,看起来Camel Bindy不处理包含换行符的引用字段。作为一种解决方法,您可以预处理"源CSV文件替换qoutes内的换行符。例如,使用Guava

   from("file:///csvSrcDir?noop=true")
        .process(new Processor() {
          @Override
          public void process(Exchange exchange) throws Exception {
            final String inBody = exchange.getIn().getBody(String.class);
            final Iterable<String> tokens = Splitter.on("\",").split(inBody);
            final Iterable<String> fixedTokens = FluentIterable.from(tokens).transform(new Function<String, String>() {
              @Nullable
              @Override
              public String apply(String input) {
                return input.contains("\"\n") ? input : input.replace("\n", "<br>");
              }
            });
            final String outBody = Joiner.on("\",").join(fixedTokens);
            exchange.getOut().setBody(outBody);
          }
        })
        .unmarshal().bindy(BindyType.Csv, Demo.class)
        .split(body())
        .process(new Processor() {
          @Override
          public void process(Exchange exchange) throws Exception {
            Demo body = exchange.getIn().getBody(Demo.class);
          }
        });

自定义处理器转换此CSV文件:

"record 1 field1","this

is still

record 1 field2","record 1 field3"
"record 2 field1","this

is still

record line 2 field2","record 2 field3" 

归档:

"record 1 field1","this<br><br>is still<br><br> record 1 field2","record 1 field3"
"record 2 field1","this<br><br>is still<br><br> record 2 field2","record 2 field3"

Bindy可以处理。