como-serializar-y-deserializar-ficheros-xml-en-c

Cómo serializar y deserializar ficheros XML en C#

En esta entrada vamos a ver cómo serializar y deserializar un objeto a un fichero XML en C#.

Ya vimos cómo trabajar con ficheros Json cómodamente en .NET gracias a la librería de JsonNET. Los ficheros Json se han convertido en el estándar preferido para intercambiar datos entre aplicaciones, especialmente en ámbitos web.

Sin embargo, el formato XML sigue siendo ampliamente utilizado, y existen muchas situaciones en las que resulta interesante poder generarlos o leerlos.

Afortunadamente trabajar con ficheros XML en C# es extremadamente sencillo, y no es necesario emplear librerías de terceros ya que las herramientas necesarias están integradas en el propio .NET.

Así, supongamos que queremos trabajar con la siguiente clase de ejemplo.

public class myItem
{
  public string Texto { get; set; }
  public int Numero { get; set; }
  public double Decimal { get; set; }

  public List<mySubItem> SubItems { get; set; } = new List<mySubItem>();
}

Que, a su vez, contiene una colección de la siguiente clase.

public class mySubItem
{
  public string SubTexto { get; set; }
  public int SubNumero { get; set; }
}

Primera solución

Serializar un objeto a un fichero XML, o el caso contrario, deserializar un fichero XML a un objeto, es tan sencillo como lo siguiente.

static void Main(string[] args)
{
  var item = new myItem
  {
    Texto = "A",
    Numero = 10,
    Decimal = 20.5,
    SubItems =
    {
       new mySubItem {SubTexto = "A.A", SubNumero = 100},
       new mySubItem {SubTexto = "A.B", SubNumero = 200},
       new mySubItem {SubTexto = "A.C", SubNumero = 300},
    }
  };
  saveToXML(item, "export.xml");
  var newItem = loadFromXML("export.xml");
}

public static void saveToXML(myItem item, string path)
{
  XmlSerializer xmlSerializer = new XmlSerializer(typeof(myItem));
  using (var writer = XmlWriter.Create(path, new XmlWriterSettings { Indent = true }))
  {
    xmlSerializer.Serialize(writer, item);
  }
}

public static myItem loadFromXML(string path)
{
  var xmlSerializer = new XmlSerializer(typeof(myItem));

  using (var reader = XmlReader.Create(path))
  {
    return xmlSerializer.Deserialize(reader) as myItem;
  }
}

Donde, como vemos, hemos empleado dos métodos ‘saveToXML’ y ‘loadFromXML’ para realizar la serialización y deserialización respectivamente a nuestra clase de ejemplo ‘myItem’.

Con métodos genéricos

Aún podemos hacer el código más sencillo y reutilizable si convertimos estas funciones en funciones genéricas, de forma que trabajen con cualquier clase.

De esta forma, el código necesario para trabajar con ficheros XML para cualquier clase quedaría de la siguiente forma.

static void Main(string[] args)
{
  var item = new myItem
  {
    Texto = "A",
    Numero = 10,
    Decimal = 20.5,
    SubItems =
    {
       new mySubItem {SubTexto = "A.A", SubNumero = 100}    ,
       new mySubItem {SubTexto = "A.B", SubNumero = 200}    ,
       new mySubItem {SubTexto = "A.C", SubNumero = 300}    ,
    }
  };
  saveToXML(item, "export.xml");
  var newItem = loadFromXML<myItem>("export.xml");
}

public static void saveToXML<T>(T item, string path)
{
  XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
  using (var writer = XmlWriter.Create(path, new XmlWriterSettings { Indent = true }))
  {
    xmlSerializer.Serialize(writer, item);
  }
}

public static T loadFromXML<T>(string path) where T: class
{
  var xmlSerializer = new XmlSerializer(typeof(T));

  using (var reader = XmlReader.Create(path))
  {
    return xmlSerializer.Deserialize(reader) as T;
  }
}

Con métodos de extensión

Finalmente, si sacamos estos métodos generales a un fichero externo como métodos de extensión, el código aún queda más sencillo y reusable, quedando así.

public static class Extensions
{
    public static void SerializeToXml<T>(this T instance, string filename) where T : class, new()
    {
        var serializer = new XmlSerializer(typeof(T));
        using (var stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
        {
            serializer.Serialize(stream, instance);
        }
    }

    public static T DeserializeFromXml<T>(this string filePath) where T : class, new()
    {
        using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            stream.Position = 0;
            var serializer = new XmlSerializer(typeof (T));
            return serializer.Deserialize(stream) as T;
        }
    }
}

Que se usaría así

    class Program
    {
        static void Main(string[] args)
        {
            var item = new myItem
            {
                Texto = "A",
                Numero = 10,
                Decimal = 20.5,
                SubItems =
                {
                     new mySubItem {SubTexto = "A.A", SubNumero = 100}    ,
                     new mySubItem {SubTexto = "A.B", SubNumero = 200}    ,
                     new mySubItem {SubTexto = "A.C", SubNumero = 300}    ,
                }
            };

            item.SerializeToXml("export.xml");
            var newItem = "export.xml".DeserializeFromXml<myItem>();
        }
    }

Podemos añadir estos métodos a nuestra colección de clases de extensión para trabajar de forma sencilla y cómoda con ficheros XML en .NET.