implement Ixmlserializable interface in a class

Asked

Viewed 223 times

1

I have a class and need to implement data serialization and deserialization in an XML structure using IXmlSerializable, for this in my class I have to implement the methods, GetSchema(), ReadXml(XmlReader), WriteXml(XmlWriter), of Interface IXmlSerializable, someone knew me how would be the implementation of these methods based on my class?

namespace XmlSerializationSample
{
    public class Order : IXmlSerializable
    {
        #region Local Variables

        private List<OrderDetails> _items = new List<OrderDetails>();

        #endregion

        #region Properties

        /// <summary>
        /// Identificador do pedido.
        /// </summary>
        public int OrderId { get; set; }

        /// <summary>
        /// Cliente associado.
        /// </summary>
        public Customer Customer { get; set; }

        /// <summary>
        /// Data do pedido.
        /// </summary>
        public DateTime OrderDate { get; set; }

        /// <summary>
        /// Itens do pedido.
        /// </summary>
        public List<OrderDetails> Items
        {
            get { return _items; }
        }

        public XmlSchema GetSchema() { return null; }

        public void WriteXml(XmlWriter writer)
        {

        }

        public void ReadXml(XmlReader reader)
        {

        }


        #endregion
    }
}
  • You need to actually implement the methods or just serialize the class instances?

  • serealizar the instances of the class.

  • I’ve already sent you an answer, you need to consider culture in xml?

  • opa, bacana. xml culture, not understood !

  • Serialization is the act of representing an object (fully) in a serial format, but often one uses an XML for other tasks (sending to a Webservice, etc.) and in such cases, it is necessary that the XML reflects a specific culture, that goes against the concept of representing the object faithfully in the chosen serialization format (XML), there is a problem.

  • ha understood, need yes!

  • Take a look at the answer and see if it fits you

Show 2 more comments

3 answers

2


Well, first we have to be careful with the concept of Serialize, after all, XML is used for a lot of things nowadays and people tend to call it serializing any action that generates an XML, conceptually this is kind of wrong.

According to Wikipedia:

"...serialization is the process of Translating data Structures or Object state into a format that can be stored"

Wikipedia

In free translation:

"Serialization is the process of translating (or transforming) the state (usually in memory) of data structures or objects in a format that can be stored."

That is, you can take an object and generate an Array of Bytes to send over the network, you can generate array of bytes to store in a file on the disk, send parameters of a process over the network to run on another server or simply generate an XML to store on disk or send to a Webservice.

MSDN has other examples of serialization needs, take a look later (MSDN), the important issue here is that serialization should be a method of representing a copy of the object.

There begins the problem of using the serialization classes of . net for other things, also has the problem that often system designers fail to make clear some concepts in the place to which you send the serialized object (usually a subsystem that you have to communicate but, which has not designed).

I have seen cases where the subsystem varied the date culture differently in different places.

Let’s go to an example code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

namespace serialTest
{
    [XmlRoot("Casa")]
    public class Casa
    {
        int? id;
        [XmlIgnoreAttribute]
        public int? ID
        {
            get { return id; }
            set { id = value; }
        }

        string cor;
        [XmlElement("cor")]
        public string Cor
        {
          get { return cor; }
          set { cor = value; }
        }

        //mesmo atributo, duas propriedades.
        DateTime dataConstrucaoPadrao;
        [XmlElement("dataConstrucaoPadrao")]
        public DateTime DataConstrucaoPadrao
        {
            get { return dataConstrucaoPadrao; }
            set { dataConstrucaoPadrao = value; }
        }

        [XmlElement("dataConstrucaoComCultura")]
        public string DataConstrucaoComCultura
        {
            get { return dataConstrucaoPadrao.ToString(); }
            set { dataConstrucaoPadrao = Convert.ToDateTime(value); }
        }
        //fim do teste de cultura

        [XmlElement("Sala")]
        public Sala sala;
    }
}

Now a smaller class for a child element in the Home XML:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

namespace serialTest
{
    [XmlRoot("Sala")]
    public class Sala
    {
        int? id;
        [XmlIgnoreAttribute]
        public int? ID
        {
            get { return id; }
            set { id = value; }
        }

        int quantJanelas;
        [XmlElement("QuantJanelas")]
        public int QuantJanelas
        {
            get { return quantJanelas; }
            set { quantJanelas = value; }
        }
    }
}

My Main method of the Console application prints XML on the screen:

