Java库或应用程序可将CSV文件转换为XML文件吗?

121

是否存在一个现成的Java应用程序或库,可以将CSV数据文件转换为XML文件?

XML标记将通过第一行包含列标题来提供。


54
似乎这是SO上第一个带有Java标签的问题。 - Paul Vargas
9
@Paul 不仅如此,它还是123! - bjb568
1
@Tommy https://dev59.com/L3VD5IYBdhLWcg3wXamd/ - bjb568
1
@bjb568 哦,哈哈。 - user7627726
8
难怪 Stack Overflow 上 Java 的第一个帖子被关闭了,因为它不属于主题:D - Sir. Hedgehog
显示剩余3条评论
16个回答

70

或许这会对您有所帮助:JSefa

您可以使用此工具读取CSV文件并将其序列化为XML。


49

像其他人一样,我不知道有什么一步完成的方法,但如果您准备使用非常简单的外部库,我建议使用:

OpenCsv用于解析 CSV(小巧、简单、可靠且易于使用)

Xstream 用于解析/序列化 XML(非常容易使用,并创建完全可读的 xml)

使用与上面相同的示例数据,代码如下所示:

package fr.megiste.test;

import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;

import au.com.bytecode.opencsv.CSVReader;

import com.thoughtworks.xstream.XStream;

public class CsvToXml {     

