Java lib ou app para converter CSV em arquivo XML? [fechadas]

114

Existe um aplicativo ou biblioteca em Java que me permite converter um CSVarquivo de dados em XMLarquivo?

As XMLtags seriam fornecidas possivelmente pela primeira linha contendo os cabeçalhos das colunas.

A Salim
fonte
47
Parece que essa é a primeira pergunta com a tag Java no SO.
Paul Vargas
8
@Paul Não só isso, também é 123!
bjb568 de
1
@Tommy stackoverflow.com/q/123
bjb568
1
@ bjb568 Oh. haha
4
Não é à toa que o primeiro post de java em SO foi fechado como fora do tópico: D
Senhor. Hedgehog

Respostas:

66

Talvez isso possa ajudar: JSefa

Você pode ler o arquivo CSV com esta ferramenta e serializá-lo para XML.

svrist
fonte
47

Como os outros acima, não conheço nenhuma maneira simples de fazer isso, mas se você estiver pronto para usar bibliotecas externas muito simples, sugiro:

OpenCsv para análise de CSV (pequeno, simples, confiável e fácil de usar)

Xstream para analisar / serializar XML (muito, muito fácil de usar e criando um xml totalmente legível por humanos)

Usando os mesmos dados de amostra acima, o código ficaria assim:

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();
        }
    }
}

Produzindo o seguinte resultado: (Xstream permite um ajuste muito fino do resultado ...)

<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>
Laurent K
fonte
27

Eu sei que você pediu Java, mas isso me parece uma tarefa adequada para uma linguagem de script. Aqui está uma solução rápida (muito simples) escrita em 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])
            }
        }
    }
}

Grava o seguinte XML no 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>

No entanto, o código faz uma análise muito simples (sem levar em consideração as vírgulas entre aspas ou com escape) e não leva em consideração a possível ausência de dados.

Anthony Cramp
fonte
Portanto, você pode chamar uma biblioteca CSV para fazer a análise e, em seguida, usar o construtor de marcação. Talvez você possa editar sua resposta para mostrar isso.
Peter Kelley
18

Eu tenho uma estrutura de código aberto para trabalhar com CSV e arquivos simples em geral. Talvez valha a pena procurar: JFileHelpers .

Com esse kit de ferramentas, você pode escrever código usando beans, como:

@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;  
}

e então apenas analise seus arquivos de texto usando:

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

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

E você terá uma coleção de objetos analisados.

Espero que ajude!

Kolrie
fonte
+1 para o uso de anotações. Infelizmente, a partir de hoje, parece que o projeto não tem nenhuma nova versão desde 11/08/2009 ...
Stephan
Sim, não tive tempo de continuar com o desenvolvimento desde então, mas é muito estável.
kolrie
17

Esta solução não precisa de nenhuma biblioteca CSV ou XML e, eu sei, ela não lida com caracteres ilegais e problemas de codificação, mas você pode estar interessado nela também, desde que sua entrada CSV não quebre as regras mencionadas acima.

Atenção: Você não deve usar este código a menos que saiba o que faz ou não tenha a chance de usar outra biblioteca (possível em alguns projetos burocráticos) ... Use um StringBuffer para ambientes de tempo de execução mais antigos ...

Aqui vamos nos:

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());

A entrada test.csv (roubada de outra resposta desta página):

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

A saída resultante:

<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>
Martin Klinke
fonte
15

A grande diferença é que o JSefa traz é que ele pode serializar seus objetos java para arquivos CSV / XML / etc e pode desserializar de volta para objetos java. E é impulsionado por anotações que lhe dão muito controle sobre a saída.

JFileHelpers também parece interessante.

James Selvakumar
fonte
14

Não entendo por que você deseja fazer isso. Soa quase como codificação de culto à carga.

Converter um arquivo CSV em XML não adiciona nenhum valor. Seu programa já está lendo o arquivo CSV, portanto, argumentar que você precisa do XML não funciona.

