.net 使用 XDocument 作为 XmlSerializer.Deserialize 的源?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1295046/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 13:10:08  来源:igfitidea点击:

Use XDocument as the source for XmlSerializer.Deserialize?

.netlinq-to-xml

提问by Roman Starkov

I would like to invoke XmlSerializer.Deserializepassing it an XDocument. It can take a Stream, an XmlReaderor a TextReader.

我想调用XmlSerializer.Deserialize将它传递给XDocument. 它可以采用 a Stream、 anXmlReader或 a TextReader

Can I generate one of the above from XDocumentwithout actually dumping the XDocumentinto some intermediate store, such as a MemoryStream?

我可以在XDocument不实际将其转储XDocument到某些中间存储中的情况下生成上述之一MemoryStream吗?

It seems that what I'm after is an implementation of XmlReaderthat works with an XDocument. I can't find one though.

似乎我所追求的是一个XmlReaderXDocument. 虽然我找不到。

回答by Steve Guidi

You can use XDocument.CreateReader()to create an XmlReaderthat reads the contents of the XDocument.

您可以使用XDocument.CreateReader()创建一个XmlReader读取XDocument.

Equivalently, the following will work too.

同样,以下也将起作用。

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

回答by Simon_Weaver

Here's a utility to serialize and deserialize objects to/from XDocument.

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

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

Here's the class:

这是课程:

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

回答by Slauma

(Appendix to Steve Guidi's answer)

(Steve Guidi 回答的附录)

As far as I can see there is no implementation of XmlReaderyou can easily use with XDocumentwithout moving the XML content through an intermediate store like a string representation of the XML and that supports all typesthat for example the System.Xml.XmlNodeReadersupports.

据我所知,没有任何实现XmlReader可以轻松使用,XDocument而无需通过中间存储移动 XML 内容,例如XML 的字符串表示形式,并且支持所有类型,例如System.Xml.XmlNodeReader支持的类型

The reader returned by XDocument.CreateReader(which is a System.Xml.Linq.XNodeReader, an internal class) is a XmlReaderand works for most Xml document but not with documents that have binary data elements because its implementation does not support Base64 or BinHex data:

XDocument.CreateReader(它是一个System.Xml.Linq.XNodeReader内部类)返回的读取器是 aXmlReader并且适用于大多数 Xml 文档,但不适用于具有二进制数据元素的文档,因为它的实现不支持 Base64 或 BinHex 数据

Base64 and BinHex data are not supported. If you attempt to retrieve these types of data (for example, by calling ReadElementContentAsBase64), the reader will throw NotSupportedException.

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

For this reader XDocument.CreateReader().CanReadBinaryContentis falsein contrast to the System.Xml.XmlNodeReader.

对于这位读者XDocument.CreateReader().CanReadBinaryContentfalse相反的System.Xml.XmlNodeReader

For example this program throws an exception:

例如这个程序抛出一个异常:

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

However, extracting the XML as stringand passing it as TextReaderinto the serializer works:

但是,将 XML 提取为string并将其作为传递TextReader给序列化程序是有效的:

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

I would be interested as well if there is another way to deserialize an XDocumentthat includes binary data without converting it into a string first.

如果有另一种方法可以反序列化一个XDocument包含二进制数据的数据,而无需先将其转换为字符串,我也会感兴趣。

回答by KarmaEDV

I like @Simon_Weaver 's answer the best. Based on that this is my summary:

我最喜欢@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
    }
}

回答by dotNetkow

Just thought I should add that after the XmlReader is created, i.e.:

只是想我应该在创建 XmlReader 之后添加,即:

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

then you should call:

那么你应该打电话:

reader.MoveToContent();

because otherwise the reader will not "point" to the first node, causing the appearance of an empty reader! Then you can safely call Deserialize:

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

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