Java lib oder App zum Konvertieren von CSV in XML-Datei? [geschlossen]

113

Gibt es eine vorhandene Anwendung oder Bibliothek in Java, mit der ich eine Datendatei in eine CSVDatei konvertieren XMLkann?

Die XMLTags würden möglicherweise durch die erste Zeile bereitgestellt, die Spaltenüberschriften enthält.

Ein Salim
quelle
47
Es scheint, dass dies die erste Frage mit dem Tag von Java in SO ist.
Paul Vargas
8
@ Paul Nicht nur das, es ist auch 123!
bjb568
1
@ Tommy Stackoverflow.com/q/123
bjb568
1
@ bjb568 Oh. haha
4
Kein Wunder, dass der erste Beitrag für Java in SO als Off-Topic geschlossen wurde: D
Sir. Igel

Antworten:

66

Vielleicht könnte das helfen: JSefa

Mit diesem Tool können Sie CSV-Dateien lesen und in XML serialisieren.

svrist
quelle
47

Wie die anderen oben, kenne ich keinen Ein-Schritt-Weg, um dies zu tun, aber wenn Sie bereit sind, sehr einfache externe Bibliotheken zu verwenden, würde ich vorschlagen:

OpenCsv zum Parsen von CSV (klein, einfach, zuverlässig und benutzerfreundlich )

Xstream zum Parsen / Serialisieren von XML (sehr, sehr einfach zu verwenden und vollständig lesbare XML- Dateien zu erstellen)

Unter Verwendung der gleichen Beispieldaten wie oben würde der Code folgendermaßen aussehen:

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

Das folgende Ergebnis wird erzeugt: (Xstream ermöglicht eine sehr feine Abstimmung des Ergebnisses ...)

<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.
quelle
27

Ich weiß, dass Sie nach Java gefragt haben, aber das scheint mir eine Aufgabe zu sein, die für eine Skriptsprache gut geeignet ist. Hier ist eine schnelle (sehr einfache) Lösung, die in Groovy geschrieben wurde.

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])
            }
        }
    }
}

Schreibt das folgende 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>

Der Code führt jedoch eine sehr einfache Analyse durch (ohne Anführungszeichen oder Kommas) und berücksichtigt möglicherweise keine fehlenden Daten.

Anthony Cramp
quelle
Sie können also eine CSV-Bibliothek aufrufen, um die Analyse durchzuführen, und dann den Markup-Builder verwenden. Vielleicht könnten Sie Ihre Antwort bearbeiten, um dies zu zeigen.
Peter Kelley
18

Ich habe ein OpenSource-Framework für die Arbeit mit CSV und Flatfiles im Allgemeinen. Vielleicht lohnt es sich zu schauen: JFileHelpers .

Mit diesem Toolkit können Sie Code mit Beans schreiben, wie zum Beispiel:

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

und analysieren Sie dann einfach Ihre Textdateien mit:

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

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

Und Sie haben eine Sammlung von analysierten Objekten.

Hoffentlich hilft das!

kolrie
quelle
+1 für die Verwendung von Anmerkungen. Leider scheint es bis heute, dass das Projekt seit dem 11.08.2009 keine neue Version mehr hat ...
Stephan
Ja, ich hatte seitdem keine Zeit mehr, mit der Entwicklung fortzufahren, aber es ist sehr stabil.
Kolrie
17

Diese Lösung benötigt keine CSV- oder XML-Bibliotheken und behandelt, wie ich weiß, keine illegalen Zeichen und Codierungsprobleme. Sie könnten jedoch auch daran interessiert sein, vorausgesetzt, Ihre CSV-Eingabe verstößt nicht gegen die oben genannten Regeln.

Beachtung: Sie sollten diesen Code nur verwenden, wenn Sie wissen, was Sie tun, oder wenn Sie nicht die Möglichkeit haben, eine weitere Bibliothek zu verwenden (in einigen bürokratischen Projekten möglich) ... Verwenden Sie einen StringBuffer für ältere Laufzeitumgebungen ...

Auf geht's:

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

Die Eingabe test.csv (gestohlen aus einer anderen Antwort auf dieser Seite):

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

Die resultierende Ausgabe:

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

Der große Unterschied, den JSefa einbringt, besteht darin, dass es Ihre Java-Objekte in CSV / XML / etc-Dateien serialisieren und wieder in Java-Objekte deserialisieren kann. Und es wird von Anmerkungen gesteuert, die Ihnen viel Kontrolle über die Ausgabe geben.

JFileHelpers sieht auch interessant aus.

James Selvakumar
quelle
14

Ich verstehe nicht, warum Sie das tun möchten. Es klingt fast wie eine Frachtkultcodierung.

Das Konvertieren einer CSV-Datei in XML bringt keinen Mehrwert. Ihr Programm liest bereits die CSV-Datei, sodass die Argumentation, dass Sie XML benötigen, nicht funktioniert.

