使用Apache Camel通过地图列表将CSV文件转换为JSON文件

时间:2016-03-04 16:04:59

标签: apache-camel

目标是学习如何将CSV读取到地图列表,然后学习如何将其编组为JSON。

一旦我理解了如何做到这一点,我将了解如何定义更多有用的路线。

我使用XML来定义路由,另一个限制不是创建任何转换bean,而只使用现有的组件。

我的理解显然缺乏一些概念。我知道你必须提供一个bean作为消费者,然后你可以传递它;但是文档说csv dataformat使用的地图列表有什么问题?

    <dataFormats>
        <json id="jack" library="Jackson"/>
    </dataFormats>  

    <route>
        <from uri="file:///C:/tries/collApp/exchange/in?fileName=registerSampleSmaller.csv"/>
        <unmarshal>
            <csv />
        </unmarshal>            
        <marshal ref="jack">                
        </marshal>
        <to uri="file:///C:/tries/collApp/exchange/out?fileName=out.json"/>          
    </route>

默默无所作为。我只能看到锁文件是如何出现和消失的。

谢谢!

ps /我期待创建两个路由,第一个将读取一个csv,转换它 - 将它的平面性质塑造成我的持久性bean,而不是传递给我的bean。而第二个只是将我的豆子保存为json,似乎是一个简单的部分;但我首先需要这样做以了解它是如何工作的

3 个答案:

答案 0 :(得分:1)

请看一下这个DataFormat页面[1] 您可以使用那些编组DSL将对象转换为您想要的格式的String。 [1] http://camel.apache.org/data-format.html

答案 1 :(得分:1)

为什么要列出地图?为什么不列出名单?

  1. 使用Bindy将CSV解组为POJO列表。
  2. 使用带注释的类或标准的jackson代码将列表编组为JSON。
  3. 如果您需要代码示例,请告诉我。但主要的想法是在解开csv之后总是检查身体。你很可能会得到一个pojo列表。然后只需迭代列表,并为每个pojo获取“getters”并设置json标记的值。

答案 2 :(得分:1)

我提出了一个答案,因为我向前迈进了一步。

我走在正确的轨道上,只有很小的错误。 JérémieB在对原始问题的评论中注意到了一个。

它无声地失败因为我没有启用日志记录,我是通过在我的pom.xml中添加这样的slf4j来实现的:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j-version}</version>
    </dependency>    
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-jdk14</artifactId>
        <version>${slf4j-version}</version>
    </dependency>    
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>${slf4j-version}</version>
    </dependency>    

我看到了很多错误,甚至是Camel越野行为,但我已经设法让这条路线起作用了:

    <dataFormats>
        <json id="jack" library="Jackson" prettyPrint="true"/>
    </dataFormats>       

    <route>

        <from uri="file:///C:/tries/collApp/exchange/in?fileName=registerSampleUtf.csv&amp;charset=UTF-8"/>
        <log message="file: ${body.class.name} ${body}" loggingLevel="WARN"/>
        <unmarshal>
            <csv delimiter=";"  useMaps="true" />
        </unmarshal>           
        <log message="unmarshalled: ${body.class.name} ${body}" loggingLevel="WARN"/>
        <marshal ref="jack"/>
        <log message="marshalled: ${body}" loggingLevel="WARN"/>
        <to uri="file:///C:/tries/collApp/exchange/out?fileName=out.json"/>         
    </route>

所以基本上,在清理错别字后我不得不

  • 指定输入文件字符集,

  • 指定Excel用于创建csv的分隔符,

  • 告诉将其放入地图。

