Czy istnieje aplikacja lub biblioteka w Javie, która pozwoli mi przekonwertować CSV
plik danych na XML
plik?
Te XML
znaczniki będą dostarczane przez ewentualnie pierwszy rząd zawierający nagłówki kolumn.
Czy istnieje aplikacja lub biblioteka w Javie, która pozwoli mi przekonwertować CSV
plik danych na XML
plik?
Te XML
znaczniki będą dostarczane przez ewentualnie pierwszy rząd zawierający nagłówki kolumn.
Odpowiedzi:
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>
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.
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!
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>
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.
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.
Możesz to zrobić wyjątkowo łatwo za pomocą Groovy, a kod jest bardzo czytelny.
Zasadniczo zmienna tekstowa zostanie zapisana contacts.xml
w 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>"""
}
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.
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.
Nie wiem nic, co mogłoby to zrobić bez ciebie przynajmniej napisania trochę kodu ... Będziesz potrzebował 2 oddzielnych bibliotek:
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ę.
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 String
tablic), ale wymaga nieco więcej pracy na wyjściu XML.
Po stronie XML potrzebujesz obiektu głównego opakowania, aby zawierał tablicę lub List
obiekty do serializacji.
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ń.
W przypadku części CSV możesz użyć mojej małej biblioteki open source
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?