Ответ 1
Вы можете использовать XDocument.CreateReader()
, чтобы создать XmlReader
, который читает содержимое XDocument
.
Эквивалентно, будет работать и следующее.
XmlReader GetReader(XDocument doc)
{
return doc.Root.CreateReader();
}
Я хотел бы вызвать XmlSerializer.Deserialize
, передав ему XDocument
. Он может принимать значения Stream
, XmlReader
или TextReader
.
Можно ли сгенерировать одно из указанных выше из XDocument
без фактического сброса XDocument
в некоторое промежуточное хранилище, например, MemoryStream
?
Кажется, что то, что мне нужно, это реализация XmlReader
, которая работает с XDocument
. Я не могу найти его, хотя.
Вы можете использовать XDocument.CreateReader()
, чтобы создать XmlReader
, который читает содержимое XDocument
.
Эквивалентно, будет работать и следующее.
XmlReader GetReader(XDocument doc)
{
return doc.Root.CreateReader();
}
Здесь утилита для сериализации и десериализации объектов в/из 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;
}
}
(Приложение к ответу Стива Гуиди)
Насколько я вижу, нет реализации 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
, который включает двоичные данные, не преобразовывая его сначала в строку.
Просто подумал, что я должен добавить, что после создания XmlReader, т.е.:
XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
XmlReader reader = xmlDocumentToDeserialize.CreateReader();
тогда вы должны позвонить:
reader.MoveToContent();
потому что иначе читатель не будет "указывать" на первый node, вызывая появление пустого читателя! Затем вы можете безопасно вызвать Deserialize:
MyObject myObject = (MyObject)serializer.Deserialize(reader);
Мне нравится @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
}
}