Serialización XML en C#

Ejemplo básico de serialización de un objeto a formato XML usando la clase XmlSerializer:

using System.IO;
using System.Xml.Serialization;
using System.Text;

// Definición de clases de ejemplo
public class DatosPrincipales
{
    public string Identificador { get; set; }
    public int Valor { get; set; }
    public ElementoSecundario[] Elementos { get; set; }
}

public class ElementoSecundario
{
    public double Cantidad { get; set; }
}

// Crear instancia y configurar datos
var instancia = new DatosPrincipales();
instancia.Identificador = "456";
instancia.Valor = 789;
instancia.Elementos = new ElementoSecundario[2];
instancia.Elementos[0] = new ElementoSecundario { Cantidad = 123.45 };
instancia.Elementos[1] = new ElementoSecundario { Cantidad = 678.90 };

// Serializar a flujo de memoria
var serializador = new XmlSerializer(typeof(DatosPrincipales));
using (var flujoMemoria = new MemoryStream())
{
    serializador.Serialize(flujoMemoria, instancia);
    flujoMemoria.Position = 0;

    // Convertir a cadena UTF-8
    using (var lector = new StreamReader(flujoMemoria, Encoding.UTF8))
    {
        string xmlResultado = lector.ReadToEnd();
        System.Console.WriteLine(xmlResultado);
    }
}

Para deserializar un objeto desde una cadena XML:

string xmlEntrada = xmlResultado; // Cadena XML obtenida previamente
var deserializador = new XmlSerializer(typeof(DatosPrincipales));
using (var lectorCadena = new StringReader(xmlEntrada))
{
    var objetoDeserializado = (DatosPrincipales)deserializador.Deserialize(lectorCadena);
    // Utilizar objetoDeserializado según necesidad
}

Clase auxiliar para simplificar operaciones de serialización:

using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;

public static class UtilidadesXml
{
    // Operaciones con memoria
    public static T DeserializarDesdeFlujo<T>(Stream flujo)
    {
        var serializador = new XmlSerializer(typeof(T));
        return (T)serializador.Deserialize(flujo);
    }

    public static Stream SerializarAFlujo(object objeto)
    {
        var serializador = new XmlSerializer(objeto.GetType());
        var flujo = new MemoryStream();
        serializador.Serialize(flujo, objeto);
        flujo.Position = 0;
        return flujo;
    }

    // Operaciones con archivos en disco
    public static T DeserializarDesdeArchivo<T>(string rutaArchivo)
    {
        string contenidoXml = File.ReadAllText(rutaArchivo);
        return DeserializarDesdeCadena<T>(contenidoXml);
    }

    public static void SerializarAArchivo(string rutaArchivo, object objeto, Encoding codificacion)
    {
        string resultadoXml = SerializarACadena(objeto);
        if (File.Exists(rutaArchivo)) File.Delete(rutaArchivo);
        File.WriteAllText(rutaArchivo, resultadoXml, codificacion);
    }

    // Operaciones con cadenas
    public static T DeserializarDesdeCadena<T>(string xml)
    {
        var serializador = new XmlSerializer(typeof(T));
        using (var lector = new StringReader(xml))
        {
            return (T)serializador.Deserialize(lector);
        }
    }

    public static string SerializarACadena(object objeto)
    {
        var serializador = new XmlSerializer(objeto.GetType());
        using (var flujo = new MemoryStream())
        {
            serializador.Serialize(flujo, objeto);
            flujo.Position = 0;
            using (var lector = new StreamReader(flujo, Encoding.UTF8))
            {
                return lector.ReadToEnd();
            }
        }
    }
}

Consideraciones importantes para la serialización XML:

  1. Las clases deben tener un constructor sin parámetros para permitir la deserialización.
  2. Para tipos complejos no serializables directamente, se requiere aplicar atributos especiales e impleemntar la interfaz IXmlSerializable. Consultar documentación de Microsoft para detalles.
  3. No se admiten campos de solo lectura en la serialización.
  4. El soporte para tipos anulables (nullable) en la serialización nativa es limitado; se recomienda evitarlos.
  5. El atributo [XmlIgnore] permite excluir miembros específicos del proceso de serialización.
  6. Los tipos Dictionary no son soportados directamente. Se puede usar una implementación personalizada como se muestra a continuación.
  7. Se soporta la serialización de clases abstractas mediante el uso de atributos de tipo conocido.
  8. Colecciones como ArrayList y Hashtable tienen soporte deficiente; por ejemplo, ArrayList solo funciona con tipos de valor.
  9. Para resolver errores de tipo no primitivo, se debe proporcionar un arreglo de tipos adicionales al constructor de XmlSerializer.
  10. Las propiedades pueden serializarse si disponen de métodos get y set.

Ejemplo de diccionario serializable personalizado:

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

[XmlRoot("diccionario"), Serializable]
public class DiccionarioSerializable<ClaveT, ValorT>
    : Dictionary<ClaveT, ValorT>, IXmlSerializable
{
    public DiccionarioSerializable() { }

    public DiccionarioSerializable(IDictionary<ClaveT, ValorT> diccionario)
        : base(diccionario) { }

    public DiccionarioSerializable(IEqualityComparer<ClaveT> comparador)
        : base(comparador) { }

    public DiccionarioSerializable(int capacidad)
        : base(capacidad) { }

    public DiccionarioSerializable(int capacidad, IEqualityComparer<ClaveT> comparador)
        : base(capacidad, comparador) { }

    public XmlSchema GetSchema() => null;

    public void ReadXml(XmlReader lector)
    {
        var serializadorClave = new XmlSerializer(typeof(ClaveT));
        var serializadorValor = new XmlSerializer(typeof(ValorT));
        bool estabaVacio = lector.IsEmptyElement;
        lector.Read();

        if (estabaVacio) return;

        while (lector.NodeType != XmlNodeType.EndElement)
        {
            lector.ReadStartElement("elemento");
            lector.ReadStartElement("clave");
            var clave = (ClaveT)serializadorClave.Deserialize(lector);
            lector.ReadEndElement();
            lector.ReadStartElement("valor");
            var valor = (ValorT)serializadorValor.Deserialize(lector);
            lector.ReadEndElement();
            Add(clave, valor);
            lector.ReadEndElement();
            lector.MoveToContent();
        }
        lector.ReadEndElement();
    }

    public void WriteXml(XmlWriter escritor)
    {
        var serializadorClave = new XmlSerializer(typeof(ClaveT));
        var serializadorValor = new XmlSerializer(typeof(ValorT));
        foreach (ClaveT clave in Keys)
        {
            escritor.WriteStartElement("elemento");
            escritor.WriteStartElement("clave");
            serializadorClave.Serialize(escritor, clave);
            escritor.WriteEndElement();
            escritor.WriteStartElement("valor");
            ValorT valor = this[clave];
            serializadorValor.Serialize(escritor, valor);
            escritor.WriteEndElement();
            escritor.WriteEndElement();
        }
    }
}

Etiquetas: XML C# Serialización .NET Framework XmlSerializer

Publicado el 5-29 20:14