C# et XML

Signaler
Messages postés
1
Date d'inscription
jeudi 15 décembre 2011
Statut
Membre
Dernière intervention
15 décembre 2011
-
desperados27
Messages postés
121
Date d'inscription
samedi 4 novembre 2006
Statut
Membre
Dernière intervention
1 juillet 2015
-
Salut,
SVP,J'ai besoin d'une classe en C# qui me permet de lire le contenu d'un fichier XML.
C'est vraiment très urgent et Merci d'avance

15 réponses

Messages postés
14252
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 février 2020
343
Bonjour,

c'est assez simple, mais un petit exemple vaut mieux qu'un grand discours

soit le fichier xml suivant
  <?xml version="1.0" encoding="utf-8" ?> 
      <!-- Un petit commentaire tout au début pour la forme ;-) --> 
      <Racine>
         <Balise1>
           <Balise2>
               <ListePersonnes>
                <Personne>
                  <Nom Prenom="Alain">Dit</Nom> 
                  <DateNaisance>1990-06-06T00:00:00</DateNaisance> 
                  </Personne>
                <Personne>
                  <Nom Prenom="Jean">Sort</Nom> 
                  <DateNaisance>2000-01-01T00:00:00</DateNaisance> 
                  </Personne>
                </ListePersonnes>
           </Balise2>
        </Balise1>
    </Racine>


On souhaite récupérer la liste de personnes,
on commence par écrire une classe Personnes

using System;

namespace test
{
    class Personnes
    {
        public string Nom { get; set; }

        public string Prenom { get; set; }

        public DateTime DateNaissance { get; set; }
    }
}


et là le code pour lire/écrie une liste de personnes

private List mesPersonnes = new List();
        
        private void ImportXml()
        {
            XDocument xDoc = XDocument.Load(string.Format(@"{0}\test.xml",Application.StartupPath));

            mesPersonnes = (from personne in xDoc.Descendants("Personne")//directement la balise qui contient les données d'une seule instance de personne
                            select new Personnes
                            {
                                Nom = personne.Element("Nom").Value, // c'est un string donc pas de conversion
                                Prenom = personne.Element("Nom").Attribute("Prenom").Value, //on va chercher l'attribut
                                DateNaissance = DateTime.Parse(personne.Element("DateNaisance").Value)//on convertit en datetime
                            }
                        ).ToList();//on en fait une liste
        }

        private void ExportXml()
        {
            XDocument xDoc = new XDocument(new XElement("Racine",
                new XElement("Balise1", //une balise
                    new XElement("Balise2", //et encore une
                        new XElement("ListePersonnes", //on attaque la liste de personnes
                            from personne in mesPersonnes
                            orderby personne.Prenom ascending //triées par prénom pour le principe
                            select new XElement("Personne",
                                new XElement("Nom", new XAttribute("Prenom", personne.Prenom), personne.Nom),//on écrit l'élement Nom avec Prenom en attribut
                                new XElement("DateNaisance", personne.DateNaissance)// on écrit l'élément date de naissance
                                )
                            )
                        )
                    )
                )
            );

            xDoc.AddFirst(new XComment("Un petit commentaire tout au début pour la forme ;-)"));

            //on sauve
            xDoc.Save(string.Format(@"{0}\test.xml",Application.StartupPath));
        }


Voilà,
l'avantage c'est que la structure xml se "voit" dans la mise en forme du code.

Whismeril
Messages postés
14655
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
22 février 2020
139
Bonjour,

Regardes dans l'espace de nom System.Xml.

---------------------------------------------------------------------
[list=ordered][*]Pour poser correctement une question et optimiser vos chances d'obtenir des réponses, pensez à lire le règlement CS, ce lien ou encore celui-ci[*]Quand vous postez un code, merci d'utiliser la coloration syntaxique (3ième icône en partant de la droite : )
[*]Si votre problème est résolu (et uniquement si c'est le cas), pensez à mettre "Réponse acceptée" sur le ou les messages qui vous ont aidés./list
---
Messages postés
642
Date d'inscription
mercredi 10 septembre 2008
Statut
Membre
Dernière intervention
9 février 2017
5
Salut,

Au cas ou tu n'ais pas utilise la recherche, si tu tapes XML dans "trouver un code source", apparait tout un tas d'exemples pour ton probleme.

@pluche

[b]"Chez ceux qui semblent très vertueux se cachent en général la vanité, l'orgueil, l'intolérance".

P.Coehlo (Maktub 2004)/b
Messages postés
121
Date d'inscription
samedi 4 novembre 2006
Statut
Membre
Dernière intervention
1 juillet 2015


C'est vraiment très urgent et Merci d'avance


Si tu veux récupérer rapidement
Utilise la classe XmlTextReader

using System.Xml;

private void RecupXML()
{
    // On instancie un Reader xml qui lit sequentiellement les noeuds
    XmlTextReader Reader = new XmlTextReader(Nom de ton fichier)
    do
    {
        // On avance de noeuds en noeuds
        Reader.Read();
        // On vérifie la première balise souhaitée
        if (Reader.Name == "Noeud" && Reader.NodeType != XmlNodeType.EndElement)
        {
             //Si tu veux récupérer un attribut :
             Reader.MoveToFirstAttribute();
             string variableAttribut = Reader.Value

             //Si il y a plusieurs attributs
             Reader.MoveToNextAttribute();
             string variableAttribut2 = Reader.Value

             string Texte = "";
             // Si il y a des Noeuds "enfants"
             do
             {
                  Reader.Read();
                  if (Reader.Name == "sous-Noeud" && Reader.NodeType != XmlNodeType.EndElement)
                  {
                      Reader.Read()
                      // Et Voici comment on récupère du texte
                      if (Reader.NodeType == XmlNodeType.Text)
                      {
                           Texte = Reader.Value;
                      }
                  }
             }
             while (Reader.Name != "Noeud");
        }
    } while (!Reader.EOF);
}



Dsl si il y a quelques fautes de syntaxe c'est ecrit à la main :)
J'espère que ça va t'aider.

Là c'est un exemple très simple, il arrive souvent que certains noeuds n'ont pas toujours la même structure. Il va falloir bosser dur ^^.

Sébastien
Messages postés
14744
Date d'inscription
lundi 11 juillet 2005
Statut
Modérateur
Dernière intervention
21 février 2020
91
Hello,
Dsl si il y a quelques fautes de syntaxe c'est ecrit à la main

Pourquoi? C'est mieux quand c'est écrit avec les pieds?

Désolé, ça m'a échappé...Je suis déjà loin...


@+
Buno, Admin CS
L'urgent est fait, l'impossible est en cours. Pour les miracles, prévoir un délai...
Messages postés
14252
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 février 2020
343
Bonsoir,

en framwork 3.5 ou 4 il y a link to xml aussi.


Whismeril
Messages postés
14252
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 février 2020
343
heu linq pardon


Whismeril
Messages postés
121
Date d'inscription
samedi 4 novembre 2006
Statut
Membre
Dernière intervention
1 juillet 2015


Pourquoi? C'est mieux quand c'est écrit avec les pieds?


Héhé c'est peut-être mieux il faut essayer ^^.
Je voulais dire par là que j'ai écrit à la volée et directement dans le message sans passer par un éditeur :)

Et oui en 3.5 il y a le LinqToXml avec
using System.Xml.Linq;

Même si je ne sais pas encore l'utiliser. (j'ai pas vraiment cherché non plus)
Je pense, à mon goût, que pour débuter la lecture séquentielle est parfaite...


Seb
Messages postés
121
Date d'inscription
samedi 4 novembre 2006
Statut
Membre
Dernière intervention
1 juillet 2015

Bonjour whismeril,

C'est vraiment très intéressant. Je viens de terminer une application qui lit un fichier XML (avec un XmlTextReader et ça fonctionne parfaitement), donc ce sera parfait pour tester ça dessus !

Seulement il y a un hic....
Ton fichier xml est très simple et sans anomalies.

