簡體   English   中英

XML不反序列化為正確的類,並且之后不使用xsi:type屬性進行序列化

[英]XML not deserializing to correct class, and not serializing with xsi:type attribute after

在以下代碼段中,我嘗試反序列化在Animal記錄上具有類型屬性的XML,以將它們標識為CatDog ,這兩個屬性均繼承自Animal

反序列化時,這些記錄都顯示為Animal

然后,當嘗試序列化對象時(反序列化之后), xsi:type="Dog"xsi:type="Cat"不會出現在XML中。

我不確定這是由於我裝飾類的方式還是在序列化器/反序列化器實現中。 如果可能的話,最好選擇類中的解決方案,而不要選擇序列化器/解串器包裝器方法。

碼:

using System;  
using System.IO; 
using System.Text;
using System.Xml;
using System.Xml.Serialization; 

namespace sandbox
{
    public partial class Program
    {
        static void Main(string[] args)
        { 
            string xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                "<OuterClass xmlns=\"http://myschema.com/\">" +
                "   <Animals>" +
                "      <Animal xmlns:xsi=\"http://myschema.com/\" xsi:type=\"Dog\">" +
                "         <Name>Watson</Name>" +
                "         <Height>10</Height>" +
                "         <Weight>10</Weight>" +
                "         <Paws>4</Paws>" +
                "         <Woof>True</Woof>" +
                "      </Animal>" +
                "      <Animal xmlns:xsi=\"http://myschema.com/\" xsi:type=\"Cat\">" +
                "         <Name>Hermy</Name>" +
                "         <Height>10</Height>" +
                "         <Weight>10</Weight>" +
                "         <Paws>4</Paws>" +
                "         <Meow>True</Meow>" +
                "      </Animal>" +
                "   </Animals>" +
                "</OuterClass>";

            OuterClass data = null;

            try
            {
                data = DeserializeXml<OuterClass>(xml);
                foreach (Animal curr in data.Animals) Console.WriteLine(curr.Name + ": " + curr.GetType().ToString());
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                Console.WriteLine(e.Message);
            }

            Console.WriteLine(SerializeXml(data));
            Console.ReadLine(); 
        }

        public static T DeserializeXml<T>(string xml)
        {
            XmlSerializer xmls = new XmlSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml))) 
                return (T)xmls.Deserialize(ms); 
        }

        public static string SerializeXml(object obj)
        { 
            XmlSerializer xml = new XmlSerializer(obj.GetType()); 
            using (MemoryStream stream = new MemoryStream())
            {
                using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
                {
                    xml.Serialize(writer, obj);
                    byte[] bytes = stream.ToArray();
                    return Encoding.UTF8.GetString(bytes, 0, bytes.Length); 
                }
            }
        }
    }

    [XmlRoot(ElementName = "OuterClass", Namespace = "http://myschema.com/", IsNullable = true)]
    public class OuterClass
    { 
        [XmlArrayItem(Type = typeof(Cat)), XmlArrayItem(Type = typeof(Dog)), XmlArrayItem(Type = typeof(Animal))] 
        public Animal[] Animals { get; set; }
        [XmlAttribute("type")]
        public string Type { get; set; }
    }

    [XmlType(TypeName = "Cat")]
    [XmlRoot(ElementName = "Animal", Namespace = "http://myschema.com/", IsNullable = true)]
    public class Cat : Animal
    { 
        public bool Meow { get; set; }
    }

    [XmlType(TypeName = "Dog")]
    [XmlRoot(ElementName = "Animal", Namespace = "http://myschema.com/", IsNullable = true)]
    public class Dog : Animal
    { 
        public bool Woof { get; set; }
    }

    [XmlInclude(typeof(Cat))]
    [XmlInclude(typeof(Dog))]
    [XmlRoot(ElementName = "Animal", Namespace = "http://myschema.com/", IsNullable = true)]
    public class Animal
    {
        public string Name { get; set; }
        public int Height { get; set; }
        public int Weight { get; set; }
        public int Paws { get; set; }
    }
}

輸出:

Watson: sandbox.Animal       <-- should be sandbox.Dog
Hermy: sandbox.Animal        <-- should be sandbox.Cat
?<?xml version="1.0" encoding="utf-8"?>
<OuterClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://myschema.com/">
  <Animals>
    <Animal>                 <-- missing xsi:type, object missing 'Woof' 
      <Name>Watson</Name>
      <Height>10</Height>
      <Weight>10</Weight>
      <Paws>4</Paws>
    </Animal>
    <Animal>                 <-- missing xsi:type, object missing 'Meow'
      <Name>Hermy</Name>
      <Height>10</Height>
      <Weight>10</Weight>
      <Paws>4</Paws>
    </Animal>
  </Animals>
</OuterClass>

您需要正確創建類:

            OuterClass outerClass = new OuterClass()
            {
                Animals = new Animal[] {
                    new Dog() { Name = "Watson", Height = 10, Weight = 10, Paws = 4},
                    new Cat() { Name = "Hermy", Height = 10, Weight = 10, Paws = 4}
                }
            };

您的示例中有兩個問題:

  • 模型與xmls不匹配
  • 每個Animal元素都覆蓋xsi命名空間
  • 布爾值不支持序列化

請在下面找到有關問題的其他詳細信息:

1.模型與xmls不匹配

當您指定XmlArrayItem時, XmlSerializer將使用類型名稱作為元素名稱,或者您可以通過顯式提供ElementName進行更改。 如果使用XmlArrayItem注釋數組屬性,將得到以下輸出:

Console.WriteLine(SerializeXml(new OuterClass { Animals = new Animal[] { new Cat(), new Dog() } }));

<OuterClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://myschema.com/">
  <Animals>
    <Cat>
      <Height>0</Height>
      <Weight>0</Weight>
      <Paws>0</Paws>
      <Meow>false</Meow>
    </Cat>
    <Dog>
      <Height>0</Height>
      <Weight>0</Weight>
      <Paws>0</Paws>
      <Woof>false</Woof>
    </Dog>
  </Animals>
</OuterClass>

如果不加注釋,則將獲得由xsi:type屬性定義的類型的輸出:

<OuterClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://myschema.com/">
  <Animals>
    <Animal xsi:type="Cat">
      <Height>0</Height>
      <Weight>0</Weight>
      <Paws>0</Paws>
      <Meow>false</Meow>
    </Animal>
    <Animal xsi:type="Dog">
      <Height>0</Height>
      <Weight>0</Weight>
      <Paws>0</Paws>
      <Woof>false</Woof>
    </Animal>
  </Animals>
</OuterClass>

在這種情況下,您必須將XmlInclude屬性添加到基類。

2.每個Animal元素都覆蓋xsi命名空間

http://www.w3.org/2001/XMLSchema-instanceW3C中定義的特殊名稱空間,可幫助序列化程序了解XML元素中的類型。 在您的輸入xml中,每個Animal元素都會使用自定義http://myschema.com/覆蓋此命名空間,因此當序列化程序遇到xsi:type="Cat"它根本不知道它的含義。 Wikipedia是閱讀XML命名空間的一個很好的起點: https : //en.wikipedia.org/wiki/XML_namespace

3. XML中的布爾值

W3C將布爾數據類型定義為“ true”,“ false”,“ 0”和“ 1”,因此,如果將值“ T rue”反序列化布爾值,則會出現異常。 您可能會在網上找到解決方法選項,但我想您輸入的XML格式錯誤,因此您需要將XML中的布爾值小寫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM