Esiste un'applicazione o una libreria esistente in Java che mi consentirà di convertire un CSV
file di dati in XML
file?
I XML
tag verrebbero forniti forse attraverso la prima riga contenente le intestazioni di colonna.
Esiste un'applicazione o una libreria esistente in Java che mi consentirà di convertire un CSV
file di dati in XML
file?
I XML
tag verrebbero forniti forse attraverso la prima riga contenente le intestazioni di colonna.
Risposte:
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>
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.
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!
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>
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.
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.
Puoi farlo in modo eccezionalmente facile usando Groovy e il codice è molto leggibile.
Fondamentalmente, la variabile di testo verrà scritta contacts.xml
per 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>"""
}
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.
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.
Non c'è niente che io sappia che possa farlo senza che tu scriva almeno un po 'di codice ... Avrai bisogno di 2 librerie separate:
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.
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 List
di oggetti da serializzare.
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.
Per la parte CSV, puoi usare la mia piccola libreria open source
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?