none
[XML] Serialization with inherited classes and public properties RRS feed

  • Question

  • Hi,

    I don't understand something between this article :

    https://msdn.microsoft.com/en-us/library/3z3z5s6h(v=vs.110).aspx

    public class Orders
    {
        public Book[] Books;
    }   


    and my code :

    public class Orders
    {
        private Book[] Books;
    
        public Book[] BookArray
        {
            get { return this.Books; }
            set { this.Books = value; }
        }
    }

    this will generate an Exception when generating XML document. Why ?

    The goal is then to transform the array of Books[] into a private Collection<Book> with public accessors in a DLL. The application will use these classes as base classes to derive them.

    Thanks,

    Vincent

    Wednesday, May 20, 2015 4:12 PM

Answers

  • I've used this article :

    http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly?msg=5062225#xx5062225xx

    which help me producing a working code :

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml.Serialization;
    
    namespace Test
    {
        public class Animal : IXmlSerializable
        {
            public Animal() { }
            public Animal(string name) { Name = name; }
            public String Name { get; set; }
            public DateTime Birthday { get; set; }
    
            public System.Xml.Schema.XmlSchema GetSchema() { return null; }
    
            public void ReadXml(System.Xml.XmlReader reader)
            {
                if (reader == null)  throw new ArgumentNullException("reader");
    
                reader.MoveToContent();
                Name = reader.GetAttribute("Name");
                Boolean isEmptyElement = reader.IsEmptyElement; // (1)
                reader.ReadStartElement();
                if (!isEmptyElement) // (1)
                {
                    Birthday = DateTime.ParseExact(reader.ReadElementString("Birthday"), "yyyy-MM-dd", null);
                    reader.ReadEndElement();
                }
            }
    
            public void WriteXml(System.Xml.XmlWriter writer)
            {
                if (writer == null) throw new ArgumentNullException("writer");
    
                writer.WriteAttributeString("Name", Name);
                if (Birthday != DateTime.MinValue)
                {
                    writer.WriteElementString("Birthday", Birthday.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
                }
            }
        }
        public class Dog : Animal
        {
            public Dog() { }
            public Dog(string name) : base (name) { }
        }
        public class Cat : Animal
        {
            public Cat() { }
            public Cat(string name) : base(name) { }
        }
        public class Mouse : Animal
        {
            public Mouse() { }
            public Mouse(string name) : base (name) { }
        }
    
        public class AnimalList
        {
            private Collection<Animal> listOfAnimals;
    
            public AnimalList() { listOfAnimals = new Collection<Animal>(); }
    
            [XmlElement("Dog", typeof(Dog))]
            [XmlElement("Cat", typeof(Cat))]
            [XmlElement("Mouse", typeof(Mouse))]
            public Collection<Animal> List
            {
                get { return listOfAnimals; } 
            }
        }
    
        public class Farm
        {
            public Farm() { Animals = new AnimalList(); }
    
            public AnimalList Animals { get; set; }
        }
    
    
        class Program
        {
            static void Main()
            {
                try
                {
                    Farm farm = new Farm();
                    string filename = @"..\..\farm.xml";
    
    
                    farm.Animals.List.Add(new Cat("Ati"));
                    farm.Animals.List.Add(new Cat("Gribouille"));
                    farm.Animals.List.Add(new Dog("Joker"));
                    farm.Animals.List.Add(new Cat("Joyeuse"));
                    
                    // Writing the file requires a TextWriter instance.
                    using (TextWriter writer = new StreamWriter(filename))
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(Farm));
                        serializer.Serialize(writer, farm);
                    }
    
                    // Read XML file
                    using (TextReader reader = new StreamReader(filename))
                    {
                        XmlSerializer serializer2 = new XmlSerializer(typeof(Farm));
                        Farm farm2 = (Farm)serializer2.Deserialize(reader);
                        Console.WriteLine("Numer of animals : {0}", farm2.Animals.List.Count);
                        foreach (Animal animal in farm2.Animals.List)
                        {
                            Console.WriteLine("Name : {0}", animal.Name);
                        }
                        Console.WriteLine("Press any key to continue...");
                        Console.ReadKey();
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
        }
    }
    

    and XML :

    <?xml version="1.0" encoding="utf-8"?>
    <Farm xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Animals>
        <Cat Name="Ati" />
        <Cat Name="Gribouille" />
        <Dog Name="Joker" />
        <Cat Name="Joyeuse" />
      </Animals>
    </Farm>

    :)

    Vincent

    Thursday, May 21, 2015 4:14 PM

All replies

  • Hello Vincent,

    >> this will generate an Exception when generating XML document. Why

    With your code, I created a test demo and it throws a “The type XML.ExpandedBook was not expected…” exception, I notice that you set the Book filed to be private, however, as far as I know, XmlSerializer only looks at public fields and properties by default, If you need more control, you can implement IXmlSerializable and serialize whatever you would like: https://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable(v=vs.110).aspx

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, May 21, 2015 3:14 AM
    Moderator
  • Have you tried to keep the name of the Books member?

    public class Orders
    {
        private Book[] mBooks;
    
        public Book[] Books
        {
            get { return mBooks; }
            set { mBooks = value; }
        }
    }
    

    Otherwise you probably have to adjust some of the strings used in the example.


    • Edited by Viorel_MVP Thursday, May 21, 2015 7:09 AM
    Thursday, May 21, 2015 7:08 AM
  • Hi,

    here's the code :

    public class Orders
        {
            private Book[] mBooks;
    
            public Book[] Books
            {
                get { return this.mBooks; }
                set { this.mBooks = value; }
            }
        }
    
        public class Book : IXmlSerializable
        {
            public string ISBN;
    
            public virtual void WriteXml(XmlWriter writer)
            {
                writer.WriteString(ISBN);
            }
    
            public virtual void ReadXml(XmlReader reader)
            {
                ISBN = reader.ReadString();
            }
    
            public XmlSchema GetSchema()
            {
                return (null);
            }
        }
    
        public class ExpandedBook : Book
        {
            public bool NewEdition;
    
            public override void WriteXml(XmlWriter writer)
            {
                base.WriteXml(writer);
                writer.WriteString(NewEdition.ToString ());
            }
    
            public override void ReadXml(XmlReader reader)
            {
                base.ReadXml(reader);
                NewEdition = bool.Parse (reader.ReadString());
            }
        }

    Same problem. Is there a mistake in my implementation ?

    How to you get your exception name ?

    (@Viorel_) : don't work too)

    Thursday, May 21, 2015 1:38 PM
  • I've used this article :

    http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly?msg=5062225#xx5062225xx

    which help me producing a working code :

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml.Serialization;
    
    namespace Test
    {
        public class Animal : IXmlSerializable
        {
            public Animal() { }
            public Animal(string name) { Name = name; }
            public String Name { get; set; }
            public DateTime Birthday { get; set; }
    
            public System.Xml.Schema.XmlSchema GetSchema() { return null; }
    
            public void ReadXml(System.Xml.XmlReader reader)
            {
                if (reader == null)  throw new ArgumentNullException("reader");
    
                reader.MoveToContent();
                Name = reader.GetAttribute("Name");
                Boolean isEmptyElement = reader.IsEmptyElement; // (1)
                reader.ReadStartElement();
                if (!isEmptyElement) // (1)
                {
                    Birthday = DateTime.ParseExact(reader.ReadElementString("Birthday"), "yyyy-MM-dd", null);
                    reader.ReadEndElement();
                }
            }
    
            public void WriteXml(System.Xml.XmlWriter writer)
            {
                if (writer == null) throw new ArgumentNullException("writer");
    
                writer.WriteAttributeString("Name", Name);
                if (Birthday != DateTime.MinValue)
                {
                    writer.WriteElementString("Birthday", Birthday.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
                }
            }
        }
        public class Dog : Animal
        {
            public Dog() { }
            public Dog(string name) : base (name) { }
        }
        public class Cat : Animal
        {
            public Cat() { }
            public Cat(string name) : base(name) { }
        }
        public class Mouse : Animal
        {
            public Mouse() { }
            public Mouse(string name) : base (name) { }
        }
    
        public class AnimalList
        {
            private Collection<Animal> listOfAnimals;
    
            public AnimalList() { listOfAnimals = new Collection<Animal>(); }
    
            [XmlElement("Dog", typeof(Dog))]
            [XmlElement("Cat", typeof(Cat))]
            [XmlElement("Mouse", typeof(Mouse))]
            public Collection<Animal> List
            {
                get { return listOfAnimals; } 
            }
        }
    
        public class Farm
        {
            public Farm() { Animals = new AnimalList(); }
    
            public AnimalList Animals { get; set; }
        }
    
    
        class Program
        {
            static void Main()
            {
                try
                {
                    Farm farm = new Farm();
                    string filename = @"..\..\farm.xml";
    
    
                    farm.Animals.List.Add(new Cat("Ati"));
                    farm.Animals.List.Add(new Cat("Gribouille"));
                    farm.Animals.List.Add(new Dog("Joker"));
                    farm.Animals.List.Add(new Cat("Joyeuse"));
                    
                    // Writing the file requires a TextWriter instance.
                    using (TextWriter writer = new StreamWriter(filename))
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(Farm));
                        serializer.Serialize(writer, farm);
                    }
    
                    // Read XML file
                    using (TextReader reader = new StreamReader(filename))
                    {
                        XmlSerializer serializer2 = new XmlSerializer(typeof(Farm));
                        Farm farm2 = (Farm)serializer2.Deserialize(reader);
                        Console.WriteLine("Numer of animals : {0}", farm2.Animals.List.Count);
                        foreach (Animal animal in farm2.Animals.List)
                        {
                            Console.WriteLine("Name : {0}", animal.Name);
                        }
                        Console.WriteLine("Press any key to continue...");
                        Console.ReadKey();
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
        }
    }
    

    and XML :

    <?xml version="1.0" encoding="utf-8"?>
    <Farm xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Animals>
        <Cat Name="Ati" />
        <Cat Name="Gribouille" />
        <Dog Name="Joker" />
        <Cat Name="Joyeuse" />
      </Animals>
    </Farm>

    :)

    Vincent

    Thursday, May 21, 2015 4:14 PM