none
Générer une structure de donnée à partir d'un fichier XML RRS feed

  • Question

  • Bonjour,

    J'ai un souci relativement bete mais je galère un peu à cause du coté récursif.
    Donc voilà en gros j'ai la structure XML suivante qui représente une table des matières :

    <ol xmlns="http://www.w3.org/1999/xhtml">
      <li>
        <a href="heftywater.xhtml#title">Hefty Water</a>
        <ol>
          <li>
            <a href="heftywater.xhtml#switch">The Switch</a>
          </li>
          <li>
            <a href="heftywater.xhtml#source">The Source</a>
          </li>
          <li>
            <a href="heftywater.xhtml#ruby">Hefty Ruby Water</a>
          </li>
        </ol>
      </li>
    </ol>

    Il s'agit juste d'un exemple car on pourrait avoir des sous-noeuds qui représentent des sous-chapitres ...

    J'aimerais transformer ce xml en instance de classe avec la structure suivante :

    public class Toc
        {
            public List<TocItem> Items { get; set; }
    
            public Toc()
            {
                Items = new List<TocItem>();
            }
        }
    
        public class TocItem
        {
            public List<string> Text { get; set; }
    
            public string HRef { get; set; }
    
            readonly List<TocItem> _children = new List<TocItem>();
            public IList<TocItem> Children
            {
                get { return _children; }
            } 
        }


    Donc j'aimerais écrire une méthode qui doit ressembler à ca :

    void BuildTocFromXml(IList<TocItem> tocItem, XElement element, int depth)
    {
       
    }


    Mais je galère un peu pour l'implémentation, donc si vous avez des idées ...


    vendredi 21 septembre 2012 14:57

Réponses

  • Changez le code de la classe ol.cs par celui ci:

    using System.Collections.Generic;
    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        public class ol : Node
        {
            [XmlElement("ol", typeof(ol))]
            [XmlElement("li", typeof(li))]
            public List<Node> Nodes { get; set; }
        }
    }

    et changez le code de la classe Node.cs par celui ci:

    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        [XmlRoot("ol")]
        [XmlInclude(typeof(ol))]
        [XmlInclude(typeof(li))]
        public class Node
        {
        }
    }

    Le résultat devient donc: 

    <?xml version="1.0"?>
    <ol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="ol">
      <li>
        <a href="http://1111">1111</a>
      </li>
      <ol>
        <li>
          <a href="http://5555">5555</a>
        </li>
        <ol>
          <li>
            <a href="http://2222">2222</a>
          </li>
          <li>
            <a href="http://6666">6666</a>
          </li>
        </ol>
        <li>
          <a href="http://7777">7777</a>
        </li>
        <li>
          <a href="http://8888">8888</a>
        </li>
      </ol>
      <li>
        <a href="http://3333">3333</a>
      </li>
      <li>
        <a href="http://4444">4444</a>
      </li>
    </ol>

    Je pense que cette fois ci c'est la bonne :)


    Blog: marouene.slimi.net


    lundi 24 septembre 2012 09:36

