Java lib или приложение для преобразования CSV в файл XML? [закрыто]


114

Есть ли на Java существующее приложение или библиотека, которые позволят мне преобразовать CSVфайл данных в XMLфайл?

Эти XMLметки будут предоставлены через , возможно , первую строку , содержащую заголовки столбцов.


47
Похоже, это первый вопрос с тегом Java в SO.
Пол Варгас,

8
@Paul Не только это, это еще 123!
bjb568


1
@ bjb568 О. ха-ха

4
Неудивительно, что первый пост для java в SO был закрыт как не по теме: D
Сэр. Hedgehog

Ответы:


66

Возможно, это может помочь: JSefa

Вы можете прочитать CSV-файл с помощью этого инструмента и преобразовать его в XML.


47

Как и другие вышеупомянутые, я не знаю одношагового способа сделать это, но если вы готовы использовать очень простые внешние библиотеки, я бы предложил:

OpenCsv для разбора CSV (маленький, простой, надежный и простой в использовании)

Xstream для синтаксического анализа / сериализации XML (очень прост в использовании и создает полностью читаемый человеком XML)

Используя те же образцы данных, что и выше, код будет выглядеть так:

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

Получение следующего результата: (Xstream позволяет очень точно настроить результат ...)

<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

Я знаю, что вы просили Java, но мне кажется, что это задача, хорошо подходящая для языка сценариев. Вот быстрое (очень простое) решение, написанное на 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])
            }
        }
    }
}

Записывает следующий XML-код в стандартный вывод:

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

Однако код выполняет очень простой синтаксический анализ (без учета кавычек или экранированных запятых) и не учитывает возможные отсутствующие данные.


Таким образом, вы можете вызвать библиотеку CSV для анализа, а затем использовать конструктор разметки. Может быть, вы могли бы отредактировать свой ответ, чтобы показать это.
Питер Келли,

18

У меня есть платформа с открытым исходным кодом для работы с CSV и плоскими файлами в целом. Может стоит посмотреть: JFileHelpers .

С помощью этого набора инструментов вы можете писать код с использованием bean-компонентов, например:

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

а затем просто проанализируйте свои текстовые файлы, используя:

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

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

И у вас будет коллекция проанализированных объектов.

Надеюсь, это поможет!


+1 за использование аннотаций. К сожалению, на сегодняшний день похоже, что у проекта нет новой версии с 11 августа 2009 года ...
Стефан

Да, с тех пор у меня не было времени продолжать разработку, но она очень стабильна.
kolrie

17

Это решение не требует каких-либо библиотек CSV или XML, и, я знаю, оно не обрабатывает какие-либо недопустимые символы и проблемы с кодировкой, но оно может вас заинтересовать, при условии, что ваш ввод CSV не нарушает вышеупомянутые правила.

Внимание: вам не следует использовать этот код, если вы не знаете, что делаете, или если у вас нет возможности использовать дополнительную библиотеку (возможно в некоторых бюрократических проектах) ... Используйте StringBuffer для более старых сред выполнения ...

Итак, начнем:

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

Входной 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

Полученный результат:

<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

Большое различие заключается в том, что JSefa предоставляет возможность сериализовать ваши java-объекты в файлы CSV / XML / etc и может десериализовать их обратно в java-объекты. И это связано с аннотациями, которые дают вам полный контроль над выводом.

JFileHelpers тоже выглядит интересно.


14

Я не понимаю, зачем вам это нужно. Это звучит почти как кодирование культа карго.

Преобразование файла CSV в XML не добавляет никакой ценности. Ваша программа уже читает CSV-файл, поэтому аргументы в пользу того, что вам нужен XML, не работают.

С другой стороны, чтение файла CSV, делать что - то со значениями, а затем сериализации XML имеет смысл (ну, так же , как с помощью XML может иметь смысл ...;)) , но вы , мол , уже есть средства сериализация в XML.


14

Вы можете сделать это исключительно легко с помощью Groovy, а код легко читается.

Обычно текстовая переменная записывается contacts.xmlдля каждой строки в contactData.csv, а массив полей содержит каждый столбец.

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 прост, но, как правило, никогда не бывает достаточно простым, чтобы разделить запятую.
Алан Крюгер

12

Вы можете использовать XSLT . Погуглите, и вы найдете несколько примеров, например, CSV в XML. Если вы используете XSLT, вы можете преобразовать XML в любой формат, который вам нужен.


8

Также существует хорошая библиотека ServingXML от Дэниела Паркера, которая способна преобразовывать практически любой простой текстовый формат в XML и обратно.

Пример для вашего случая можно найти здесь : он использует заголовок поля в файле CSV в качестве имени элемента XML.


7

Я не знаю ничего, что могло бы сделать это без того, чтобы вы хотя бы написали немного кода ... Вам понадобятся 2 отдельные библиотеки:

  • Фреймворк парсера CSV
  • Платформа сериализации XML

Я бы порекомендовал парсер CSV (если вы не хотите немного повеселиться, чтобы написать свой собственный парсер CSV) - это OpenCSV (проект SourceForge для анализа данных CSV).

Платформа XML-сериализации должна быть чем-то, что может масштабироваться в случае, если вы хотите преобразовать большой (или огромный) CSV-файл в XML: Я рекомендую Sun Java Streaming XML Parser Framework (см. Здесь ), которая позволяет выполнять анализ методом извлечения и сериализацию.


7

Насколько я знаю, готовой библиотеки для этого не существует, но для создания инструмента, способного переводить из CSV в XML, вам потребуется всего лишь написать сырой анализатор CSV и подключить JDOM (или вашу XML-библиотеку Java из выбор) с некоторым кодом клея.


4

Семейство процессоров Jackson имеет серверные части для нескольких форматов данных, а не только для JSON. Сюда входят серверные части как XML ( https://github.com/FasterXML/jackson-dataformat-xml ), так и CSV ( https://github.com/FasterXML/jackson-dataformat-csv/ ).

Преобразование будет основываться на чтении ввода с помощью серверной части CSV, записи с использованием базы данных XML. Это проще всего сделать, если у вас есть (или вы можете определить) POJO для построчных записей (CSV). Это не строгое требование, так как контент из CSV также может считываться «нетипизированным» (последовательность Stringмассивов), но требует немного больше работы над выводом XML.

Для стороны XML вам потребуется корневой объект оболочки, содержащий массив или Listобъекты для сериализации.


3

У меня была та же проблема, и мне требовалось приложение для преобразования файла CSV в файл XML для одного из моих проектов, но я не нашел в сети ничего бесплатного и достаточно хорошего, поэтому я написал свое собственное приложение Java Swing CSVtoXML.

Он доступен на моем сайте ЗДЕСЬ . Надеюсь, это поможет вам.

Если нет, вы можете легко написать свой собственный код, как это сделал я; Исходный код находится внутри файла jar, поэтому измените его по своему усмотрению, если он не соответствует вашим требованиям.



3

Это может быть слишком простым или ограниченным решением, но не могли бы вы сделать для String.split()каждой строки файла, запомнив массив результатов первой строки для генерации XML, и просто выплюнуть данные массива каждой строки с правильным XML элементы, заполняющие каждую итерацию цикла?


2
Нет, если ваш файл CSV когда-либо содержит в данных кавычки, что довольно часто.
Алан Крюгер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.