使用XDocument作为XmlSerializer.Deserialize的源?

时间:2009-08-18 16:34:59

标签: .net linq-to-xml

我想调用XmlSerializer.Deserialize传递XDocument。它可能需要StreamXmlReaderTextReader

我是否可以从XDocument生成以上其中一项而不实际将XDocument转储到某个中间商店,例如MemoryStream

似乎我所追求的是XmlReader的实现与XDocument一起使用。我找不到一个。

5 个答案:

答案 0 :(得分:48)

您可以使用XDocument.CreateReader()创建一个XmlReader来读取XDocument的内容。

同样,以下内容也适用。

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

答案 1 :(得分:12)

这是一个将对象序列化和反序列化到XDocument中的实用程序。

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

这是班级:

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;
    }
}

答案 2 :(得分:4)

(Steve Guidi回答的附录)

据我所知,没有XmlReader的实现,您可以轻松地使用XDocument而不通过中间存储移动XML内容,如XML的字符串表示和支持所有类型,例如System.Xml.XmlNodeReader支持。

XDocument.CreateReader(一个System.Xml.Linq.XNodeReader,一个内部类)返回的阅读器是XmlReader,适用于大多数Xml文档,但不适用于具有二进制数据元素的文档,因为它实施does not support Base64 or BinHex data

  

不支持Base64和BinHex数据。如果您尝试检索   这些类型的数据(例如,通过调用   ReadElementContentAsBase64),读者将抛出   NotSupportedException异常。

XDocument.CreateReader().CanReadBinaryContent形成鲜明对比的是,此false System.Xml.XmlNodeReaderpublic 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) } } }

例如,该程序抛出异常:

string

但是,将XML解压缩为TextReader并将其作为 using (var reader = new StringReader(document.ToString())) 传递到序列化程序中:

XDocument

如果有另一种方法来反序列化包含二进制数据的{{1}}而不将其首先转换为字符串,我也会感兴趣。

答案 3 :(得分:0)

我想在创建XmlReader后添加它,即:

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

然后你应该打电话:

reader.MoveToContent();

因为否则读者不会“指向”第一个节点,导致空读者出现!然后你可以安全地调用反序列化:

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

答案 4 :(得分:0)

我喜欢@Simon_Weaver的答案。基于此,这是我的总结:

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
    }
}