Java lib o app per convertire CSV in file XML? [chiuso]


114

Esiste un'applicazione o una libreria esistente in Java che mi consentirà di convertire un CSVfile di dati in XMLfile?

I XMLtag verrebbero forniti forse attraverso la prima riga contenente le intestazioni di colonna.


47
Sembra che questa sia la prima domanda con il tag di Java in SO.
Paul Vargas

8
@Paul Non solo, è anche 123!
bjb568


1
@ bjb568 Oh. haha

4
Non c'è da stupirsi che il primo post in assoluto per java in SO sia stato chiuso come fuori tema: D
Sir. Riccio

Risposte:


66

Forse questo potrebbe aiutare: JSefa

Puoi leggere il file CSV con questo strumento e serializzarlo in XML.


47

Come gli altri sopra, non conosco alcun modo in un solo passaggio per farlo, ma se sei pronto per utilizzare librerie esterne molto semplici, ti suggerirei:

OpenCsv per l'analisi di CSV (piccolo, semplice, affidabile e facile da usare)

Xstream per analizzare / serializzare XML (molto molto facile da usare e creare xml completamente leggibile dall'uomo)

Utilizzando gli stessi dati di esempio come sopra, il codice sarebbe simile a:

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

Produrre il seguente risultato: (Xstream consente una regolazione molto precisa del risultato ...)

<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>

27

So che hai chiesto Java, ma questo mi sembra un compito adatto a un linguaggio di scripting. Ecco una soluzione rapida (molto semplice) scritta in 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])
            }
        }
    }
}

Scrive il seguente XML in 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>

Tuttavia, il codice esegue un'analisi molto semplice (senza tenere conto delle virgole tra virgolette o di escape) e non tiene conto di eventuali dati assenti.


Quindi potresti chiamare una libreria CSV per eseguire l'analisi e quindi utilizzare il generatore di markup. Forse potresti modificare la tua risposta per mostrarlo.
Peter Kelley

18

Ho un framework opensource per lavorare con CSV e file flat in generale. Forse vale la pena guardare: JFileHelpers .

Con quel toolkit puoi scrivere codice usando i bean, come:

@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 poi analizza i tuoi file di testo usando:

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

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

E avrai una raccolta di oggetti analizzati.

Spero che aiuti!


+1 per l'uso delle annotazioni. Sfortunatamente, ad oggi, sembra che il progetto non abbia nessuna nuova versione dal 2009-08-11 ...
Stephan

Sì, da allora non ho avuto il tempo di continuare con lo sviluppo, ma è molto stabile.
kolrie

17

Questa soluzione non necessita di alcuna libreria CSV o XML e, lo so, non gestisce caratteri illegali e problemi di codifica, ma potrebbe interessarti anche tu, a condizione che il tuo input CSV non infranga le regole sopra menzionate.

Attenzione: non dovresti usare questo codice a meno che tu non sappia cosa fai o non hai la possibilità di usare un'ulteriore libreria (possibile in alcuni progetti burocratici) ... Usa uno StringBuffer per vecchi ambienti runtime ...

Quindi eccoci qui:

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

L'input test.csv (rubato da un'altra risposta in questa pagina):

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

L'output risultante:

<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>

15

La grande differenza è che JSefa introduce è che può serializzare i tuoi oggetti java in file CSV / XML / etc e può deserializzare di nuovo in oggetti java. Ed è guidato da annotazioni che ti danno molto controllo sull'output.

Anche JFileHelpers sembra interessante.


14

Non capisco perché vorresti farlo. Sembra quasi una codifica del culto del carico.

La conversione di un file CSV in XML non aggiunge alcun valore. Il tuo programma sta già leggendo il file CSV, quindi sostenere che hai bisogno di XML non funziona.

D'altra parte, leggere il file CSV, fare qualcosa con i valori e quindi serializzare in XML ha senso (beh, tanto quanto l'uso di XML può avere senso ...;)) ma presumibilmente avresti già un mezzo per serializzazione in XML.


14

Puoi farlo in modo eccezionalmente facile usando Groovy e il codice è molto leggibile.

Fondamentalmente, la variabile di testo verrà scritta contacts.xmlper ogni riga del contactData.csv, e l'array dei campi contiene ogni colonna.

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 è semplice, ma generalmente non è mai abbastanza semplice da essere sufficiente una divisione sulla virgola.
Alan Krueger

12

Potresti usare XSLT . Cercalo su Google e troverai alcuni esempi, ad esempio da CSV a XML. Se usi XSLT puoi convertire l'XML in qualsiasi formato tu voglia.


8

C'è anche una buona libreria ServingXML di Daniel Parker, che è in grado di convertire quasi tutti i formati di testo normale in XML e viceversa .

L'esempio per il tuo caso può essere trovato qui : Utilizza l'intestazione del campo nel file CSV come nome dell'elemento XML.


7

Non c'è niente che io sappia che possa farlo senza che tu scriva almeno un po 'di codice ... Avrai bisogno di 2 librerie separate:

  • Un framework di analisi CSV
  • Un framework di serializzazione XML

Il parser CSV che consiglierei (a meno che tu non voglia divertirti un po 'a scrivere il tuo parser CSV) è OpenCSV (A SourceForge Project for parsing CSV Data)

Il framework di serializzazione XML dovrebbe essere qualcosa che può scalare nel caso in cui si desideri trasformare file CSV di grandi dimensioni (o enormi) in XML: la mia raccomandazione è il Sun Java Streaming XML Parser Framework (vedere qui ) che consente la serializzazione E di pull-parsing.


7

Per quanto ne so, non esiste una libreria già pronta per farlo per te, ma la produzione di uno strumento in grado di tradurre da CSV a XML dovrebbe richiedere solo di scrivere un parser CSV grezzo e collegare JDOM (o la tua libreria Java XML di scelta) con un po 'di codice colla.


4

La famiglia di processori Jackson ha backend per più formati di dati, non solo JSON. Ciò include sia i backend XML ( https://github.com/FasterXML/jackson-dataformat-xml ) che CSV ( https://github.com/FasterXML/jackson-dataformat-csv/ ).

La conversione si baserebbe sulla lettura dell'input con il backend CSV, scrivere utilizzando il backend XML. Questo è più facile da fare se hai (o puoi definire) un POJO per voci per riga (CSV). Questo non è un requisito rigoroso, poiché anche i contenuti di CSV possono essere letti "non tipizzati" (una sequenza diString array), ma richiede un po 'più di lavoro sull'output XML.

Per il lato XML, è necessario un oggetto root wrapper per contenere un array o Listdi oggetti da serializzare.


3

Ho avuto lo stesso problema e avevo bisogno di un'applicazione per convertire un file CSV in un file XML per uno dei miei progetti, ma non ho trovato nulla di libero e abbastanza buono in rete, quindi ho codificato la mia applicazione Java Swing CSVtoXML.

È disponibile dal mio sito web QUI . Spero che ti possa aiutare.

In caso contrario, puoi facilmente codificare il tuo come ho fatto io; Il codice sorgente si trova all'interno del file jar, quindi modificalo come necessario se non soddisfa i tuoi requisiti.



3

Potrebbe essere una soluzione troppo semplice o limitata, ma non potresti fare un String.split()su ogni riga del file, ricordando l'array dei risultati della prima riga per generare l'XML, e semplicemente sputare i dati dell'array di ogni riga con l'XML appropriato elementi che riempiono ogni iterazione di un ciclo?


2
Non se il tuo file CSV contiene mai virgolette nei dati, il che è abbastanza comune.
Alan Krueger
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.