web-dev-qa-db-fra.com

Convertir un fichier XML en fichier CSV en utilisant java

J'ai besoin d'aide pour comprendre les étapes nécessaires à la conversion d'un fichier XML en fichier CSV à l'aide de Java . Voici un exemple de fichier XML

<?xml version="1.0"?>
<Sites>
<Site id="101" name="NY-01" location="New York">
    <Hosts>
        <Host id="1001">
           <Host_Name>srv001001</Host_Name>
           <IP_address>10.1.2.3</IP_address>
           <OS>Windows</OS>
           <Load_avg_1min>1.3</Load_avg_1min>
           <Load_avg_5min>2.5</Load_avg_5min>
           <Load_avg_15min>1.2</Load_avg_15min>
        </Host>
        <Host id="1002">
           <Host_Name>srv001002</Host_Name>
           <IP_address>10.1.2.4</IP_address>
           <OS>Linux</OS>
           <Load_avg_1min>1.4</Load_avg_1min>
           <Load_avg_5min>2.5</Load_avg_5min>
           <Load_avg_15min>1.2</Load_avg_15min>
        </Host>
        <Host id="1003">
           <Host_Name>srv001003</Host_Name>
           <IP_address>10.1.2.5</IP_address>
           <OS>Linux</OS>
           <Load_avg_1min>3.3</Load_avg_1min>
           <Load_avg_5min>1.6</Load_avg_5min>
           <Load_avg_15min>1.8</Load_avg_15min>
        </Host>
        <Host id="1004">
           <Host_Name>srv001004</Host_Name>
           <IP_address>10.1.2.6</IP_address>
           <OS>Linux</OS>
           <Load_avg_1min>2.3</Load_avg_1min>
           <Load_avg_5min>4.5</Load_avg_5min>
           <Load_avg_15min>4.2</Load_avg_15min>
        </Host>     
    </Hosts>
</Site>
</Sites>

et voici le fichier CSV résultant.

site_id, site_name, site_location, Host_id, Host_name, ip_address, operative_system, load_avg_1min, load_avg_5min, load_avg_15min
101, NY-01, New York, 1001, srv001001, 10.1.2.3, Windows, 1.3, 2.5, 1.2
101, NY-01, New York, 1002, srv001002, 10.1.2.4, Linux, 1.4, 2.5, 1.2
101, NY-01, New York, 1003, srv001003, 10.1.2.5, Linux, 3.3, 1.6, 1.8
101, NY-01, New York, 1004, srv001004, 10.1.2.6, Linux, 2.3, 4.5, 4.2

Je pensais utiliser un analyseur DOM pour lire le fichier XML. Le problème que j’ai avec cela est que j’aurais besoin de spécifier des éléments spécifiques dans le code par nom, mais je veux qu’il puisse l’analyser sans le faire.

Existe-t-il des outils ou des bibliothèques en Java qui pourraient m'aider à atteindre cet objectif?.

Si j'ai un fichier XML de ce format ci-dessous et que je veux ajouter la valeur de InitgPty dans la même ligne que MSgId (Remarque: PlgPty est au niveau de balise suivant, de sorte qu'il affiche la valeur dans la rangée suivante).

<?xml version="1.0"?>
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>XYZ07/ABC</MsgId>
<NbOfTxs>100000</NbOfTxs>
<InitgPty>
<Nm>XYZ</Nm>
</InitgPty>
10
Emre801

voici un exemple de travail, data.xml a vos données:

import Java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

class Xml2Csv {

    public static void main(String args[]) throws Exception {
        File stylesheet = new File("src/main/resources/style.xsl");
        File xmlSource = new File("src/main/resources/data.xml");

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(xmlSource);

        StreamSource stylesource = new StreamSource(stylesheet);
        Transformer transformer = TransformerFactory.newInstance()
                .newTransformer(stylesource);
        Source source = new DOMSource(document);
        Result outputTarget = new StreamResult(new File("/tmp/x.csv"));
        transformer.transform(source, outputTarget);
    }
}

style.xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" >
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
Host_Name,IP_address,OS,Load_avg_1min,Load_avg_5min,Load_avg_15min
<xsl:for-each select="//Host">
<xsl:value-of select="concat(Host_Name,',',IP_address,',',OS,Load_avg_1min,',',Load_avg_5min,',',Load_avg_15min,'&#xA;')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

sortie:

Host_Name,IP_address,OS,Load_avg_1min,Load_avg_5min,Load_avg_15min
srv001001,10.1.2.3,Windows1.3,2.5,1.2
srv001002,10.1.2.4,Linux1.4,2.5,1.2
srv001003,10.1.2.5,Linux3.3,1.6,1.8
srv001004,10.1.2.6,Linux2.3,4.5,4.2
24
Guy Gavriely

Trois étapes: 

  1. Analyser le fichier XML dans un objet Java XML library
  2. Récupère les données pertinentes de l'objet pour chaque ligne. 
  3. Ecrivez les résultats dans un fichier texte à l'aide de fonctions Java natives , enregistrez-les avec l'extension * .csv.
2
Jono

Le mieux est d’utiliser XSLT pour "transformer" le XML en CSV. Il y a des questions sur comment (comme ici ) qui expliquent comment faire cela. La clé est de fournir un schéma pour vos données source afin que le processus de transformation XSLT sache le lire afin qu'il puisse formater correctement les résultats.

Ensuite, vous pouvez utiliser Xalan pour saisir le XML, lire le XSLT et afficher vos résultats.

2
Pedantic

La réponse a déjà été fournie par Pedantic (utilisant l'approche de type DOM {Document Object Model}) et Jono (avec l'approche de type SAX cette fois) en janvier.

Mon opinion est que les deux méthodes fonctionnent bien pour les petits fichiers mais que ces derniers fonctionnent mieux avec les gros fichiers XML. Vous n'avez pas mentionné la taille réelle de vos fichiers XML, mais vous devez en tenir compte.

Quelle que soit la méthode utilisée, un programme spécifique (qui détecterait des balises spéciales adaptées à votre code XML local) sera plus facile à écrire mais ne fonctionnera pas sans adaptations de code pour une autre version XML, alors qu'un programme plus générique sera plus difficile à concevoir mais fonctionnera pour tous les fichiers XML . Vous avez dit que vous vouliez pouvoir analyser un fichier sans spécifier de noms d'élément spécifiques, alors je suppose que l'approche générique est ce que vous préférez, et je suis d'accord avec cela, mais veuillez noter que c'est plus facile à dire qu'à faire . En effet, j'ai eu le même problème en janvier aussi, impliquant cette fois un gros fichier XML (>> 100Mo) et j'ai été surpris que rien ne soit disponible sur Internet jusqu'à présent. Améliorer la frustration en quelque chose de mieux est toujours une bonne chose, j'ai donc décidé de traiter ce problème spécifique de la manière la plus générique par moi-même, avec un souci particulier pour le big-XML-file-issue.

Vous serez peut-être intéressé de savoir que la bibliothèque générique Java que j'ai écrite, qui est maintenant publiée en tant que logiciel libre, convertit votre fichier XML en fichier CSV comme vous le souhaitiez (en mode -x -u {veuillez vous reporter à la documentation pour plus d'informations}) .

La réponse à la dernière partie de votre question est donc la suivante: oui, il existe au moins une bibliothèque qui vous aidera à atteindre votre objectif, le mien, qui s'appelle "XML2CSV-Generic-Converter" . Il pourrait y en avoir d'autres de Bien sûr, et les meilleurs certainement, mais je ne pouvais en choisir aucun (gratuit) seul.

Je ne fournirai aucun lien ici pour me conformer à la remarque judicieuse de Peter Foti - mais si vous entrez "XML2CSV-Generic-Converter" dans votre moteur de recherche préféré, vous devriez le trouver facilement.

1
Lochrann

votre fichier a l'air vraiment plat et simple. Vous n'avez pas nécessairement besoin d'un analyseur XML pour le convertir. Il suffit de l’analyser avec LineNumberReader.readLine() et d’utiliser regexp pour extraire des champs spécifiques. 

Une autre option consiste à utiliser StAX, une API de diffusion en continu pour le traitement XML. C'est assez simple et vous n'avez pas besoin de charger le document entier dans la RAM.

0
injecteer