2008-12-18 10 views
18

Tengo una clase simple que hereda de Collection y agrega un par de propiedades. Necesito serializar esta clase a XML, pero XMLSerializer ignora mis propiedades adicionales.XmlSerialice una colección personalizada con un Atributo

Supongo que esto se debe al trato especial que XMLSerializer brinda a los objetos ICollection e IEnumerable. ¿Cuál es la mejor manera de evitar esto?

He aquí algunos ejemplos de código:

using System.Collections.ObjectModel; 
using System.IO; 
using System.Xml.Serialization; 

namespace SerialiseCollection 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var c = new MyCollection(); 
      c.Add("Hello"); 
      c.Add("Goodbye"); 

      var serializer = new XmlSerializer(typeof(MyCollection)); 
      using (var writer = new StreamWriter("test.xml")) 
       serializer.Serialize(writer, c); 
     } 
    } 

    [XmlRoot("MyCollection")] 
    public class MyCollection : Collection<string> 
    { 
     [XmlAttribute()] 
     public string MyAttribute { get; set; } 

     public MyCollection() 
     { 
      this.MyAttribute = "SerializeThis"; 
     } 
    } 
} 

Esto genera el siguiente código XML (tenga en cuenta MyAttribute no se encuentra en el elemento MiColeccion):

<?xml version="1.0" encoding="utf-8"?> 
<MyCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <string>Hello</string> 
    <string>Goodbye</string> 
</MyCollection> 

Lo que quieren es

<MyCollection MyAttribute="SerializeThis" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <string>Hello</string> 
    <string>Goodbye</string> 
</MyCollection> 

¿Alguna idea? Cuanto más simple, mejor. Gracias.

Respuesta

13

Las colecciones en general no son buenos lugares para las propiedades adicionales. Tanto durante la serialización como en el enlace de datos, se ignorarán si el elemento se ve como una colección (IList, IEnumerable, etc., según el caso).

Si fuera yo, me gustaría encapsular la colección - es decir,

[Serializable] 
public class MyCollectionWrapper { 
    [XmlAttribute] 
    public string SomeProp {get;set;} // custom props etc 
    [XmlAttribute] 
    public int SomeOtherProp {get;set;} // custom props etc 
    public Collection<string> Items {get;set;} // the items 
} 

La otra opción es poner en práctica IXmlSerializable (bastante mucho trabajo), pero que todavía no funcionará para enlace de datos, etc. Básicamente, este no es el uso esperado.

0

He estado peleando con el mismo problema que Romaroo (querer agregar propiedades a la serialización xml de una clase que implemente ICollection). No he encontrado ninguna forma de exponer las propiedades que están en la clase de colección. Incluso intenté usar la etiqueta XmlAttribute y hacer que mis propiedades aparezcan como atributos del nodo raíz, pero tampoco tuve suerte allí. Sin embargo, pude usar la etiqueta XmlRoot en mi clase para cambiarle el nombre desde "ArrayOf ...". Aquí hay algunas referencias en caso de que esté interesado:

+0

Ver mi solución, puede que le resulte interesante. – toddmo

12

Si encapsular, como sugiere Marc Gravell, el principio de este post explica cómo haz que tu XML se vea exactamente como lo describes.

http://blogs.msdn.com/youssefm/archive/2009/06/12/customizing-the-xml-for-collections-with-xmlserializer-and-datacontractserializer.aspx

Es decir, en lugar de esto:

<MyCollection MyAttribute="SerializeThis" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Items> 
    <string>Hello</string> 
    <string>Goodbye</string> 
    <Items> 
</MyCollection> 

puede tener este:

<MyCollection MyAttribute="SerializeThis" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
    <string>Hello</string> 
    <string>Goodbye</string> 
</MyCollection> 
+0

@ neilwhitaker1: Volví a subir esta respuesta, pero sería aún mejor si describieras la técnica en la respuesta en lugar de obligarnos a leer la publicación del blog. Aún puedes hacer referencia a la publicación. –

+1

La publicación del blog responde muy bien la pregunta con un nivel de detalle apropiado, y la respuesta es fácil de encontrar en la publicación del blog. Creo que los enlaces al blog en este caso son preferibles. – AndrewS

0

Como Neil Whitaker sugiere y en caso de que su enlace muere ..

Crear una colección interna para almacenar las cadenas y aplicar el atributo XmlElement para enmascarar el nombre de la colección. Produce el mismo resultado xml que si MyCollection heredó de Collection, pero también serializa atributos en el elemento principal.

[XmlRoot("MyCollection")] 
public class MyCollection 
{ 
    [XmlAttribute()] 
    public string MyAttribute { get; set; } 

    [XmlElement("string")] 
    public Collection<string> unserializedCollectionName { get; set; } 

    public MyCollection() 
    { 
     this.MyAttribute = "SerializeThis"; 
     this.unserializedCollectionName = new Collection<string>(); 
     this.unserializedCollectionName.Add("Hello"); 
     this.unserializedCollectionName.Add("Goodbye"); 
    } 
} 
Cuestiones relacionadas