Comment récupérer toutes les données d'un XML vers un CSV

Signaler
-
 faborus -
Bonjour a tous,

Dans ma société je dois créer un logiciel qui convertit automatiquement un fichier XML en CSV.

Ce fichier doit dans un premier temps être affiché dans un DataGridView pour avoir une vue IHM.

Ensuite avoir un système de Checkbox sur chaque colonne pour savoir si on garde ou non cette colonne.

Le problème c'est que je dois faire en sorte d'utiliser aucun nom en dur dans mon code, pour que mon code recupère automatiquement le nom des colonnes et aussi ses valeurs...

Voici mon flux :

<?xml version="1.0" encoding= "UTF-8"?>
<catalog>
<ref_produit><![CDATA[ABH007]]></ref_produit><nom_produit><![CDATA[NiMH medical battery 8.4V]]></nom_produit> http://www.monsite.fr <sous-categorie>Medical battery</sous-categorie>


<ref_produit><![CDATA[ABH0011]]></ref_produit><nom_produit><![CDATA[NiMH battery]]></nom_produit>http://www.monsite.fr<sous-categorie>Calculator battery</sous-categorie>


<ref_produit><![CDATA[GML90280]]></ref_produit><nom_produit><![CDATA[Mobile phone battery]]></nom_produit>http://www.monsite.fr<sous-categorie>Mobile phone, PDA battery</sous-categorie>


</catalog>


Voici un code :

 XmlDocument doc  = new XmlDocument();
               // chemin de mon fichier ce-dessus
                doc.Load(chemin);

                // Get and display all the book titles.
                XmlElement root = doc.DocumentElement;
                //bout de code qu'il ne faudrait pas que j'utilise
                XmlNodeList elemList = root.GetElementsByTagName("product");
                for (int i = 0; i < elemList.Count; i++)
                {
                    MessageBox.Show(elemList[i].InnerXml);                    
                }



Voici un autre bout de code qui fait a peu près la même chose :

                StringBuilder output = new StringBuilder();
                String xmlString = XDocument.Load(chemin).FirstNode.ToString();               
                // Create an XmlReader
                using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
                {
                    XmlWriterSettings ws = new XmlWriterSettings();
                    string textcdata = "";
                    int fin = 0;
                    bool retourchariot = false;

                    while (reader.Read())
                    {
                        switch (reader.NodeType)
                        {
                            case XmlNodeType.Element:
                                fin = 0;                                
                                // MessageBox.Show(reader.Name);
                                break;
                            case XmlNodeType.CDATA:
                            case XmlNodeType.Text:
                               //le replace sert a ne pas faire planter sur les ' ' 0x20
                                textcdata = reader.Value.Replace("<![CDATA[", "").Replace("]]>", "");
                                break;
                            case XmlNodeType.EndElement:
                               //quand 2 noeuds se ferment c'est la fin d'un product... pas très propre mais bon...
                                fin = fin + 1;
                                if (fin == 2)
                                {
                                    retourchariot = true;
                                }
                                break;
                        }
                    }
                }



Un autre bout sinon :
XDocument fichier = XDocument.Load(chemin);
//affiche toutes les lignes du fichier                
MessageBox.Show(fichier.FirstNode.ToString()); 

//1er product
MessageBox.Show(fichier.Root.FirstNode.ToString());
//2eme product
MessageBox.Show(fichier.Root.FirstNode.NextNode.ToString());
//3eme product
MessageBox.Show(fichier.Root.FirstNode.NextNode.NextNode.ToString());

//pas propre car je me vois pas avec mes flux de +900 000 lignes avec .NextNode 900 000 fois



Je tiens a préciser qu'il faut que mon programme fonctionne avec tout les fichier XML standard

J'ai testé quelques autres choses qui peuvent être mieux je pense, mais je voulais avoir un petit avis de la communautée.

Dictionary ? XMLserializer ? XMLDocument ?

7 réponses

Messages postés
239
Date d'inscription
lundi 5 décembre 2005
Statut
Membre
Dernière intervention
27 août 2012
5
Essaies avec xpath et des fonctions récursives.
Bonjour,

Merci Tupad de ta réponse, seulement avec le Xpath j'ai l'impression que je suis obligé de lui donner le nom des différents noeuds de mon fichier XML...