Toutes les réponses

  • Bonjour,

    Vous pouvez utiliser la sérialisation XML. Je vous ai fait un petit exemple:

    La classe mère Node.cs

    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        [XmlRoot("List")]
        [XmlInclude(typeof(ol))]
        [XmlInclude(typeof(li))]
        public class Node
        {
        }
    }

    Les classes filles:

    ol.cs

    using System.Collections.Generic; using System.Xml.Serialization; namespace SerializeRecursive { [XmlRoot("ol")] public class ol : Node { [XmlArray("ChildNodes")] [XmlArrayItem("Node")] public List<Node> Nodes { get; set; } } }

    li.cs

    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        public class li : Node
        {
            [XmlElement("a")]
            public a link { get; set; }
    
            public li() { }
    
            public li(a link)
            {
                this.link = link;
            }
        }
    }
    

    La classe a.cs

    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        public class a
        {
            [XmlAttribute("href")]
            public string Tref { get; set; }
            [XmlText]
            public string Text { get; set; }
        }
    }
    

    et enfin Program.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        class Program
        {
            static void Main(string[] args)
            {
                // La construction de l'arborescence
                li li1 = new li(new a { Text = "1111", Tref = "http://1111" });
                li li2 = new li(new a { Text = "2222", Tref = "http://2222" });
                li li3 = new li(new a { Text = "3333", Tref = "http://3333" });
                li li4 = new li(new a { Text = "4444", Tref = "http://4444" });
                li li5 = new li(new a { Text = "5555", Tref = "http://5555" });
                li li6 = new li(new a { Text = "6666", Tref = "http://6666" });
                li li7 = new li(new a { Text = "7777", Tref = "http://7777" });
                li li8 = new li(new a { Text = "8888", Tref = "http://8888" });
    
                ol ol3 = new ol();
                ol3.Nodes = new List<Node> { li2, li6 };
    
                ol ol2 = new ol();
                ol2.Nodes = new List<Node> { li5, ol3, li7, li8 };
    
                ol root = new ol();
                root.Nodes = new List<Node> { li1, ol2, li3, li4 };
    
                //La sérialisation
                XmlSerializer xml = new XmlSerializer(typeof(Node));
                FileStream ofs = new FileStream(@"D:\TableDeMatières.xml", FileMode.Create, FileAccess.Write);
                xml.Serialize(ofs, root);
                ofs.Close();
    
                //La désérialisation
                FileStream ifs = new FileStream(@"D:\TableDeMatières.xml", FileMode.Open, FileAccess.Read);
                Node result = (Node)xml.Deserialize(ifs);
                ifs.Close();
    
                Console.ReadKey();
            }
        }
    }

    J'espère que cette implémentation vous aidera dans ce que vous voulez faire.

    Cordialement,




    Blog: marouene.slimi.net


    dimanche 23 septembre 2012 12:29
  • Bonjour,

    Vous pouvez utiliser la sérialisation XML. Je vous ai fait un petit exemple:

    La classe mère Node.cs

    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        [XmlRoot("List")]
        [XmlInclude(typeof(ol))]
        [XmlInclude(typeof(li))]
        public class Node
        {
        }
    }

    Les classes filles:

    ol.cs

    using System.Collections.Generic; using System.Xml.Serialization; namespace SerializeRecursive { [XmlRoot("ol")] public class ol : Node { [XmlArray("ChildNodes")] [XmlArrayItem("Node")] public List<Node> Nodes { get; set; } } }

    li.cs

    using System.Xml.Serialization; namespace SerializeRecursive { public class li : Node { [XmlElement("a")] public a link { get; set; } } }

    la classe a.cs

    using System.Xml.Serialization;

    namespace SerializeRecursive
    {
        public class li : Node
        {
            [XmlElement("a")]
            public a link { get; set; }

            public li() { }

            public li(a link)
            {
                this.link = link;
            }
        }
    }

    et enfin Program.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        class Program
        {
            static void Main(string[] args)
            {
                // La construction de l'arborescence
                li li1 = new li(new a { Text = "1111", Tref = "http://1111" });
                li li2 = new li(new a { Text = "2222", Tref = "http://2222" });
                li li3 = new li(new a { Text = "3333", Tref = "http://3333" });
                li li4 = new li(new a { Text = "4444", Tref = "http://4444" });
                li li5 = new li(new a { Text = "5555", Tref = "http://5555" });
                li li6 = new li(new a { Text = "6666", Tref = "http://6666" });
                li li7 = new li(new a { Text = "7777", Tref = "http://7777" });
                li li8 = new li(new a { Text = "8888", Tref = "http://8888" });
    
                ol ol3 = new ol();
                ol3.Nodes = new List<Node> { li2, li6 };
    
                ol ol2 = new ol();
                ol2.Nodes = new List<Node> { li5, ol3, li7, li8 };
    
                ol root = new ol();
                root.Nodes = new List<Node> { li1, ol2, li3, li4 };
    
                //La sérialisation
                XmlSerializer xml = new XmlSerializer(typeof(Node));
                FileStream ofs = new FileStream(@"D:\TableDeMatières.xml", FileMode.Create, FileAccess.Write);
                xml.Serialize(ofs, root);
                ofs.Close();
    
                //La désérialisation
                FileStream ifs = new FileStream(@"D:\TableDeMatières.xml", FileMode.Open, FileAccess.Read);
                Node result = (Node)xml.Deserialize(ifs);
                ifs.Close();
    
                Console.ReadKey();
            }
        }
    }

    J'espère que cette implémentation vous aidera dans ce que vous voulez faire.

    Cordialement,




    Blog: marouene.slimi.net

    Bonjour,

    Pouvez-vous revérifier votre code SVP ?

    Car la classe "a" ce nomme "li" qui a deux instances "li" et plus haut vous avez mis une classe nommée "li" sans instance.

    Cordialement


    Merci de valider par "Proposer comme réponse" si celle-ci répond a votre demande !

    dimanche 23 septembre 2012 16:19
  • Erreur de copie depuis mon VS. Le code est désormais OK

    Blog: marouene.slimi.net

    dimanche 23 septembre 2012 16:55
  • Malheureusement ca ne correspond pas du tout à mon xml initial


    lundi 24 septembre 2012 09:09
  • Effectivement, le but de mon exemple c'est de vous aiguiller. En ce qui concerne le résultat voulu, Cherchez du côté de la sérialisation custom en implémentant l'interface IXmlSerializable.

    La raison pour laquelle vous voulez absolument le format XML voulu c'est que vous avez des XML déjà existants?


    Blog: marouene.slimi.net


    lundi 24 septembre 2012 09:18
  • Changez le code de la classe ol.cs par celui ci:

    using System.Collections.Generic;
    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        public class ol : Node
        {
            [XmlElement("ol", typeof(ol))]
            [XmlElement("li", typeof(li))]
            public List<Node> Nodes { get; set; }
        }
    }

    et changez le code de la classe Node.cs par celui ci:

    using System.Xml.Serialization;
    
    namespace SerializeRecursive
    {
        [XmlRoot("ol")]
        [XmlInclude(typeof(ol))]
        [XmlInclude(typeof(li))]
        public class Node
        {
        }
    }

    Le résultat devient donc: 

    <?xml version="1.0"?>
    <ol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="ol">
      <li>
        <a href="http://1111">1111</a>
      </li>
      <ol>
        <li>
          <a href="http://5555">5555</a>
        </li>
        <ol>
          <li>
            <a href="http://2222">2222</a>
          </li>
          <li>
            <a href="http://6666">6666</a>
          </li>
        </ol>
        <li>
          <a href="http://7777">7777</a>
        </li>
        <li>
          <a href="http://8888">8888</a>
        </li>
      </ol>
      <li>
        <a href="http://3333">3333</a>
      </li>
      <li>
        <a href="http://4444">4444</a>
      </li>
    </ol>

    Je pense que cette fois ci c'est la bonne :)


    Blog: marouene.slimi.net


    lundi 24 septembre 2012 09:36
  • Ok merci beacoup je vais regarder ca et je modifierais pour adapter. Mais dans ce cas la quitte à passer par de la sérialisation ca ne serait pas plus simple de passer par un fichier xsd ? Avec ce fichier ensuite on appelle xsd.exe template.xml /classes et ca génère automatiquement toutes les classes.

    Bon en fait ça ne fonctionne pas avec mon exemple de départ, c'est pour ça que j'étais parti sur une methode récursive.



    lundi 24 septembre 2012 09:41