Подтвердить что ты не робот

Использовать XDocument в качестве источника для XmlSerializer.Deserialize?

Я хотел бы вызвать XmlSerializer.Deserialize, передав ему XDocument. Он может принимать значения Stream, XmlReader или TextReader.

Можно ли сгенерировать одно из указанных выше из XDocument без фактического сброса XDocument в некоторое промежуточное хранилище, например, MemoryStream?

Кажется, что то, что мне нужно, это реализация XmlReader, которая работает с XDocument. Я не могу найти его, хотя.

4b9b3361

Ответ 1

Вы можете использовать XDocument.CreateReader(), чтобы создать XmlReader, который читает содержимое XDocument.

Эквивалентно, будет работать и следующее.

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

Ответ 2

Здесь утилита для сериализации и десериализации объектов в/из 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;
    }
}

Ответ 3

(Приложение к ответу Стива Гуиди)

Насколько я вижу, нет реализации XmlReader, вы можете легко использовать с XDocument, не перемещая содержимое XML через промежуточное хранилище, как строковое представление XML и , которое поддерживает все типы, который поддерживает System.Xml.XmlNodeReader.

Читатель, возвращаемый XDocument.CreateReader (который является System.Xml.Linq.XNodeReader, внутренним классом), является XmlReader и работает для большинства документов Xml, но не с документами, которые имеют двоичные элементы данных, поскольку его реализация не поддерживает данные Base64 или BinHex:

Данные Base64 и BinHex не поддерживаются. Если вы попытаетесь восстановить эти типы данных (например, путем вызова ReadElementContentAsBase64), читатель бросит NotSupportedException.

Для этого читателя XDocument.CreateReader().CanReadBinaryContent есть false в отличие от System.Xml.XmlNodeReader.

Например, эта программа выдает исключение:

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

Однако извлечение XML как string и передача его как TextReader в сериализатор работает:

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

Мне также было бы интересно, если есть еще один способ десериализации XDocument, который включает двоичные данные, не преобразовывая его сначала в строку.

Ответ 4

Просто подумал, что я должен добавить, что после создания XmlReader, т.е.:

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

тогда вы должны позвонить:

reader.MoveToContent();

потому что иначе читатель не будет "указывать" на первый node, вызывая появление пустого читателя! Затем вы можете безопасно вызвать Deserialize:

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

Ответ 5

Мне нравится @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
    }
}