Est-ce que tu aurai une autre idées ou sinon quels genre de fonctions récursives je pourrai utilisé ?

Je rappel que les flux a traité feront en moyenne une taille de 500mo --> 3go max avec plus de 3millions de ligne.

Merci de votre aide
Messages postés
239
Date d'inscription
lundi 5 décembre 2005
Statut
Membre
Dernière intervention
27 août 2012
5
Le fichier XML

<test>
<child>

ceci est du texte


</child>
<child1>
</child1>
</test>


Xpath:
- Pour récupérer test: /*
- Pour child et child1: /test/*
- Pour récupérer plop : /test/child/*
- Pour récupérer Ceci est du test : /test/child/plop/text()

De là, les fonctions récursives sont assez simples ;)
Cette méthode est bien, mais je ne connais pas d'avance les différents noeuds de mon fichier, c'est la que je pense que le Xpath est pas forcement bien dans mon cas
Messages postés
239
Date d'inscription
lundi 5 décembre 2005
Statut
Membre
Dernière intervention
27 août 2012
5
J'ai développé le code suivant. Il parse un fichier de 21Mo en +/- 600ms (sur ma machine). Je ne connais pas suffisament XPath, donc je suis certain que l'on peut faire mieux

public class XMLtoCSV
    {
        // Get selector of product
        private string GetSelector(XPathNavigator nav, string selector)
        {
            string completeSelector = selector + "/*[1]";


            XPathNodeIterator iterator = nav.Select(completeSelector);
            if (iterator.MoveNext())
                return selector + "/" + this.GetSelector(nav, iterator.Current.Name);
            return selector;
        }

        // get count of childs node
        private int GetChildsCount(XPathNavigator nav, string selector)
        {

            string allChildsSelector = selector + "/*";
            string itemSelector = selector;


            XPathNodeIterator allChildsIterator = nav.Select(allChildsSelector);
            XPathNodeIterator itemIterator = nav.Select(itemSelector);
            return allChildsIterator.Count / itemIterator.Count;
        }

        // Convert to CSV
        private List<string> ConvertToCSV(XPathNavigator nav, string selector, int childsCount)
        {
            List<string> list = new List<string>();
            string allChildsSelector = selector + "/*";
            XPathNodeIterator iterator = nav.Select(allChildsSelector);

            int i = 0;
            string s = "";
            while (iterator.MoveNext())
            {
                if (s == string.Empty)
                    s = iterator.Current.Value;
                else
                    s += ";" +  iterator.Current.Value;

                i++;

                if (i !0 && i % 8 0)
                {
                    list.Add(s);
                    s = string.Empty;
                }

            }
            return list;
        }


        public void ParseXML()
        {
            XPathDocument xmlPathDoc = new XPathDocument("test.xml");
            XPathNavigator nav = xmlPathDoc.CreateNavigator();

            string selector = this.GetSelector(nav, "");

            int count = this.GetChildsCount(nav, selector);

            List<string> list = this.ConvertToCSV(nav, selector, count);

// missing : write list in file
        }
    }
Merci beaucoup pour ton code, je comprend un peu mieux comment fonctionne le Xpath maintenant.

J'espère trouver une solution à mon problème et j'afficherai la solution quand je l'aurai trouvé.
Bonjour à tous,

J'ai trouvé un bout de code dans mon livre C# 4.0 in a nutshell.

Le voici :

 XmlReaderSettings settings = new XmlReaderSettings();
                settings.IgnoreWhitespace = true;

                using (XmlReader r = XmlReader.Create(chemin, settings))
                {
                    r.ReadStartElement("catalog");
                    while (r.Name == "product")
                    {
                        XElement logEntry = (XElement)XNode.ReadFrom(r);
                        string source = (string)logEntry.Element("ref_produit");  
                    }
                    r.ReadEndElement();                
                }


Ce bout de code me sert à savoir quelles sont les variables qui sont disponibles pour chaque produit et récupérer leurs variables.
Ce n'est pas exactement ce que je voulais mais comme sa je pourrai vérifier dans quel cas les balises sont présentes ou non, et je pourrais les ranger si celle-ci sont mélangées dans le flux.


Merci Tupad de ton aide et de ton attention