Java lib ou application pour convertir CSV en fichier XML? [fermé]

114

Existe-t-il une application ou une bibliothèque en Java qui me permettra de convertir un CSVfichier de données en XMLfichier?

Les XMLbalises seraient fournies via éventuellement la première ligne contenant les en-têtes de colonne.

Un Salim
la source
47
Il semble que ce soit la première question avec l'étiquette de Java dans SO.
Paul Vargas
8
@Paul Non seulement cela, c'est aussi 123!
bjb568
1
@Tommy stackoverflow.com/q/123
bjb568
1
@ bjb568 Oh. haha
4
Pas étonnant que le tout premier post pour java dans SO ait été fermé comme hors sujet: D
Monsieur. Hérisson

Réponses:

66

Peut-être que cela pourrait aider: JSefa

Vous pouvez lire le fichier CSV avec cet outil et le sérialiser au format XML.

svrist
la source
47

Comme les autres ci-dessus, je ne connais pas de moyen en une seule étape de le faire, mais si vous êtes prêt à utiliser des bibliothèques externes très simples, je suggérerais:

OpenCsv pour l'analyse CSV (petit, simple, fiable et facile à utiliser)

Xstream pour analyser / sérialiser XML (très très facile à utiliser, et créer un XML entièrement lisible par l'homme)

En utilisant les mêmes exemples de données que ci-dessus, le code ressemblerait à ceci:

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

Produisant le résultat suivant: (Xstream permet un réglage très fin du résultat ...)

<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
la source
27

Je sais que vous avez demandé Java, mais cela me semble être une tâche bien adaptée à un langage de script. Voici une solution rapide (très simple) écrite 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])
            }
        }
    }
}

Écrit le code XML suivant dans 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>

Cependant, le code effectue une analyse très simple (sans tenir compte des virgules entre guillemets ou échappées) et ne tient pas compte des éventuelles données absentes.

Anthony Cramp
la source
Vous pouvez donc appeler une bibliothèque CSV pour effectuer l'analyse, puis utiliser le générateur de balisage. Vous pourriez peut-être modifier votre réponse pour l'afficher.
Peter Kelley
18

J'ai un framework Open Source pour travailler avec CSV et les fichiers plats en général. Cela vaut peut-être la peine de regarder: JFileHelpers .

Avec cette boîte à outils, vous pouvez écrire du code en utilisant des beans, comme:

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

puis analysez simplement vos fichiers texte en utilisant:

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

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

Et vous aurez une collection d'objets analysés.

J'espère que cela pourra aider!

Kolrie
la source
+1 pour l'utilisation des annotations. Malheureusement, à ce jour, il semble que le projet n'ait pas de nouvelle version depuis le 11/08/2009 ...
Stephan
Oui, je n'ai pas eu le temps de continuer le développement depuis, mais c'est très stable.
kolrie
17

Cette solution n'a pas besoin de bibliothèques CSV ou XML et, je sais, elle ne gère pas les caractères illégaux et les problèmes d'encodage, mais cela pourrait également vous intéresser, à condition que votre entrée CSV ne casse pas les règles mentionnées ci-dessus.

Attention: vous ne devez pas utiliser ce code à moins que vous ne sachiez ce que vous faites ou que vous n'ayez pas la possibilité d'utiliser une autre bibliothèque (possible dans certains projets bureaucratiques) ... Utilisez un StringBuffer pour les environnements d'exécution plus anciens ...

Alors on y va:

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

L'entrée test.csv (volée dans une autre réponse sur cette page):

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 sortie résultante:

<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
la source
15

La grande différence est que JSefa apporte, c'est qu'il peut sérialiser vos objets java en fichiers CSV / XML / etc et peut les désérialiser en objets java. Et il est alimenté par des annotations qui vous donnent beaucoup de contrôle sur la sortie.

JFileHelpers semble également intéressant.

James Selvakumar
la source
14

Je ne comprends pas pourquoi vous voudriez faire ça. Cela ressemble presque au codage culte du fret.

La conversion d'un fichier CSV en XML n'ajoute aucune valeur. Votre programme lit déjà le fichier CSV, donc prétendre que vous avez besoin de XML ne fonctionne pas.

