¿Java lib o aplicación para convertir CSV a archivo XML? [cerrado]

114

¿Existe una aplicación o biblioteca en Java que me permita convertir un CSVarchivo de datos en un XMLarchivo?

Las XMLetiquetas se proporcionarían posiblemente a través de la primera fila que contiene encabezados de columna.

A Salim
fuente
47
Parece que esta es la primera pregunta con la etiqueta de Java en SO.
Paul Vargas
8
@Paul No solo eso, ¡también es 123!
bjb568
1
@Tommy stackoverflow.com/q/123
bjb568
1
@ bjb568 Oh. jaja
4
No es de extrañar que la primera publicación de java en SO se cerrara por estar fuera de tema: D
Sir. Hedgehog

Respuestas:

66

Quizás esto pueda ayudar: JSefa

Puede leer el archivo CSV con esta herramienta y serializarlo en XML.

svrist
fuente
47

Como los demás anteriores, no conozco ninguna forma de un solo paso para hacerlo, pero si está listo para usar bibliotecas externas muy simples, sugeriría:

OpenCsv para analizar CSV (pequeño, simple, confiable y fácil de usar)

Xstream para analizar / serializar XML (muy, muy fácil de usar y creando xml completamente legible para humanos)

Usando los mismos datos de muestra que arriba, el código se vería así:

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

Produciendo el siguiente resultado: (Xstream permite un ajuste muy fino del resultado ...)

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

Sé que solicitó Java, pero me parece una tarea muy adecuada para un lenguaje de secuencias de comandos. Aquí hay una solución rápida (muy simple) escrita en 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])
            }
        }
    }
}

Escribe el siguiente XML en 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>

Sin embargo, el código hace un análisis muy simple (sin tener en cuenta las comillas entre comillas o escapadas) y no tiene en cuenta la posible ausencia de datos.

Anthony Calambre
fuente
Por lo tanto, podría llamar a una biblioteca CSV para realizar el análisis y luego usar el generador de marcado. Tal vez puedas editar tu respuesta para mostrar esto.
Peter Kelley
18

Tengo un marco de código abierto para trabajar con archivos CSV y planos en general. Quizás valga la pena mirar: JFileHelpers .

Con ese kit de herramientas, puede escribir código usando beans, como:

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

y luego simplemente analice sus archivos de texto usando:

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

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

Y tendrás una colección de objetos analizados.

¡Espero que ayude!

Kolrie
fuente
+1 para el uso de anotaciones. Desafortunadamente, a partir de hoy, parece que el proyecto no tiene ninguna versión nueva desde 2009-08-11 ...
Stephan
Sí, no tuve tiempo de continuar con el desarrollo desde entonces, pero es muy estable.
Kolrie
17

Esta solución no necesita bibliotecas CSV o XML y, lo sé, no maneja caracteres ilegales ni problemas de codificación, pero es posible que también le interese, siempre que su entrada CSV no rompa las reglas mencionadas anteriormente.

Atención: No debe usar este código a menos que sepa lo que hace o no tenga la oportunidad de usar una biblioteca adicional (posible en algunos proyectos burocráticos) ... Use un StringBuffer para entornos de ejecución más antiguos ...

Así que, aquí vamos:

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

La entrada test.csv (robada de otra respuesta en esta página):

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

La salida resultante:

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

La gran diferencia es que trae JSefa es que puede serializar sus objetos java a archivos CSV / XML / etc y puede deserializar de nuevo a objetos java. Y está impulsado por anotaciones que le brindan mucho control sobre la salida.

JFileHelpers también parece interesante.

James Selvakumar
fuente
14

No entiendo por qué querrías hacer esto. Suena casi como una codificación de culto de carga.

La conversión de un archivo CSV a XML no agrega ningún valor. Su programa ya está leyendo el archivo CSV, por lo que argumentar que necesita XML no funciona.

