2009-08-18 12 views
28

Me gustaría invocar XmlSerializer.Deserialize pasando un XDocument. Puede tomar Stream, XmlReader o TextReader.Utilice XDocument como fuente para XmlSerializer.Deserialize?

¿Puedo generar uno de los anteriores desde XDocument sin realmente tirar el XDocument en una tienda intermedia, como MemoryStream?

Parece que lo que estoy buscando es una implementación de XmlReader que funcione con XDocument. No puedo encontrar uno sin embargo.

+0

Ver también http://stackoverflow.com/q/7901558/11912 –

Respuesta

43

Puede usar XDocument.CreateReader() para crear un XmlReader que lea el contenido del XDocument.

Equivalentemente, lo siguiente también funcionará.

XmlReader GetReader(XDocument doc) 
{ 
    return doc.Root.CreateReader(); 
} 
0

sólo pensé que debería añadir que una vez creado el XmlReader, es decir:

XmlSerializer serializer = new XmlSerializer(typeof(MyObject)); 
XmlReader reader = xmlDocumentToDeserialize.CreateReader(); 

entonces usted debe llamar:

reader.MoveToContent(); 

porque de lo contrario el lector no va a "punto" a el primer nodo, causando la apariencia de un lector vacío A continuación, puede llamar de manera segura Deserialize:

MyObject myObject = (MyObject)serializer.Deserialize(reader); 
9

Aquí hay una utilidad para serializar y deserializar objetos a/desde XDocument.

XDocument doc = SerializationUtil.Serialize(foo); 
Foo foo = SerializationUtil.Deserialize<Foo>(doc); 

Aquí está la clase:

public static class SerializationUtil 
{ 
    public static T Deserialize<T>(XDocument doc) 
    { 
     XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 

     using (var reader = doc.Root.CreateReader()) 
     { 
      return (T)xmlSerializer.Deserialize(reader); 
     } 
    } 

    public static XDocument Serialize<T>(T value) 
    { 
     XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 

     XDocument doc = new XDocument(); 
     using (var writer = doc.CreateWriter()) 
     { 
      xmlSerializer.Serialize(writer, value); 
     } 

     return doc; 
    } 
} 
3

(Anexo a la respuesta de Steve Guidi)

Por lo que yo puedo ver que no hay aplicación de XmlReader puede utilizar simplemente con XDocument sin mover el Contenido XML a través de una tienda intermedia como una representación de cadena de XML y que admite todos los tipos que, por ejemplo, admite System.Xml.XmlNodeReader.

El lector devuelto por XDocument.CreateReader (que es un System.Xml.Linq.XNodeReader, una clase interna) es una XmlReader y funciona para la mayoría de documentos XML, pero no con los documentos que tienen elementos de datos binarios, ya que su aplicación does not support Base64 or BinHex data:

base 64 y Los datos BinHex no son compatibles. Si intenta recuperar este tipo de datos (por ejemplo, llamando al ReadElementContentAsBase64), el lector arrojará NotSupportedException.

Para este lector XDocument.CreateReader().CanReadBinaryContent es false en contraste con la System.Xml.XmlNodeReader.

Por ejemplo este programa genera una excepción:

public class SomeTest 
{ 
    public byte[] BinaryTest { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     XDocument document = new XDocument(
      new XElement("SomeTest", 
       new XElement("BinaryTest", "VGVzdA=="))); 

     using (var reader = document.CreateReader()) 
     { 
      var serializer = new XmlSerializer(typeof(SomeTest)); 
      var someTest = serializer.Deserialize(reader) as SomeTest; 
      // NotSupportedException here (as inner exception) 
     } 
    } 
} 

Sin embargo, extraer el XML como string y haciéndola pasar como TextReader en el serializador funciona:

 using (var reader = new StringReader(document.ToString())) 

estaría interesado también si hay otra manera de deserializar un XDocument que incluye datos binarios sin convertirlo primero en una cadena.

+0

Tenía la esperanza de encontrar una solución para esto. Tengo un poco de contenido xml con datos binarios, lo que hará que todo sea mucho más lento. un disparo redondo a una cuerda parece una locura. Creo que podría tratar de negociar dejando caer el contenido de byte [] por completo en lugar de tomar el golpe de rendimiento. – Jim

0

Me gusta la respuesta de @Simon_Weaver la mejor. Sobre la base de que este es mi resumen:

using System; 
using System.Xml.Linq; 
using System.Xml.Serialization; 

namespace XDocSerialization 
{ 
    [TestClass] 
    public class Tests 
    { 
     [TestMethod] 
     public void Tests_SerializeToXDoc() 
     { 
      var sheep = new Animal 
      { 
       Name = "Sheep", Legs = 4, Nutrition = Nutrition.Herbivore 
      }; 
      var xdoc = sheep.SerializeToXDoc(); 
      var ser = "<Animal " + 
         "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + 
         "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n " + 
         "<Name>Sheep</Name>\r\n <Legs>4</Legs>\r\n " + 
         "<Nutrition>Herbivore</Nutrition>\r\n</Animal>"; 

      Assert.AreEqual(xdoc.ToString(), ser); 
      Assert.IsInstanceOfType(xdoc, typeof(XDocument)); 
     } 

     [TestMethod] 
     public void Tests_DeserializeFromXDoc() 
     { 
      var Sheep = new Animal 
      { 
       Name = "Sheep", Legs = 4, Nutrition = Nutrition.Herbivore 
      }; 
      var des = Sheep.SerializeToXDoc().DeserializeFromXDoc<Animal>(); 

      Assert.AreEqual(des.Name, Sheep.Name); 
      Assert.AreEqual(des.Nutrition, Sheep.Nutrition); 
      Assert.AreEqual(des.Legs, Sheep.Legs); 
      Assert.AreNotSame(des, Sheep); 
     } 
    } 

    public static class ExtensionMethods 
    { 
     public static T DeserializeFromXDoc<T>(this XDocument source) 
     { 
      if (source == null || source.Root == null) 
       return default(T); 

      using (var reader = source.Root.CreateReader()) 
       return (T)new XmlSerializer(typeof(T)).Deserialize(reader); 
     } 

     public static XDocument SerializeToXDoc<T>(this T source) 
     { 
      if (source == null) 
       return null; 

      var doc = new XDocument(); 
      using (var writer = doc.CreateWriter()) 
       new XmlSerializer(typeof(T)).Serialize(writer, source); 

      return doc; 
     } 
    } 

    [Serializable] 
    public class Animal 
    { 
     public string Name { get; set; } 
     public int Legs { get; set; } 
     public Nutrition Nutrition { get; set; } 
    } 

    public enum Nutrition 
    { 
     Herbivore, 
     Carnivore, 
     Omnivore 
    } 
} 
Cuestiones relacionadas