    public static void main(String[] args) {

        String startFile = "./startData.csv";
        String outFile = "./outData.xml";

        try {
            CSVReader reader = new CSVReader(new FileReader(startFile));
            String[] line = null;

            String[] header = reader.readNext();

            List out = new ArrayList();

            while((line = reader.readNext())!=null){
                List<String[]> item = new ArrayList<String[]>();
                    for (int i = 0; i < header.length; i++) {
                    String[] keyVal = new String[2];
                    String string = header[i];
                    String val = line[i];
                    keyVal[0] = string;
                    keyVal[1] = val;
                    item.add(keyVal);
                }
                out.add(item);
            }

            XStream xstream = new XStream();

            xstream.toXML(out, new FileWriter(outFile,false));

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

产生以下结果: (Xstream允许对结果进行非常精细的调整...)

<list>
  <list>
    <string-array>
      <string>string</string>
      <string>hello world</string>
    </string-array>
    <string-array>
      <string>float1</string>
      <string>1.0</string>
    </string-array>
    <string-array>
      <string>float2</string>
      <string>3.3</string>
    </string-array>
    <string-array>
      <string>integer</string>
      <string>4</string>
    </string-array>
  </list>
  <list>
    <string-array>
      <string>string</string>
      <string>goodbye world</string>
    </string-array>
    <string-array>
      <string>float1</string>
      <string>1e9</string>
    </string-array>
    <string-array>
      <string>float2</string>
      <string>-3.3</string>
    </string-array>
    <string-array>
      <string>integer</string>
      <string>45</string>
    </string-array>
  </list>
  <list>
    <string-array>
      <string>string</string>
      <string>hello again</string>
    </string-array>
    <string-array>
      <string>float1</string>
      <string>-1</string>
    </string-array>
    <string-array>
      <string>float2</string>
      <string>23.33</string>
    </string-array>
    <string-array>
      <string>integer</string>
      <string>456</string>
    </string-array>
  </list>
  <list>
    <string-array>
      <string>string</string>
      <string>hello world 3</string>
    </string-array>
    <string-array>
      <string>float1</string>
      <string>1.40</string>
    </string-array>
    <string-array>
      <string>float2</string>
      <string>34.83</string>
    </string-array>
    <string-array>
      <string>integer</string>
      <string>4999</string>
    </string-array>
  </list>
  <list>
    <string-array>
      <string>string</string>
      <string>hello 2 world</string>
    </string-array>
    <string-array>
      <string>float1</string>
      <string>9981.05</string>
    </string-array>
    <string-array>
      <string>float2</string>
      <string>43.33</string>
    </string-array>
    <string-array>
      <string>integer</string>
      <string>444</string>
    </string-array>
  </list>
</list>

30

我知道你要求Java,但这让我觉得脚本语言更适合这个任务。以下是用Groovy编写的一个快速(非常简单)解决方案。

test.csv

string,float1,float2,integer
hello world,1.0,3.3,4
goodbye world,1e9,-3.3,45
hello again,-1,23.33,456
hello world 3,1.40,34.83,4999
hello 2 world,9981.05,43.33,444

csvtoxml.groovy

#!/usr/bin/env groovy

def csvdata = []
new File("test.csv").eachLine { line ->
    csvdata << line.split(',')
}

def headers = csvdata[0]
def dataRows = csvdata[1..-1]

def xml = new groovy.xml.MarkupBuilder()

// write 'root' element
xml.root {
    dataRows.eachWithIndex { dataRow, index ->
        // write 'entry' element with 'id' attribute
        entry(id:index+1) {
            headers.eachWithIndex { heading, i ->
                // write each heading with associated content
                "${heading}"(dataRow[i])
            }
        }
    }
}

输出以下 XML 到标准输出:

Writes the following XML to stdout:

<root>
  <entry id='1'>
    <string>hello world</string>
    <float1>1.0</float1>
    <float2>3.3</float2>
    <integer>4</integer>
  </entry>
  <entry id='2'>
    <string>goodbye world</string>
    <float1>1e9</float1>
    <float2>-3.3</float2>
    <integer>45</integer>
  </entry>
  <entry id='3'>
    <string>hello again</string>
    <float1>-1</float1>
    <float2>23.33</float2>
    <integer>456</integer>
  </entry>
  <entry id='4'>
    <string>hello world 3</string>
    <float1>1.40</float1>
    <float2>34.83</float2>
    <integer>4999</integer>
  </entry>
  <entry id='5'>
    <string>hello 2 world</string>
    <float1>9981.05</float1>
    <float2>43.33</float2>
    <integer>444</integer>
  </entry>
</root>

然而,该代码仅执行简单的解析(不考虑引号或转义逗号)并且未考虑可能缺少的数据。


所以你可以调用一个CSV库来进行解析,然后使用标记生成器。也许你可以编辑你的答案来展示这一点。 - Peter Kelley

19

我有一个开源框架,用于处理 CSV 和其他平面文件。也许值得一看:JFileHelpers

使用该工具包,您可以像使用 bean 一样编写代码:

@FixedLengthRecord()
public class Customer {
    @FieldFixedLength(4)
    public Integer custId;

    @FieldAlign(alignMode=AlignMode.Right)
    @FieldFixedLength(20)
    public String name;

    @FieldFixedLength(3)
    public Integer rating;

    @FieldTrim(trimMode=TrimMode.Right)
    @FieldFixedLength(10)
    @FieldConverter(converter = ConverterKind.Date, 
    format = "dd-MM-yyyy")
    public Date addedDate;

    @FieldFixedLength(3)
    @FieldOptional
    public String stockSimbol;  
}

然后只需要使用以下方法解析您的文本文件:

FileHelperEngine<Customer> engine = 
    new FileHelperEngine<Customer>(Customer.class); 
List<Customer> customers = 
    new ArrayList<Customer>();

customers = engine.readResource(
    "/samples/customers-fixed.txt");

你将拥有一系列解析后的对象。

希望这能帮到你!


很遗憾,截至今日,该项目似乎自2009-08-11以来没有任何新版本... +1 用于注释的使用。 - Stephan
是的,自那时以来我没有时间继续开发,但它非常稳定。 - kolrie

18

这个解决方案不需要使用任何CSV或XML库,我知道它无法处理任何非法字符和编码问题,但是如果你的CSV输入不违反以上规则,你可能也会对它感兴趣。

注意:除非你知道自己在做什么,或者没有机会使用进一步的库(某些官僚项目可能会有这种情况),否则不要使用此代码...在旧的运行环境中,请使用StringBuffer...

所以让我们开始吧:

BufferedReader reader = new BufferedReader(new InputStreamReader(
        Csv2Xml.class.getResourceAsStream("test.csv")));
StringBuilder xml = new StringBuilder();
String lineBreak = System.getProperty("line.separator");
String line = null;
List<String> headers = new ArrayList<String>();
boolean isHeader = true;
int count = 0;
int entryCount = 1;
xml.append("<root>");
xml.append(lineBreak);
while ((line = reader.readLine()) != null) {
    StringTokenizer tokenizer = new StringTokenizer(line, ",");
    if (isHeader) {
        isHeader = false;
        while (tokenizer.hasMoreTokens()) {
            headers.add(tokenizer.nextToken());
        }
    } else {
        count = 0;
        xml.append("\t<entry id=\"");
        xml.append(entryCount);
        xml.append("\">");
        xml.append(lineBreak);
        while (tokenizer.hasMoreTokens()) {
            xml.append("\t\t<");
            xml.append(headers.get(count));
            xml.append(">");
            xml.append(tokenizer.nextToken());
            xml.append("</");
            xml.append(headers.get(count));
            xml.append(">");
            xml.append(lineBreak);
            count++;
        }
        xml.append("\t</entry>");
        xml.append(lineBreak);
        entryCount++;
    }
}
xml.append("</root>");
System.out.println(xml.toString());

以下是被从本页另一个答案窃取的输入文件test.csv:

string,float1,float2,integer
hello world,1.0,3.3,4
goodbye world,1e9,-3.3,45
hello again,-1,23.33,456
hello world 3,1.40,34.83,4999
hello 2 world,9981.05,43.33,444

生成的输出:
<root>
    <entry id="1">
        <string>hello world</string>
        <float1>1.0</float1>
        <float2>3.3</float2>
        <integer>4</integer>
    </entry>
    <entry id="2">
        <string>goodbye world</string>
        <float1>1e9</float1>
        <float2>-3.3</float2>
        <integer>45</integer>
    </entry>
    <entry id="3">
        <string>hello again</string>
        <float1>-1</float1>
        <float2>23.33</float2>
        <integer>456</integer>
    </entry>
    <entry id="4">
        <string>hello world 3</string>
        <float1>1.40</float1>
        <float2>34.83</float2>
        <integer>4999</integer>
    </entry>
    <entry id="5">
        <string>hello 2 world</string>
        <float1>9981.05</float1>
        <float2>43.33</float2>
        <integer>444</integer>
    </entry>
</root>

16

最大的区别在于JSefa可以将您的Java对象序列化为CSV/XML等文件,并可以反序列化回Java对象。并且它是由注释驱动的,这使您对输出有很多控制。

JFileHelpers看起来也很有趣。


16

我不明白你为什么想要这样做。这几乎听起来像是盲目追随的编码。

将CSV文件转换成XML并没有增加任何价值。您的程序已经在读取CSV文件,因此认为您需要XML是行不通的。

另一方面,读取CSV文件,对值进行某些操作,然后序列化为XML是有意义的(嗯,尽管使用XML可能有点不可思议... ;)),但您应该已经有了一种序列化到XML的方法。


15

您可以使用Groovy非常容易地完成此操作,代码非常易读。

基本上,对于contactData.csv中的每一行,文本变量将被写入contacts.xml,而fields数组包含每个列。

def file1 = new File('c:\\temp\\ContactData.csv')
def file2 = new File('c:\\temp\\contacts.xml')

def reader = new FileReader(file1)
def writer = new FileWriter(file2)

reader.transformLine(writer) { line ->
    fields =  line.split(',')

    text = """<CLIENTS>
    <firstname> ${fields[2]} </firstname>
    <surname> ${fields[1]} </surname>
    <email> ${fields[9]} </email>
    <employeenumber> password </employeenumber>
    <title> ${fields[4]} </title>
    <phone> ${fields[3]} </phone>
    </CLIENTS>"""
}

7
CSV很简单,但通常不够简单,只用逗号拆分是不够的。 - Alan Krueger

13
你可以使用XSLT。搜索一下谷歌,你会找到一些示例,例如CSV转XML。如果你使用XSLT,那么你可以将XML转换成任何你想要的格式。

8

还有一款很好的库ServingXML,由Daniel Parker制作,能够将几乎所有普通文本格式转换为XML格式并进行反向转换。

对于您的情况,可以在此处找到示例here:它使用CSV文件中字段的标题作为XML元素名。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接