using System;
using System.Collections.Generic;
using System.Text;
using serialTest;

namespace ConsoleTestSerial
{
    class Program
    {
        static void Main(string[] args)
        {
            Casa c;

            c = new Casa();

            c.Cor = "Vermelho";
            c.ID = 1;

            c.DataConstrucaoPadrao = DateTime.Now;

            c.sala = new Sala();
            c.sala.QuantJanelas = 2;
            c.sala.ID = 1;

            string resultSerial = UtilSerial.Serialize<Casa>(c);

            Console.WriteLine( resultSerial);
            Console.ReadLine();
        }
    }
}

And the generated XML:

<Casa>
  <Sala>
    <QuantJanelas>2</QuantJanelas>
  </Sala>
  <cor>Vermelho</cor>
  <dataConstrucaoPadrao>2016-11-03T14:25:17.5677191-03:00</dataConstrucaoPadrao>
  <dataConstrucaoComCultura>03/11/2016 14:25:17</dataConstrucaoComCultura>
</Casa>

The code that generates the XML is missing, but I’m going to leave it at the end because basically it doesn’t matter, since I use a generic and static method to serialize or deserialize, the problem is the way I wrote the classes and let’s focus on that.

Starting with the problems:

1. Serialization classes are made to serialize (generate a copy) and try to ensure that you don’t worry about the rest, so they use invariant culture, if you need to vary the culture, do it yourself.

It is no use to set the application and thread culture if the code of the class that will be serialized does not have an adaptation.

See for example the attribute Datetime dataConstrucaoPadrao of the House Class, change your code to use properties, you are using the attributes publicly, besides being an anti-standard, you will have problems serializing because you will need to change the return without changing the data type. Apply refactoring to your code and carry it forward in other projects.

Notice i Gero two interpretations of the attribute in XML, using proprieades, one reflects the culture and the other not, however, are the same attribute.

This is possible because the standard culture is applied when serializing a datetime, but I create a string property that returns the . Tostring of the date, then will be serialized the result of Tostring and not the date, then Tostring uses the culture of Thread before serialize, in my case, en.

So, if you need to generate XML in a specific culture, use a String attribute and return the Tostring attribute.

I know this culture in front, wait a minute.

2. Objects often have attributes that you do not want to send in XML if you are generating it to go to another system.

Note that the ID attribute of my classes needs to exist to identify the object in my system (and probably in the database) but, it is not a useful attribute in my XML (I don’t even put it there).

good, ai is easy, just use [Xmlignoreattribute] and ta all beauty, just not.

First, there is a conceptual problem, my XML is no longer a copy of the object that existed in memory, so I can no longer guarantee that I can reproduce the state of the application before generating XML, if I need to reverse the process, You’ll have trouble knowing who’s who in the database or elsewhere. Then the ID attribute will need to be null on the return, so it needs to be null.

Generally, in these situations there is some field that is part of the business rule that may be used as primary key (CPF, RG, etc).

But, you’re using serialization outside the definition of serialization.

So why should I use these classes? Well, you know whether or not to use.

It is very easy to put an attribute in the class and generate an XML with the generic method, so ease is sometimes better than perfection. A simple application, which will run only for a small table or routine, can be done in a few minutes instead of days.

The problem is usually maintenance.

And finally, the generic class to serialize:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Globalization;
using System.Threading;

namespace serialTest
{
    public class UtilSerial
    {
        public static string Serialize<T>(T dataToSerialize)
        {
            try
            {
                CultureInfo n = new CultureInfo("pt-br");
                Thread.CurrentThread.CurrentCulture = n;
                Thread.CurrentThread.CurrentUICulture = n;

                var serializer = new XmlSerializer(typeof(T));
                var stringwriter = new System.IO.StringWriter();

                var ns = new XmlSerializerNamespaces();
                ns.Add("", "");

                var xmlWriter = XmlWriter.Create(stringwriter, new XmlWriterSettings() { OmitXmlDeclaration = true });

                serializer.Serialize(xmlWriter, dataToSerialize, ns);

                return stringwriter.ToString();
            }
            catch(Exception e)
            {
                throw e;
            }
        }

        public static T Deserialize<T>(string xmlText)
        {
            try
            {
                CultureInfo n = new CultureInfo("pt-br");
                Thread.CurrentThread.CurrentCulture = n;
                Thread.CurrentThread.CurrentUICulture = n;

                var stringReader = new System.IO.StringReader(xmlText);
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(stringReader);
            }
            catch(Exception e)
            {
                throw e;
            }
        }
    }
}