D'un autre côté, lire le fichier CSV, faire quelque chose avec les valeurs, puis sérialiser en XML a du sens (enfin, autant utiliser XML peut avoir du sens ...;)) mais vous auriez supposément déjà un moyen de sérialisation vers XML.

Ryan Fox
la source
14

Vous pouvez le faire exceptionnellement facilement en utilisant Groovy, et le code est très lisible.

Fondamentalement, la variable de texte sera écrite contacts.xmlpour chaque ligne du contactData.csv, et le tableau de champs contient chaque colonne.

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
la source
7
CSV est simple, mais n'est généralement jamais assez simple pour qu'une séparation entre la virgule soit suffisante.
Alan Krueger
12

Vous pouvez utiliser XSLT . Google et vous trouverez quelques exemples, par exemple CSV en XML. Si vous utilisez XSLT, vous pouvez ensuite convertir le XML dans le format de votre choix.

Simmo
la source
8

Il existe également une bonne bibliothèque ServingXML de Daniel Parker, qui est capable de convertir presque tous les formats de texte brut en XML et inversement.

L'exemple pour votre cas peut être trouvé ici : Il utilise l'en-tête du champ dans le fichier CSV comme nom d'élément XML.

Lukáš Rampa
la source
7

Il n'y a rien à ma connaissance qui puisse faire cela sans que vous n'écriviez au moins un peu de code ... Vous aurez besoin de 2 bibliothèques séparées:

  • Un cadre d'analyse CSV
  • Un cadre de sérialisation XML

L'analyseur CSV que je recommanderais (à moins que vous ne souhaitiez vous amuser un peu à écrire votre propre analyseur CSV) est OpenCSV (Un projet SourceForge pour l'analyse des données CSV)

Le framework de sérialisation XML devrait être quelque chose qui peut évoluer au cas où vous voudriez transformer un fichier CSV volumineux (ou énorme) en XML: Ma recommandation est le Sun Java Streaming XML Parser Framework (voir ici ) qui permet l'analyse par extraction ET la sérialisation.

Claude Houle
la source
7

Autant que je sache, il n'y a pas de bibliothèque prête à l'emploi pour le faire pour vous, mais la production d'un outil capable de traduire de CSV en XML ne devrait vous obliger qu'à écrire un analyseur CSV brut et à connecter JDOM (ou votre bibliothèque XML Java de choix) avec du code de colle.

Mat
la source
4

La famille de processeurs Jackson a des backends pour plusieurs formats de données, pas seulement JSON. Cela inclut à la fois les backends XML ( https://github.com/FasterXML/jackson-dataformat-xml ) et CSV ( https://github.com/FasterXML/jackson-dataformat-csv/ ).

La conversion reposerait sur la lecture de l'entrée avec le backend CSV, l'écriture à l'aide du backend XML. C'est plus simple à faire si vous avez (ou pouvez définir) un POJO pour les entrées par ligne (CSV). Ce n'est pas une exigence stricte, car le contenu de CSV peut également être lu "non typé" (une séquence de Stringtableaux), mais nécessite un peu plus de travail sur la sortie XML.

Pour le côté XML, vous auriez besoin d'un objet racine wrapper pour contenir un tableau ou Listd'objets à sérialiser.

StaxMan
la source
3

J'ai eu le même problème et j'avais besoin d'une application pour convertir un fichier CSV en fichier XML pour l'un de mes projets, mais je n'ai rien trouvé de gratuit et d'assez bon sur le net, j'ai donc codé ma propre application Java Swing CSVtoXML.

Il est disponible sur mon site Web ICI . J'espère que cela vous aidera.

Sinon, vous pouvez facilement coder le vôtre comme je l'ai fait; Le code source est à l'intérieur du fichier jar, alors modifiez-le selon vos besoins s'il ne répond pas à vos besoins.

Ibrabel
la source
3

Cela peut être une solution trop basique ou limitée, mais vous ne pourriez pas faire un String.split()sur chaque ligne du fichier, en vous souvenant du tableau de résultats de la première ligne pour générer le XML, et simplement cracher les données du tableau de chaque ligne avec le XML approprié éléments remplissant chaque itération d'une boucle?

saint_groceon
la source
2
Pas si votre fichier CSV contient des virgules entre guillemets dans les données, ce qui est assez courant.
Alan Krueger