Por otro lado, leer el archivo CSV, hacer algo con los valores y luego serializar a XML tiene sentido (bueno, tanto como usar XML puede tener sentido ...;)) pero supuestamente ya tendrías un medio de serializando a XML.

Ryan Fox
fuente
14

Puede hacer esto de manera excepcionalmente fácil usando Groovy, y el código es muy legible.

Básicamente, la variable de texto se escribirá contacts.xmlpara cada línea en el contactData.csv, y la matriz de campos contiene cada columna.

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
fuente
7
CSV es simple, pero generalmente nunca es lo suficientemente simple como para que una división por coma sea suficiente.
Alan Krueger
12

Podrías usar XSLT . Búscalo en Google y encontrarás algunos ejemplos, por ejemplo, CSV a XML. Si usas XSLT , puedes convertir el XML al formato que desees.

Simmo
fuente
8

También hay una buena biblioteca ServingXML de Daniel Parker, que puede convertir casi cualquier formato de texto plano a XML y viceversa.

El ejemplo de su caso se puede encontrar aquí : Utiliza el encabezado del campo en el archivo CSV como el nombre del elemento XML.

Lukáš Rampa
fuente
7

No hay nada que sepa que pueda hacer esto sin que al menos escriba un poco de código ... Necesitará 2 bibliotecas separadas:

  • Un marco de analizador CSV
  • Un marco de serialización XML

El analizador CSV que recomendaría (a menos que quiera divertirse un poco escribiendo su propio analizador CSV) es OpenCSV (un proyecto de SourceForge para analizar datos CSV)

XML Serialization Framework debe ser algo que pueda escalar en caso de que desee transformar un archivo CSV grande (o enorme) a XML: Mi recomendación es Sun Java Streaming XML Parser Framework (ver aquí ) que permite el análisis de extracción Y la serialización.

Claude Houle
fuente
7

Hasta donde yo sé, no existe una biblioteca lista para hacer esto por usted, pero producir una herramienta capaz de traducir de CSV a XML solo debería requerir que escriba un analizador CSV crudo y conecte JDOM (o su biblioteca XML Java de elección) con algún código de pegamento.

Mate
fuente
4

La familia de procesadores Jackson tiene backends para múltiples formatos de datos, no solo JSON. Esto incluye backends XML ( https://github.com/FasterXML/jackson-dataformat-xml ) y CSV ( https://github.com/FasterXML/jackson-dataformat-csv/ ).

La conversión se basaría en leer la entrada con el backend CSV, escribir usando el backend XML. Esto es más fácil de hacer si tiene (o puede definir) un POJO para entradas por fila (CSV). Este no es un requisito estricto, ya que el contenido de CSV también se puede leer "sin tipo" (una secuencia de Stringmatrices), pero requiere un poco más de trabajo en la salida XML.

Para el lado XML, necesitaría un objeto raíz contenedor para contener una matriz o Listde objetos para serializar.

StaxMan
fuente
3

Tuve el mismo problema y necesitaba una aplicación para convertir un archivo CSV en un archivo XML para uno de mis proyectos, pero no encontré nada gratis y lo suficientemente bueno en la red, así que codifiqué mi propia aplicación Java Swing CSVtoXML.

Está disponible en mi sitio web AQUÍ . Espero que te ayude.

Si no es así, puede codificar fácilmente el suyo como lo hice yo; El código fuente está dentro del archivo jar, así que modifíquelo como necesite si no cumple con sus requisitos.

Ibrabel
fuente
3

Esto puede ser una solución demasiado básica o limitada, pero ¿no podría hacer un String.split()en cada línea del archivo, recordando la matriz de resultados de la primera línea para generar el XML, y simplemente escupir los datos de la matriz de cada línea con el XML adecuado? elementos que rellenan cada iteración de un bucle?

saint_groceon
fuente
2
No si su archivo CSV alguna vez contiene comas entre comillas en los datos, lo cual es bastante común.
Alan Krueger