Here many factors are already clear when we look at the code, I think only the issue of culture is worth an addendum.

These methods will generate representations of attributes with different cultures. All attributes / properties that are defined in the class in order to have a return of a standard type (int, string, datetime, etc.) will be represented with invariant culture, those that return some method that uses crop to generate output (usually Tostring), will have their output in the culture being configured in the thread of these methods, in this case, en.

The same goes for the entrance.

Basic concepts:

  • [Xmlroot("Room")] - XML root, use in class definition.
  • [Xmlelement("color")] - In XML, use on XML nodes.

For attributes that are Generic Object Lists:

  • [Xmlarray("Rooms")] - Generates the root attribute of the list
  • [Xmlarrayitem("Room")] - generates each item in the list

In this case, if our House class had a list of Rooms:

private List<Sala> salas;
[XmlArray("Salas")]
[XmlArrayItem("Sala")]
public List<Sala> Salas
{
       get { return salas; }
       set { salas = value; }
}

Well, to finish, using this structure, every time you need to generate an XML of a class just define the attributes and call the methods of the Utilserial class and you are ready.

A good conversation about Marshall Cline’s C++ Serialization.

1

In most cases it is not necessary to implement IXmlSerializable.

Instances of relatively simple classes like yours can be serialized directly by XMLSerializer hassle-free.

If the xml resulting from standard serialization does not meet your need, certain attributes can be applied to its class elements to refine the serialization process.

  • I understand, this class is very simple, in this case it’s just a study so that I can serialize an entire entity, of much greater commonality, so I wanted to understand how to serealizar the attributes of my class, in the method.

  • Would it be something like that? public void Readxml(Xmlreader Reader) { this.Orderid = Reader.Getattribute("Rid ")&#ordeXa; }

  • @fernandotso Read Ixmlserializable documentation on MSDN. There are 2 rare situations where it is necessary to implement this interface. If in fact it is still necessary to implement it, use the methods' Reader/Writer parameters to read/write the xml, respectively.

0

follows an example I used to Serialize and Deserialize an XML using C#

    [Serializable]
        [XmlRoot("Pessoa"), XmlType("Pessoa")]
        public class Pessoa
        {
            [XmlAttribute("id")]
            public string Id { get; set; }

            [XmlAttribute("Data")]
            public string Data { get; set; }

            [XmlElement("DadosPessoais")]
            public DadosPessoais DadosPessoais { get; set; }
        }

        public class DadosPessoais
        {
            [XmlElement("Nome")]
            public string Nome { get; set; }

            [XmlElement("Email")]
            public string Email { get; set; }

            [XmlElement("CPF")]
            public string Cpf { get; set; }

            [XmlElement("Endereco")]
            public Endereco Endereco { get; set; }
        }

        public class Endereco
        {
            [XmlElement("Bairro")]
            public string Bairro { get; set; }

            [XmlElement("Cidade")]
            public string Cidade { get; set; }

            [XmlElement("Estado")]
            public string Estado { get; set; }

            [XmlElement("Cep")]
            public string Cep { get; set; }
        }


    public class XmlWorkReader
        {
            private string _fullpath;

            public XmlWorkReader(string _fullpath)
            {
                this._fullpath = _fullpath;
            }

            public void ConvertXMltoClass<TXml>()
            {
                using (XmlReader reader = XmlReader.Create(_fullpath))
                {
                    XmlSerializer xs = new XmlSerializer(typeof(TXml));
                    TXml txml = (TXml)xs.Deserialize(reader);
                }
            }
        }




 public class XmlWorkWriter
    {
        private XmlSerializer _xmlSerializer;
        private string _path;
        private string _filename;
        private string _fullpath;

        public XmlWorkWriter(string _path, string _filename)
        {
            this._path = _path;
            this._filename = _filename;
            _fullpath = Path.Combine(_path, _filename + ".xml");
        }


        public void XmlWrite<Txml>(Txml xml)
        {
            try
            {
                using (TextWriter writer = new StreamWriter(_fullpath))
                {
                    _xmlSerializer = new XmlSerializer(typeof(Txml));
                    _xmlSerializer.Serialize(writer, xml);
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }

    }

example on github https://github.com/EduardoSampaio/Projeto-Serializando-Deserializando-XML

Browser other questions tagged

You are not signed in. Login or sign up in order to post.