xsi:type属性搞乱了C#XML反序列化
我使用XSD.exe根据XML模式(.xsd文件)自动生成C#对象。 我正在反序列化OpenCover输出,但其中一个部分类没有正确生成。
这是导致exception的行:
这是MethodPoint类的缩短版本:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)] public partial class CoverageSessionModulesModuleClassesClassMethodsMethodMethodPoint { private string vcField; private string uspidField; private string ordinalField; private string offsetField; private string slField; private string scField; private string elField; private string ecField; private string becField; private string bevField; private string fileidField; }
现在我已经浏览了很多.xml文件,但OpenCover输出文件是唯一一个在属性中包含冒号的文件。 MethodPoint对象也是唯一包含属性冒号的对象。 如您所见,该类不包含xsi:type
属性,我知道只是添加它将因冒号而无效。 你如何处理xsi
前缀?
这是从其中一个OpenCover XML文件生成的原始.xsd
简短的回答是您需要手动将[XmlInclude(typeof(SequencePoint))]
到MethodPoint
类:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)] [XmlInclude(typeof(SequencePoint))] public partial class CoverageSessionModulesModuleClassesClassMethodsMethodMethodPoint { private string vcField; private string uspidField; private string ordinalField; private string offsetField; private string slField; private string scField; private string elField; private string ecField; private string becField; private string bevField; private string fileidField; }
如果尚未从MethodPoint
inheritance,还需要使SequencePoint
inheritance。
您需要这样做,因为当您使用xsd.exe从XML示例生成XSD ,然后依次生成c#类时,当属性xsi:type="SomePolymoirphicSubType"
时,它显然不会自动向基类型添加多态子类型属性xsi:type="SomePolymoirphicSubType"
出现在XML中,即使看起来应该如此。
解释如下。 xsi:type
属性是{http://www.w3.org/2001/XMLSchema-instance}type
缩写,是一个w3c标准属性 ,允许元素显式断言其类型,例如,当它是多态的子类型时预期的元素类型。 XmlSerializer
支持此属性 ,并将使用它来确定要对此类多态类型进行反序列化的实际对象类型。 但是,需要使用XmlIncludeAttribute
提前通知所有可能的类型。 因此,如果我创建以下类型层次结构:
[XmlInclude(typeof(SequencePoint))] public class MethodPoint { } public class SequencePoint : MethodPoint { }
并按如下顺序排列:
var test = new SequencePoint(); var serializer = new XmlSerializer(typeof(MethodPoint)); var sb = new StringBuilder(); using (var stream = new StringWriter(sb)) serializer.Serialize(stream, test); Console.WriteLine(sb);
我得到以下XML:
然后,如果我使用var serializer = new XmlSerializer(typeof(MethodPoint))
对其进行反var serializer = new XmlSerializer(typeof(MethodPoint))
,我会返回一个SequencePoint
,而不是它的基类。 如果我使用xsd.exe为这些类生成模式,我得到:
注意xs:extension
? 这就是XSD如何表示多态子类型。 然后,如果我向后运行xsd.exe以重新生成我的类,我得到:
[System.Xml.Serialization.XmlIncludeAttribute(typeof(SequencePoint))] [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)] public partial class MethodPoint { } /// [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)] public partial class SequencePoint : MethodPoint { }
如您所见, XmlIncludeAttribute
存在,结果类等同于原始类。 到目前为止,一切都很完美。
但是,似乎在从示例XML文件中推断出XSD时,xsd.exe没有获取xsi:type
属性的存在。 例如,如果我从上面的普通XML创建XSD,结果是:
多态子类型完全缺失。 从此XSD生成的类将无法反序列化该XML。
因此,使用xsd.exe从XML样本生成c#类似乎不如从正确的XSD生成它们那样可靠。 具体而言,如果XML文件中出现xsi:type
,则需要手动修复生成的类或生成的XSD以实现所需的层次结构。 这可能是工具中的限制或错误。
(限制/错误也会出现在粘贴XML中作为在内部使用xsd.exe
类 。)