Auf der anderen Seite ist es sinnvoll , die CSV-Datei zu lesen, etwas mit den Werten zu tun und dann in XML zu serialisieren (so viel wie die Verwendung von XML sinnvoll sein kann ...;)), aber Sie hätten angeblich bereits ein Mittel dazu Serialisierung in XML.

Ryan Fox
quelle
14

Sie können dies außergewöhnlich einfach mit Groovy tun, und der Code ist sehr gut lesbar.

Grundsätzlich wird die Textvariable contacts.xmlfür jede Zeile im contactData.csvFeld geschrieben , und das Feldarray enthält jede Spalte.

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
quelle
7
CSV ist einfach, aber im Allgemeinen nie so einfach, dass eine Aufteilung des Kommas ausreicht.
Alan Krueger
12

Sie könnten XSLT verwenden . Google it und Sie werden einige Beispiele finden, z. B. CSV in XML. Wenn Sie XSLT verwenden , können Sie das XML in das gewünschte Format konvertieren.

Simmo
quelle
8

Es gibt auch eine gute Bibliothek ServingXML von Daniel Parker, die fast jedes Text-Format in XML und zurück konvertieren kann.

Das Beispiel für Ihren Fall finden Sie hier : Als XML-Elementname wird die Feldüberschrift in der CSV-Datei verwendet.

Lukáš Rampa
quelle
7

Es gibt nichts, von dem ich weiß, dass es dies tun kann, ohne dass Sie zumindest ein wenig Code schreiben ... Sie benötigen 2 separate Bibliotheken:

  • Ein CSV-Parser-Framework
  • Ein XML-Serialisierungsframework

Der CSV-Parser, den ich empfehlen würde (es sei denn, Sie möchten ein bisschen Spaß beim Schreiben Ihres eigenen CSV-Parsers haben), ist OpenCSV (ein SourceForge-Projekt zum Parsen von CSV-Daten).

Das XML-Serialisierungsframework sollte skalierbar sein, wenn Sie große (oder große) CSV-Dateien in XML umwandeln möchten: Meine Empfehlung ist das Sun Java Streaming XML-Parser-Framework (siehe hier ), das Pull-Parsing UND Serialisierung ermöglicht.

Claude Houle
quelle
7

Soweit ich weiß, gibt es keine vorgefertigte Bibliothek, die dies für Sie erledigt. Um jedoch ein Tool zu erstellen, mit dem von CSV nach XML übersetzt werden kann, müssen Sie lediglich einen groben CSV-Parser schreiben und JDOM (oder Ihre XML-Java-Bibliothek von) anschließen Wahl) mit etwas Klebercode.

Matt
quelle
4

Die Jackson-Prozessorfamilie verfügt über Backends für mehrere Datenformate, nicht nur für JSON. Dies umfasst sowohl XML- Backends ( https://github.com/FasterXML/jackson-dataformat-xml ) als auch CSV- Backends ( https://github.com/FasterXML/jackson-dataformat-csv/ ).

Die Konvertierung basiert auf dem Lesen von Eingaben mit CSV-Backend und dem Schreiben mit XML-Backend. Dies ist am einfachsten, wenn Sie ein POJO für CSV-Einträge (Per Row) haben (oder definieren können). Dies ist keine strikte Anforderung, da Inhalte aus CSV auch "untypisiert" gelesen werden können (eine Folge von StringArrays), aber etwas mehr Arbeit an der XML-Ausgabe erfordern.

Für die XML-Seite benötigen Sie ein Wrapper-Stammobjekt, das ein Array enthält, oder ListObjekte, die serialisiert werden sollen.

StaxMan
quelle
3

Ich hatte das gleiche Problem und brauchte eine Anwendung, um eine CSV-Datei für eines meiner Projekte in eine XML-Datei zu konvertieren, fand aber nichts Freies und Gutes im Netz, sodass ich meine eigene Java Swing CSVtoXML-Anwendung codierte.

Es ist auf meiner Website HIER verfügbar . Hoffe es wird dir helfen.

Wenn nicht, können Sie ganz einfach Ihre eigenen codieren, wie ich es getan habe. Der Quellcode befindet sich in der JAR-Datei. Ändern Sie ihn daher nach Bedarf, wenn er Ihre Anforderungen nicht erfüllt.

Ibrabel
quelle
3

Dies mag für eine Lösung zu einfach oder zu begrenzt sein, aber Sie können nicht String.split()in jeder Zeile der Datei ein Ergebnisarray der ersten Zeile speichern, um das XML zu generieren, und einfach die Array-Daten jeder Zeile mit dem richtigen XML ausspucken Elemente, die jede Iteration einer Schleife auffüllen?

saint_groceon
quelle
2
Nicht, wenn Ihre CSV-Datei jemals Kommas in Anführungszeichen in Daten enthält, was ziemlich häufig vorkommt.
Alan Krueger