Biblioteka Java lub aplikacja do konwersji CSV do pliku XML? [Zamknięte]

114

Czy istnieje aplikacja lub biblioteka w Javie, która pozwoli mi przekonwertować CSVplik danych na XMLplik?

Te XMLznaczniki będą dostarczane przez ewentualnie pierwszy rząd zawierający nagłówki kolumn.

Salim
źródło
47
Wygląda na to, że jest to pierwsze pytanie z tagiem Java w SO.
Paul Vargas
8
@Paul Nie tylko to, to także 123!
bjb568
1
@Tommy stackoverflow.com/q/123
bjb568
1
@ bjb568 Oh. haha
4
Nic dziwnego, że pierwszy w historii post dla javy w SO został zamknięty jako nie na temat: D
Sir. Jeż

Odpowiedzi:

66

Może to pomoże: JSefa

Możesz odczytać plik CSV za pomocą tego narzędzia i serializować go do XML.

svrist
źródło
47

Podobnie jak inni powyżej, nie znam żadnego jednostopniowego sposobu, aby to zrobić, ale jeśli jesteś gotowy do korzystania z bardzo prostych bibliotek zewnętrznych, proponuję:

OpenCsv do parsowania CSV (mały, prosty, niezawodny i łatwy w użyciu)

Xstream do analizowania / serializacji XML (bardzo, bardzo łatwy w użyciu i tworzenia w pełni czytelnego dla człowieka xml)

Korzystając z tych samych przykładowych danych co powyżej, kod wyglądałby następująco:

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

Uzyskanie następującego wyniku: (Xstream umożliwia bardzo dokładne dostrojenie wyniku ...)

<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
źródło
27

Wiem, że prosiłeś o Javę, ale wydaje mi się to zadanie dobrze dopasowane do języka skryptowego. Oto szybkie (bardzo proste) rozwiązanie napisane w 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])
            }
        }
    }
}

Zapisuje następujący kod XML na 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>

Jednak kod wykonuje bardzo prostą analizę (bez uwzględnienia cudzysłowów lub przecinków) i nie uwzględnia ewentualnych braków danych.

Anthony Cramp
źródło
Możesz więc wywołać bibliotekę CSV, aby przeprowadzić analizę, a następnie użyć konstruktora znaczników. Może mógłbyś zmienić swoją odpowiedź, aby to pokazać.
Peter Kelley,
18

Mam otwarte środowisko do pracy z CSV i ogólnie plikami płaskimi. Może warto zajrzeć : JFileHelpers .

Za pomocą tego zestawu narzędzi możesz pisać kod za pomocą fasoli, takich jak:

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

a następnie po prostu przeanalizuj pliki tekstowe za pomocą:

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

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

Będziesz mieć kolekcję przeanalizowanych obiektów.

Mam nadzieję, że to pomoże!

kolrie
źródło
+1 za korzystanie z adnotacji. Niestety, na dzień dzisiejszy wydaje się, że projekt nie ma żadnej nowej wersji od 2009-08-11 ...
Stephan
Tak, od tamtej pory nie miałem czasu, aby kontynuować rozwój, ale jest bardzo stabilny.
kolrie
17

To rozwiązanie nie wymaga żadnych bibliotek CSV ani XML i wiem, że nie radzi sobie z żadnymi niedozwolonymi znakami i problemami z kodowaniem, ale może Cię również zainteresować, pod warunkiem, że twoje wejście CSV nie łamie wyżej wymienionych zasad.

Uwaga: nie powinieneś używać tego kodu, chyba że wiesz, co robisz lub nie masz szansy użyć dalszej biblioteki (możliwe w niektórych projektach biurokratycznych) ... Użyj StringBuffer dla starszych środowisk wykonawczych ...

Więc zaczynamy:

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

Plik wejściowy test.csv (skradziony z innej odpowiedzi na tej stronie):

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

Wynikowy wynik:

<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
źródło
15

Największą różnicą jest to, że JSefa umożliwia serializację obiektów java do plików CSV / XML / etc i może deserializować z powrotem do obiektów java. Jest napędzany przez adnotacje, które dają dużą kontrolę nad wynikami.

Ciekawie wygląda również JFileHelpers.

James Selvakumar
źródło
14

Nie rozumiem, dlaczego chcesz to zrobić. Brzmi prawie jak kultowe kodowanie cargo.

Konwersja pliku CSV na XML nie dodaje żadnej wartości. Twój program już czyta plik CSV, więc twierdzenie, że potrzebujesz XML, nie działa.