Por outro lado, ler o arquivo CSV, fazer algo com os valores e, em seguida, serializar para XML faz sentido (bem, tanto quanto usar XML pode fazer sentido ...;)), mas você supostamente já teria um meio de serializando para XML.

Ryan Fox
fonte
14

Você pode fazer isso de maneira excepcionalmente fácil usando Groovy, e o código é muito legível.

Basicamente, a variável de texto será gravada contacts.xmlpara cada linha no contactData.csv, e a matriz de campos contém cada coluna.

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>"""
}
Abarax
fonte
7
CSV é simples, mas geralmente nunca é simples o suficiente para que uma divisão na vírgula seja suficiente.
Alan Krueger
12

Você pode usar XSLT . Pesquise no Google e você encontrará alguns exemplos, por exemplo, CSV para XML. Se você usar XSLT, poderá converter o XML para o formato que desejar.

Simmo
fonte
8

Há também uma boa biblioteca ServingXML de Daniel Parker, que é capaz de converter quase qualquer formato de texto simples para XML e vice-versa.

O exemplo para o seu caso pode ser encontrado aqui : Ele usa o título do campo no arquivo CSV como o nome do elemento XML.

Lukáš Rampa
fonte
7

Não há nada que eu conheça que possa fazer isso sem que você, pelo menos, escreva um pouco de código ... Você precisará de 2 bibliotecas separadas:

  • Um framework CSV Parser
  • Uma estrutura de serialização XML

O analisador CSV que eu recomendaria (a menos que você queira se divertir um pouco para escrever seu próprio analisador CSV) é o OpenCSV (um projeto SourceForge para análise de dados CSV)

O XML Serialization Framework deve ser algo que pode ser escalonado caso você queira transformar um arquivo CSV grande (ou enorme) em XML: Minha recomendação é o Sun Java Streaming XML Parser Framework (veja aqui ), que permite pull-parsing E serialização.

Claude Houle
fonte
7

Até onde eu sei, não há uma biblioteca pronta para fazer isso para você, mas a produção de uma ferramenta capaz de traduzir de CSV para XML deve exigir apenas que você escreva um analisador CSV bruto e conecte JDOM (ou sua biblioteca XML de Java de escolha) com algum código de cola.

Matt
fonte
4

A família de processadores Jackson tem back-ends para vários formatos de dados, não apenas JSON. Isso inclui back-ends XML ( https://github.com/FasterXML/jackson-dataformat-xml ) e CSV ( https://github.com/FasterXML/jackson-dataformat-csv/ ).

A conversão dependeria da leitura de entrada com back-end CSV e da escrita usando back-end XML. Isso é mais fácil de fazer se você tiver (ou puder definir) um POJO para entradas por linha (CSV). Este não é um requisito estrito, pois o conteúdo do CSV também pode ser lido "sem tipo" (uma sequência de Stringmatrizes), mas requer um pouco mais de trabalho na saída XML.

Para o lado XML, você precisaria de um objeto raiz do wrapper para conter a matriz ou Listde objetos para serializar.

StaxMan
fonte
3

Eu tive o mesmo problema e precisava de um aplicativo para converter um arquivo CSV em um arquivo XML para um de meus projetos, mas não encontrei nada gratuito e bom o suficiente na rede, então codifiquei meu próprio aplicativo Java Swing CSVtoXML.

Está disponível no meu site AQUI . Espero que ajude você.

Se não, você pode facilmente codificar o seu próprio código como eu fiz; O código-fonte está dentro do arquivo jar, portanto, modifique-o conforme necessário, se ele não atender aos seus requisitos.

Ibrabel
fonte
3

Isso pode ser uma solução muito básica ou limitada, mas você não poderia fazer um String.split()em cada linha do arquivo, lembrando a matriz de resultado da primeira linha para gerar o XML, e apenas cuspir os dados da matriz de cada linha com o XML adequado elementos preenchendo cada iteração de um loop?

saint_groceon
fonte
2
Não se o seu arquivo CSV contiver vírgulas entre aspas nos dados, o que é bastante comum.
Alan Krueger