[英]XML not deserializing to correct class, and not serializing with xsi:type attribute after
In the following snippet, I'm trying to deserialize XML that has type attributes on Animal
records identifying them as either Cat
or Dog
, both of which inherit from Animal
. 在以下代码段中,我尝试反序列化在Animal
记录上具有类型属性的XML,以将它们标识为Cat
或Dog
,这两个属性均继承自Animal
。
When deserialized, these records all appear as Animal
. 反序列化时,这些记录都显示为Animal
。
Then, when attempting to serialize the object (after deserialization), the xsi:type="Dog"
and xsi:type="Cat"
does not appear in the XML. 然后,当尝试序列化对象时(反序列化之后), xsi:type="Dog"
和xsi:type="Cat"
不会出现在XML中。
I'm not sure if this is due to how I've decorated the classes or in my serializer/deserializer implementation. 我不确定这是由于我装饰类的方式还是在序列化器/反序列化器实现中。 Preferring if possible a solution in the class rather than the serializer/deserializer wrapper methods. 如果可能的话,最好选择类中的解决方案,而不要选择序列化器/解串器包装器方法。
Code: 码:
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; }
}
}
Output: 输出:
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>
You need to create the classes correctly : 您需要正确创建类:
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}
}
};
There are a couple of problems in your example: 您的示例中有两个问题:
Please find additional details about problems below: 请在下面找到有关问题的其他详细信息:
When you specify XmlArrayItem XmlSerializer
will use type name as element name, or you can change it by providing ElementName explicitly. 当您指定XmlArrayItem时, XmlSerializer
将使用类型名称作为元素名称,或者您可以通过显式提供ElementName进行更改。 If you annotate array property with XmlArrayItem
you'll get the following output: 如果使用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>
If you don't annotate, you'll get output with type defined by xsi:type attribute: 如果不加注释,则将获得由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>
In this case you must add XmlInclude
attribute to the base class. 在这种情况下,您必须将XmlInclude
属性添加到基类。
http://www.w3.org/2001/XMLSchema-instance is a special namespace defined in W3C that helps serializer to know what type is in the XML element. http://www.w3.org/2001/XMLSchema-instance是W3C中定义的特殊名称空间,可帮助序列化程序了解XML元素中的类型。 In your input xml, each Animal element overrides this namespace with a custom http://myschema.com/ so when serializer meets xsi:type="Cat"
it has no idea what it means. 在您的输入xml中,每个Animal元素都会使用自定义http://myschema.com/覆盖此命名空间,因此当序列化程序遇到xsi:type="Cat"
它根本不知道它的含义。 Wikipedia is a good starting point to read about XML namespaces: https://en.wikipedia.org/wiki/XML_namespace Wikipedia是阅读XML命名空间的一个很好的起点: https : //en.wikipedia.org/wiki/XML_namespace
W3C defines boolean data type as 'true', 'false', '0', and '1' so you'll get an exception if you'll deserialize boolean with value ' T rue'. W3C将布尔数据类型定义为“ true”,“ false”,“ 0”和“ 1”,因此,如果将值“ T rue”反序列化布尔值,则会出现异常。 You may find workaround options online but I suppose that your input XML is malformed and you need to lowercase boolean values in XML. 您可能会在网上找到解决方法选项,但我想您输入的XML格式错误,因此您需要将XML中的布尔值小写。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.