不幸的是,这个特定的代码不起作用,可能是由于我向开发者社区报告的Camel错误(还没有反应,http://camel.465427.n5.nabble.com/A-possible-bug-in-IOConverter-with-Win-1251-charset-td5778665.html

虽然我向前迈进,但现在我可能绕过了有缺陷的Camel的IOConverter,目前我正处于这个阶段(这不是问题的答案,只是为了信息,Camel有多方便):

    <route>
        <from uri="file:///C:/tries/collApp/exchange/in?fileName=registerSampleSmaller1.csv&amp;charset=windows-1251"/>
        <split streaming="true">
            <method ref="csvSplitter" method="tokenizeReader"/>  <!-- aprepends the first line of file for every subsequent line -->
            <log message="splitted: ${body}" loggingLevel="DEBUG"/>
            <unmarshal>
                <csv delimiter=";"  useMaps="true" />
            </unmarshal>            
            <log message="unmarshalled: size: ${body.size()}, ${body}" loggingLevel="DEBUG"/>
            <filter>
                <simple>${body.size()} == 1</simple><!-- be sure to have spaces around an operator -->
                <log message="filtered: listItem: ${body[0]['PATRONYMIC']}, list: ${body}" loggingLevel="DEBUG"/>
                <transform>
                    <spel>#{
                        {
                        lastName:body[0]['LAST_NAME'],
                        firstName: body[0]['FIRST_NAME'],
                        patronymic: body[0]['PATRONYMIC'],
                        comment:body[0]['COMMENT6']
                        }
                        }</spel><!-- split the spel {:} map creation notation in multiline is crucial-->
                </transform>                
                <log message="transformed: ${body}" loggingLevel="DEBUG"/>
                <marshal ref="jack"/>
                <log message="marshalled: ${body}" loggingLevel="DEBUG"/>
                <to uri="file:///C:/tries/collApp/exchange/out?fileName=out${exchangeProperty.CamelSplitIndex}.json"/>          
            </filter>
        </split>
    </route>

我必须编写自己的CSV分割器(关于所有Unicode代码点等),这基本上将第一行添加到所有后续行,但现在我能够以流畅的方式将CSV分成一组JSON ,或以不同方式处理对象而不是编组。

** update - csvSplitter code **

Reader Tokenizer - 读者周围的迭代器:

public class ReaderTokenizer implements Iterator<String> {

private String _curString = null;
private boolean _endReached = false;
private final Reader _reader;
private char[] _token;

public ReaderTokenizer(Reader reader, String token) {
    setToken(token);
    _reader = reader;
}

public final void setToken(String token){
    _token = token.toCharArray();
    if(_token.length==0){
        throw new IllegalArgumentException("Can't tokenize with the empty string");
    }
}

private void _readNextToken() throws IOException {

    int curCharInt;
    char previousChar = (char) -1;
    int tokenPos = 0;
    StringBuilder sb = new StringBuilder(255);

    while (true) {
        curCharInt = _reader.read();
        if (curCharInt == -1) {
            _endReached = true;
            _reader.close();
            break;
        }
        if (curCharInt == _token[tokenPos]) {

            if (tokenPos != 0 || !Character.isHighSurrogate(previousChar)) {
                tokenPos++;

                if (tokenPos >= _token.length) {
                    tokenPos = 0;
                    previousChar = (char) curCharInt;
                    sb.append(previousChar);
                    break;
                }
            }
        }

        previousChar = (char) curCharInt;
        sb.append(previousChar);
    }
    _curString = sb.toString();
}

@Override
public boolean hasNext() {
    if (_curString == null) {
        if (_endReached) {
            return false;
        }
        try {
            _readNextToken();
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }

        if (_curString != null) {
            return true;
        }

        if (_endReached) {
            return false;
        }

        throw new RuntimeException("Someting wrong");

    } else {
        return true;
    }
}

@Override
public String next() {
    if (_curString != null) {
        String ret = _curString;
        _curString = null;
        return ret;
    }
    if (_endReached) {
        throw new NoSuchElementException();
    }

    try {
        _readNextToken();
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }

    if (_curString != null) {
        String ret = _curString;
        _curString = null;
        return ret;
    }

    throw new RuntimeException("Someting wrong");
}

@Override
public void remove() {
    throw new UnsupportedOperationException("Not supported.");
}

}

分裂器本身:

public class CamelReaderSplitter {

private final String _token;
private final int _headerLinesNumber;

public CamelReaderSplitter(String token, int headerLinesNumber) {
    _token = token;
    _headerLinesNumber = headerLinesNumber;
}

public CamelReaderSplitter(String token) {
    _token = token;
    _headerLinesNumber = 1;
}

public CamelReaderSplitter(int headerLinesNumber) {
    _token = "\r\n";
    _headerLinesNumber = headerLinesNumber;
}

public CamelReaderSplitter() {
    _token = "\r\n";
    _headerLinesNumber = 1;
}

public Iterator<String> tokenizeReader(final Reader reader) throws IOException {

    Iterator<String> ret = new ReaderTokenizer(reader, _token) {

        private final String _firstLines;

        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < _headerLinesNumber; i++) {
                if (super.hasNext()) {
                    sb.append(super.next());
                }
            }
            _firstLines = sb.toString();
        }

        @Override
        public String next() {
            return _firstLines + super.next();
        }

    };

    return ret;

}

}