Voici une partie de variable de mon xml :


<variable ident="21" type="single" format="numeric">
    <name>Titre de la variable</name>
    <label>
        <text xml:lang="en-US" mode="interview">Libellé de la variable en anglais US</text>
        <text xml:lang="en-GB" mode="interview">Libellé de la variable en anglais GB</text>
    </label>
</variable>



Comment fais-je pour définir une condition qui lui fait récupérer seulement le noeud "text" avec xml:lang="en-GB" !!?
Voici mon code pour le moment (il se trouve que j'avais déjà une classe et une collection pour mon programme ;) )

            XDocument xDoc = XDocument.Load(NomFichier + ".xml");
            VariablesCollection = (from uneVar in xDoc.Descendants("variable") // Je viens directement au noeud suscitant l'intérêt
                                   select new Variable
                                   {
                                       iID = Convert.ToInt32(uneVar.Attribute("ident").Value), // Je récupère la première info
                                       sTypeQuestion = uneVar.Attribute("type").Value, // Je récupère la deuxième info
                                       sTitre = uneVar.Element("name").Value, // Je récupère la troisième info - Jusqu'ici pas de soucis !

                                       // A partir de là c'est un mystère
                                       sLibelTitre = uneVar.Element("label").Element("text").Value
                                   }
                                   ).ToList<Variable>();


Ca me parait compliqué la non ?
Seb
Messages postés
14252
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 février 2020
343
Re,

tu peux extraire une liste dans une liste:

    class Libelle
    {
        public string Text { get; set; }

        public string Langue { get; set; }
    }


            VariablesCollection = (from uneVar in xDoc.Descendants("variable") // Je viens directement au noeud suscitant l'intérêt
                                   select new Variable
                                   {
                                       iID = Convert.ToInt32(uneVar.Attribute("ident").Value), // Je récupère la première info
                                       sTypeQuestion = uneVar.Attribute("type").Value, // Je récupère la deuxième info
                                       sTitre = uneVar.Element("name").Value, // Je récupère la troisième info - Jusqu'ici pas de soucis !

                                       
                                       ListeDeLibbele = (from libelle in xDoc.Descendants("text")
                                                             select new Libelle
                                                             {
                                                                 Text = libelle.Value,// l'accent de libellé ne passe pas  car par défaut le xml c'est en utf8.
                                                                 Langue = libelle.FirstAttribute.Value//la recherche de Attribute("xml:lang") bugue sur le :, d'ou le FirstAttibute
                                                             }).ToList<Libelle>()//uneVar.Element("label").Element("text").Value
                                   }
                                   ).ToList<Variable>();

et ensuite tu te débrouilles dans la classe variable pour que soit retourné le bon libélé.

Sinon pour lire directement le bon, je ne sais pas, je n'ai pas eu ce cas jusque là.
Peut-être une méthode dérivée?

Whismeril
Messages postés
121
Date d'inscription
samedi 4 novembre 2006
Statut
Membre
Dernière intervention
1 juillet 2015

Salut whismeril,

Ca ressemble très fortement au SQL tout ça
on ne peut pas mettre genre n "where" ? :

VariablesCollection = (from uneVar in xDoc.Descendants("variable") // Je viens directement au noeud suscitant l'intérêt
                                   select new Variable
                                   {
                                       iID = Convert.ToInt32(uneVar.Attribute("ident").Value), // Je récupère la première info
                                       sTypeQuestion = uneVar.Attribute("type").Value, // Je récupère la deuxième info
                                       sTitre = uneVar.Element("name").Value, // Je récupère la troisième info - Jusqu'ici pas de soucis !

                                       
                                       ListeDeLibbele = (from libelle in xDoc.Descendants("text")
                                                         where libelle.FirstAttribute.Value == "en-GB" // C'est juste une idée
                                                             select new Libelle
                                                             {
                                                                 Text = libelle.Value,// l'accent de libellé ne passe pas  car par défaut le xml c'est en utf8.
                                                                 Langue = libelle.FirstAttribute.Value//la recherche de Attribute("xml:lang") bugue sur le :, d'ou le FirstAttibute
                                                             }).ToList<Libelle>()//uneVar.Element("label").Element("text").Value
                                   }
                                   ).ToList<Variable>();


Désolé je ne peux pas tester ce 'where' de la journée. Après je ne sais pas du tout si ce que j'ai marqué est possible...
Messages postés
14252
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 février 2020
343
Re,

si ça marche, mais du coup ça te retourne une liste avec 1 enregistrement et par la suie tu dois aller chercher l'index 0 de ta liste.
En grattant de ce coté voile ce que je te propose

                                      MonLibelle = (from libelle in xDoc.Descendants("text")
                                                         where libelle.FirstAttribute.Value == "en-GB"    
                                                         select new Libelle
                                                             {
                                                                 Text = libelle.Value,
                                                                 Langue = libelle.FirstAttribute.Value
                                                             }).ToList<Libelle>()[0]//on prend ici la valeur contenue dans l'index 0



Whismeril
Messages postés
121
Date d'inscription
samedi 4 novembre 2006
Statut
Membre
Dernière intervention
1 juillet 2015

Salut whismeril,

Franchement merci, tu m'as mis sur la piste du LINQ et j'adore déjà !!!!! J'ai réussi à re-récupérer mon fichier xml comme avec le XmlTextReader exactement de la même façon mais avec 75% de lignes de code en moins !!

J'ai dû pas mal bouquiner hier soir pour trouver ce que je cherchais pour faire la totalité de la récupération de mon fichier.

Je vais poster mon code ce soir avec des commentaires si ça peut aider certain.

Merci à toi, tu mérites ta réponse acceptée
Seb
Messages postés
14252
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
22 février 2020
343
J'ai découvert ça assez récemment, j'étais coincé à la framework 2 à cause d'un PC sous W2000 (si si ça existe encore) et comme toi ça m'a réduit de façon importante le nombre de ligne et la complexité du code.
Par contre je suis loin d'avoir tout exploré...


Whismeril
Messages postés
121
Date d'inscription
samedi 4 novembre 2006
Statut
Membre
Dernière intervention
1 juillet 2015

Hello,
Comme promis voici mon code pour récupérer les variables de mon xml

D'abord je vous montre variable en entier :

<variable ident="1" type="quantity" use="serial">
        <name>Serial</name>
        <label>
          <text xml:lang="da-DK" mode="analysis">Titre en Danois</text>
          <text xml:lang="de-DE" mode="analysis">Titre en US</text>
          <text xml:lang="en-US" mode="analysis">Titre en Anglais</text>
          <text xml:lang="en-GB" mode="analysis">Titre en Néerlandais</text>
          <text xml:lang="fr-FR" mode="analysis">Titre en Suédois</text>
        </label>
        
        <values>
          <range from="1" to="2147483647" />  <!--Ici variable quantitative donc pas de modalités -->
        </values>
      </variable>
            <variable ident="276" type="single" format="numeric">
        <name>satQA</name>
        <label>
          <text xml:lang="da-DK" mode="interview">Titre en Danois</text>
          <text xml:lang="en-US" mode="interview">Titre en US</text>
          <text xml:lang="en-GB" mode="interview">Titre en Anglais</text>
          <text xml:lang="nl-NL" mode="interview">Titre en Néerlandais</text>
          <text xml:lang="sv-SE" mode="interview">Titre en Suédois</text>
        </label>
        
        <values>
          <value code="1">VeryEnjoyable<text xml:lang="da-DK" mode="interview">Vældig godt lide undersøgelsen</text><text xml:lang="en-US" mode="interview">Very enjoyable</text><text xml:lang="en-GB" mode="interview">Very enjoyable</text><text xml:lang="nl-NL" mode="interview">Erg leuk</text><text xml:lang="sv-SE" mode="interview">Mycket trevlig</text></value>
          <value code="2">SomewhatEnjoyable<text xml:lang="da-DK" mode="interview">Rimelig godt lide undersøgelsen </text><text xml:lang="en-US" mode="interview">Quite enjoyable</text><text xml:lang="en-GB" mode="interview">Quite enjoyable</text><text xml:lang="nl-NL" mode="interview">Redelijk leuk</text><text xml:lang="sv-SE" mode="interview">Ganska trevlig</text></value>
          <value code="3">NotVeryEnjoyable<text xml:lang="da-DK" mode="interview">Ikke lide undersøgelsen</text><text xml:lang="en-US" mode="interview">Not very enjoyable</text><text xml:lang="en-GB" mode="interview">Not very enjoyable</text><text xml:lang="nl-NL" mode="interview">Niet zo leuk</text><text xml:lang="sv-SE" mode="interview">Inte särskilt trevlig</text></value>
          <value code="4">NotAtAllEnjoyable<text xml:lang="da-DK" mode="interview">Slet ikke lide undersøgelsen</text><text xml:lang="en-US" mode="interview">Not at all enjoyable</text><text xml:lang="en-GB" mode="interview">Not at all enjoyable</text><text xml:lang="nl-NL" mode="interview">Helemaal niet leuk</text><text xml:lang="sv-SE" mode="interview">Inte alls trevlig</text></value>
          <value code="5" /> <!--Ici spécial car pas de Value à retourner !!! -->
        </values>
      </variable>



Alors il existe plein d'autres possibiltés de variables que je gère parfaitement dans le code suivant expliqué en commentaire :) :


//J'ai 4 classes
class Variable
    {
        public int iID { get; set; }
        public string sTitre { get; set; }
        public List<LabelTitre> sLibelTitres { get; set; }
        public int iStart { get; set; }
        public int iEnd { get; set; }
        public int iSpreadSubfields { get; set; }
        public int iSpreadWidth { get; set; }
        public string sTypeQuestion { get; set; }
        public List<Moda> sModas { get; set; }
        public bool bChecked { get; set; }
    }
class LabelTitre : Variable // Hérite de Variable
    {
        public string monLibelleTitre { get; set; }
        public string langueTitre { get; set; }
    }
class Moda : Variable // Hérite de Variable
    {
        public List<LabelModa> LabelModas { get; set; }
        public int sCode { get; set; }
    }
class LabelModa : Moda // Hérite de Moda
    {
        public string monLibelleModa { get; set; }
        public string langueModa { get; set; }
    }

//Ensuite dans ma Form après avoir cliqué sur le bouton "Récupérer le xml"
VariablesCollection.Clear();
XDocument xDoc = XDocument.Load(NomFichier + ".xml");
//Le mot clé (int) comme (int)unElement.Element("NomElement") PEUT REMPLACER DIRECTEMENT Convert.ToInt32(unElement.Element("NomElement").Value)
                //Le mot clé (string) comme (string)unElement.Element("NomElement") PEUT REMPLACER DIRECTEMENT unElement.Element("NomElement").Value
                //C'est vraiment très pratique

                VariablesCollection = (from uneVar in xDoc.Descendants("variable") // je prend toutes les variables
                                       where (int)uneVar.Element("position").Attribute("start") != 0 // Je vérifie position start != 0 (car pour moi c'est une variable inutile et donc je la vire si == 0)
                                       let FinishAttributeExist = uneVar.Element("position").Attribute("finish") // Je crée une variable temporaire qui reçoit l'attribut finish pour savoir si il existe ou pas (car il est optionnel)
                                       let SpreadElementExist = uneVar.Element("spread") // Idem sauf que là je vérifie carrément si l'élément 'spread' existe
                                       let LabelElementEmpty = (string)uneVar.Element("label") // Idem sauf qu'ici label existe forcément mais peut être une balise vide, je détecte donc si une Value existe ici
                                       let StartOrder = (int)uneVar.Element("position").Attribute("start") // Ici une variable pour définir l'ordre de rangement dans VariablesCollection par position start
                                       let ValuesElementEmpty = (string)uneVar.Element("values") // Je regarde si values est un élément vide et donc sans Value
                                       orderby StartOrder ascending // J'applique mon ordre de rangement dans VariableCollection
                                       select new Variable
                                       {
                                           iID = (int)uneVar.Attribute("ident"), // Pas de soucis ici
                                           sTypeQuestion = (string)uneVar.Attribute("type"), // Pas de soucis ici
                                           sTitre = (string)uneVar.Element("name").Value, // Pas de soucis ici
                                           iStart = (int)uneVar.Element("position").Attribute("start"), // Pas de soucis ici
                                           iEnd = FinishAttributeExist != null ? (int)uneVar.Element("position").Attribute("finish") : 0, // Ici on peut mettre une condition sur la variable FinishAttributeExist définie précédement pour vérifier si finsih existe et si oui récupéré Value sinon par défaut : 0
                                           iSpreadSubfields = SpreadElementExist != null ? (int)uneVar.Element("spread").Attribute("subfields") : 0, // Idem ici mais là c'est l'élément qui est vérifié
                                           iSpreadWidth = SpreadElementExist != null ? (int)uneVar.Element("spread").Attribute("width") : 0, // Idem ici
                                           sLibelTitres = LabelElementEmpty != null ? // avant d'executer la nouvelle requête je vérifie si label n'est pas vide
                                                           (from unLabelTitre in uneVar.Element("label").Descendants("text") // Ici je part directement de 'uneVar.' et non 'xDoc' pour une question de logique
                                                           let LabelTitreAttributeEmpty = unLabelTitre.FirstAttribute // Une petite vérification d'attribut existant
                                                           select new LabelTitre
                                                           {
                                                               langueTitre = LabelTitreAttributeEmpty != null ? (string)unLabelTitre.FirstAttribute : null, // Je récupère la langue si l'attribut existe sinon reçoit 'null'
                                                               monLibelleTitre = LabelTitreAttributeEmpty != null ? (string)unLabelTitre : null // Idem ici on ne récupère pas le libellé si la langue n'existe pas (il ne devrait pas exister tbh mais bon...)
                                                           }).ToList<LabelTitre>() : null, // Directement dans la collection sinon null
                                           sModas = ValuesElementEmpty != null ? // Idem que pour le libellé du titre, on vérifie si ValuesElementEmpty n'est pas vide ('null')
                                                           (from uneModa in uneVar.Element("values").Descendants("value") // je pars de uneVar
                                                           let CodeOrder = (int)uneModa.Attribute("code") // Je prépare un tri sur le code des 'value'
                                                            let ValueEmpty = (string)uneModa // Pour vérifier si 'value' est un élément vide
                                                           orderby CodeOrder ascending // J'applique mon ordre de rangement dans sModas
                                                           select new Moda
                                                           {
                                                               sCode = (int)uneModa.Attribute("code"), // Je récupère le code (il existe toujours, pas besoin de vérif
                                                               LabelModas = ValueEmpty != null ? // On vérifie que value a quelquechose dans son élément
                                                                            (from unLabelModa in uneModa.Descendants("text")
                                                                            // Ici c'est pareil que dans slibelTitre
                                                                            let LabelModaAttributeEmpty = unLabelModa.FirstAttribute
                                                                            select new LabelModa
                                                                            {
                                                                                langueModa = LabelModaAttributeEmpty != null ? (string)unLabelModa.FirstAttribute : null,
                                                                                monLibelleModa = LabelModaAttributeEmpty != null ? (string)unLabelModa : null
                                                                            }).ToList<LabelModa>() : null
                                                           }).ToList<Moda>() : null

                                       }
                                       ).ToList<Variable>(); // VariablesCollection est totalement remplie sans erreurs youpi !!!



J'espère avoir été compréhensible
J'ai fait des tests de vitesse entre XmlTextReader et LinqToXml, il n'y pas de différences !!

Bon ben on devrait être proche de finir ce topic.
Merci pour tout whismeril, tu m'as mis la où il fallait, niquel.


Ciao,
Seb