【问题标题】:Use XDocument as the source for XmlSerializer.Deserialize?使用 XDocument 作为 XmlSerializer.Deserialize 的源?
【发布时间】:2009-08-18 16:34:59
【问题描述】:

我想调用 XmlSerializer.Deserialize 并传递一个 XDocument。它可以采用StreamXmlReaderTextReader

我可以从XDocument 生成上述其中一个而不将XDocument 实际转储到某个中间存储,例如MemoryStream

看来我所追求的是XmlReader 的实现,它与XDocument 一起工作。但是我找不到。

【问题讨论】:

标签: .net linq-to-xml


【解决方案1】:

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

同样,以下也可以。

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

【讨论】:

    【解决方案2】:

    这是一个将对象序列化和反序列化到 XDocument 或从 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】:

      (Steve Guidi 回答的附录)

      据我所知,没有XmlReader 的实现,您可以轻松地与XDocument 一起使用,而无需通过中间存储(如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().CanReadBinaryContentfalse,与 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,我也会感兴趣。

      【讨论】:

      • 我希望找到解决方案。我有一些带有二进制数据的 xml 内容,这会使一切变得更慢。往返于字符串似乎很疯狂。我想我可能会尝试协商完全删除 byte[] 内容,而不是降低性能。
      【解决方案4】:

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

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

      那么你应该调用:

      reader.MoveToContent();
      

      因为否则阅读器不会“指向”第一个节点,导致出现空阅读器!然后你就可以安全地调用 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
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-13
          • 1970-01-01
          • 2018-02-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多