Z drugiej strony, odczytanie pliku CSV, zrobienie czegoś z wartościami, a następnie serializacja do XML ma sens (no cóż, użycie XML może mieć sens ...;)), ale podobno masz już środki na serializacja do XML.

Ryan Fox
źródło
14

Możesz to zrobić wyjątkowo łatwo za pomocą Groovy, a kod jest bardzo czytelny.

Zasadniczo zmienna tekstowa zostanie zapisana contacts.xmlw każdym wierszu w contactData.csv, a tablica pól zawiera każdą kolumnę.

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
źródło
7
CSV jest prosty, ale generalnie nigdy nie jest na tyle prosty, aby wystarczył podział na przecinek.
Alan Krueger,
12

Możesz użyć XSLT . Wygoogluj, a znajdziesz kilka przykładów, np. CSV na XML. Jeśli używasz XSLT , możesz następnie przekonwertować XML na dowolny format.

Simmo
źródło
8

Jest też dobra biblioteka ServingXML autorstwa Daniela Parkera, która jest w stanie przekonwertować prawie każdy format zwykłego tekstu na XML iz powrotem.

Przykład dla twojego przypadku można znaleźć tutaj : Używa nagłówka pola w pliku CSV jako nazwy elementu XML.

Lukáš Rampa
źródło
7

Nie wiem nic, co mogłoby to zrobić bez ciebie przynajmniej napisania trochę kodu ... Będziesz potrzebował 2 oddzielnych bibliotek:

  • Struktura parsera CSV
  • Struktura serializacji XML

Parser CSV, który poleciłbym (chyba że chcesz się trochę zabawić, pisząc własny parser CSV) to OpenCSV (projekt SourceForge do analizowania danych CSV)

Struktura serializacji XML powinna być czymś, co można skalować w przypadku, gdy chcesz przekształcić duży (lub ogromny) plik CSV do formatu XML: Moją rekomendacją jest struktura parsera strumieniowego XML strumieniowania XML firmy Sun (patrz tutaj ), która umożliwia analizowanie w trybie pull ORAZ serializację.

Claude Houle
źródło
7

O ile wiem, nie ma gotowej biblioteki, która mogłaby to zrobić za Ciebie, ale stworzenie narzędzia zdolnego do tłumaczenia z CSV na XML powinno wymagać jedynie napisania prostego parsera CSV i podłączenia JDOM (lub biblioteki XML Java w wybór) z kodem kleju.

Matt
źródło
4

Rodzina procesorów Jackson ma zaplecze obsługujące wiele formatów danych, nie tylko JSON. Obejmuje to zarówno backendy XML ( https://github.com/FasterXML/jackson-dataformat-xml ), jak i CSV ( https://github.com/FasterXML/jackson-dataformat-csv/ ).

Konwersja polegałaby na czytaniu danych wejściowych za pomocą zaplecza CSV, pisaniu przy użyciu zaplecza XML. Jest to najłatwiejsze do zrobienia, jeśli masz (lub możesz zdefiniować) POJO dla wpisów na wiersz (CSV). Nie jest to wymaganie ścisłe, ponieważ treść z CSV może być również odczytywana jako „bez typu” (sekwencja Stringtablic), ale wymaga nieco więcej pracy na wyjściu XML.

Po stronie XML potrzebujesz obiektu głównego opakowania, aby zawierał tablicę lub Listobiekty do serializacji.

StaxMan
źródło
3

Miałem ten sam problem i potrzebowałem aplikacji do konwersji pliku CSV na plik XML dla jednego z moich projektów, ale nie znalazłem w sieci nic wolnego i wystarczająco dobrego, więc zakodowałem własną aplikację Java Swing CSVtoXML.

Jest dostępny na mojej stronie TUTAJ . Mam nadzieję, że to ci pomoże.

Jeśli nie, możesz łatwo zaprogramować własne, tak jak ja; Kod źródłowy znajduje się w pliku jar, więc zmodyfikuj go według potrzeb, jeśli nie spełnia Twoich wymagań.

Ibrabel
źródło
3

Może to być zbyt proste lub ograniczone rozwiązanie, ale nie mógłbyś zrobić dla String.split()każdego wiersza pliku, pamiętając tablicę wyników pierwszego wiersza w celu wygenerowania XML i po prostu wypluć dane tablicowe każdego wiersza odpowiednim XML elementy wypełniające każdą iterację pętli?

saint_groceon
źródło
2
Nie, jeśli plik CSV kiedykolwiek zawiera dane w cudzysłowach, co jest dość powszechne.
Alan Krueger,