xsi:type 属性搞乱了 C# XML 反序列化
xsi:type attribute messing up C# XML deserialization
我使用 XSD.exe 基于 XML 模式(.xsd 文件)自动生成 C# 对象。我正在反序列化 OpenCover 输出,但部分 classes 之一没有正确生成。
这是导致异常的行:
<MethodPoint xsi:type="SequencePoint" vc="0" uspid="1" ordinal="0" offset="0" sl="19" sc="9" el="19" ec="10" bec="0" bev="0" fileid="1" />
这是 MethodPoint 的简化版本 class:
[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 对象也是唯一在属性中包含冒号的对象。如您所见,class 不包含 xsi:type
属性,而且我知道仅仅添加它是行不通的,因为有冒号。你如何处理 xsi
前缀?
这是从 OpenCover XML 文件之一生成的原始 .xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="CoverageSession" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="Summary">
<xs:complexType>
<xs:attribute name="numSequencePoints" type="xs:string" />
<xs:attribute name="visitedSequencePoints" type="xs:string" />
<xs:attribute name="numBranchPoints" type="xs:string" />
<xs:attribute name="visitedBranchPoints" type="xs:string" />
<xs:attribute name="sequenceCoverage" type="xs:string" />
<xs:attribute name="branchCoverage" type="xs:string" />
<xs:attribute name="maxCyclomaticComplexity" type="xs:string" />
<xs:attribute name="minCyclomaticComplexity" type="xs:string" />
<xs:attribute name="visitedClasses" type="xs:string" />
<xs:attribute name="numClasses" type="xs:string" />
<xs:attribute name="visitedMethods" type="xs:string" />
<xs:attribute name="numMethods" type="xs:string" />
</xs:complexType>
</xs:element>
<xs:element name="CoverageSession" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Summary" />
<xs:element name="Modules">
<xs:complexType>
<xs:sequence>
<xs:element name="Module" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="FullName" type="xs:string" minOccurs="0" msdata:Ordinal="1" />
<xs:element name="ModuleName" type="xs:string" minOccurs="0" msdata:Ordinal="2" />
<xs:element ref="Summary" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="Files" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="File" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="uid" type="xs:string" />
<xs:attribute name="fullPath" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Classes" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Class" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="FullName" type="xs:string" minOccurs="0" />
<xs:element ref="Summary" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="Methods" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Method" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="MetadataToken" type="xs:string" minOccurs="0" msdata:Ordinal="1" />
<xs:element name="Name" type="xs:string" minOccurs="0" msdata:Ordinal="2" />
<xs:element ref="Summary" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="FileRef" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="uid" type="xs:string" />
</xs:complexType>
</xs:element>
<xs:element name="SequencePoints" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="SequencePoint" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="vc" type="xs:string" />
<xs:attribute name="uspid" type="xs:string" />
<xs:attribute name="ordinal" type="xs:string" />
<xs:attribute name="offset" type="xs:string" />
<xs:attribute name="sl" type="xs:string" />
<xs:attribute name="sc" type="xs:string" />
<xs:attribute name="el" type="xs:string" />
<xs:attribute name="ec" type="xs:string" />
<xs:attribute name="bec" type="xs:string" />
<xs:attribute name="bev" type="xs:string" />
<xs:attribute name="fileid" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="BranchPoints" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="BranchPoint" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="vc" type="xs:string" />
<xs:attribute name="uspid" type="xs:string" />
<xs:attribute name="ordinal" type="xs:string" />
<xs:attribute name="offset" type="xs:string" />
<xs:attribute name="sl" type="xs:string" />
<xs:attribute name="path" type="xs:string" />
<xs:attribute name="offsetend" type="xs:string" />
<xs:attribute name="fileid" type="xs:string" />
<xs:attribute name="offsetchain" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="MethodPoint" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="vc" type="xs:string" />
<xs:attribute name="uspid" type="xs:string" />
<xs:attribute name="ordinal" type="xs:string" />
<xs:attribute name="offset" type="xs:string" />
<xs:attribute name="sl" type="xs:string" />
<xs:attribute name="sc" type="xs:string" />
<xs:attribute name="el" type="xs:string" />
<xs:attribute name="ec" type="xs:string" />
<xs:attribute name="bec" type="xs:string" />
<xs:attribute name="bev" type="xs:string" />
<xs:attribute name="fileid" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="visited" type="xs:string" />
<xs:attribute name="cyclomaticComplexity" type="xs:string" />
<xs:attribute name="sequenceCoverage" type="xs:string" />
<xs:attribute name="branchCoverage" type="xs:string" />
<xs:attribute name="isConstructor" type="xs:string" />
<xs:attribute name="isStatic" type="xs:string" />
<xs:attribute name="isGetter" type="xs:string" />
<xs:attribute name="isSetter" type="xs:string" />
<xs:attribute name="skippedDueTo" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="skippedDueTo" type="xs:string" />
<xs:attribute name="hash" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
简短的回答 是您需要手动将 [XmlInclude(typeof(SequencePoint))]
添加到您的 MethodPoint
class:
[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;
}
您还需要让 SequencePoint
从 MethodPoint
继承,如果它还没有这样做的话。
您需要这样做是因为,当您使用 xsd.exe 从 XML 样本 生成 XSD,然后使用 c# class 反过来,当属性 xsi:type="SomePolymoirphicSubType"
出现在 XML 中时,它显然不会自动将多态子类型属性添加到基类型,即使它看起来应该如此。
解释如下。 xsi:type
属性是 {http://www.w3.org/2001/XMLSchema-instance}type
的缩写,是 w3c standard attribute that allows an element to explicitly assert its type, e.g. when it is a polymorphic subtype of the expected element type. XmlSerializer
supports this attribute and will use it to determine the actual type of object to deserialize for such a polymorphic type. However, it requires to be informed in advance of all possible types using 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:
<MethodPoint
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xsi:type="SequencePoint" />
然后如果我使用 var serializer = new XmlSerializer(typeof(MethodPoint))
反序列化它,我会得到一个 SequencePoint
,而不是它的基础 class。如果我使用 xsd.exe 为这些 class 生成模式,我会得到:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="MethodPoint" nillable="true" type="MethodPoint" />
<xs:complexType name="MethodPoint" />
<xs:complexType name="SequencePoint">
<xs:complexContent mixed="false">
<xs:extension base="MethodPoint" />
</xs:complexContent>
</xs:complexType>
<xs:element name="SequencePoint" nillable="true" type="SequencePoint" />
</xs:schema>
注意到 xs:extension
了吗?这就是 XSD 表示多态子类型的方式。然后如果我 运行 xsd.exe 向后重新生成我的 classes,我得到:
[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 {
}
/// <remarks/>
[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
就在那里,生成的 classes 等同于原始文件。到目前为止一切正常。
但是,似乎在从示例 XML 文件推断 XSD 时,xsd.exe 没有发现 xsi:type
属性的存在。例如,如果我从上面的普通 XML 创建一个 XSD,结果是:
<xs:schema id="MethodPoint" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="MethodPoint" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded" />
</xs:complexType>
</xs:element>
</xs:schema>
多态子类型完全缺失。从此 XSD 生成的 类 将无法反序列化 XML.
因此,从带有 xsd.exe 的 XML 样本生成 c# classes 似乎不如从适当的 XSD 生成它们可靠。具体来说,在 XML 文件中出现 xsi:type
的情况下,您将需要手动修复生成的 classes 或生成的 XSD 以实现所需的层次结构。这可能是工具中的限制或错误。
(limitation/bug也会出现在内部使用xsd.exe
的Paste XML as Classes中。)
我使用 XSD.exe 基于 XML 模式(.xsd 文件)自动生成 C# 对象。我正在反序列化 OpenCover 输出,但部分 classes 之一没有正确生成。
这是导致异常的行:
<MethodPoint xsi:type="SequencePoint" vc="0" uspid="1" ordinal="0" offset="0" sl="19" sc="9" el="19" ec="10" bec="0" bev="0" fileid="1" />
这是 MethodPoint 的简化版本 class:
[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 对象也是唯一在属性中包含冒号的对象。如您所见,class 不包含 xsi:type
属性,而且我知道仅仅添加它是行不通的,因为有冒号。你如何处理 xsi
前缀?
这是从 OpenCover XML 文件之一生成的原始 .xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="CoverageSession" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="Summary">
<xs:complexType>
<xs:attribute name="numSequencePoints" type="xs:string" />
<xs:attribute name="visitedSequencePoints" type="xs:string" />
<xs:attribute name="numBranchPoints" type="xs:string" />
<xs:attribute name="visitedBranchPoints" type="xs:string" />
<xs:attribute name="sequenceCoverage" type="xs:string" />
<xs:attribute name="branchCoverage" type="xs:string" />
<xs:attribute name="maxCyclomaticComplexity" type="xs:string" />
<xs:attribute name="minCyclomaticComplexity" type="xs:string" />
<xs:attribute name="visitedClasses" type="xs:string" />
<xs:attribute name="numClasses" type="xs:string" />
<xs:attribute name="visitedMethods" type="xs:string" />
<xs:attribute name="numMethods" type="xs:string" />
</xs:complexType>
</xs:element>
<xs:element name="CoverageSession" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Summary" />
<xs:element name="Modules">
<xs:complexType>
<xs:sequence>
<xs:element name="Module" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="FullName" type="xs:string" minOccurs="0" msdata:Ordinal="1" />
<xs:element name="ModuleName" type="xs:string" minOccurs="0" msdata:Ordinal="2" />
<xs:element ref="Summary" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="Files" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="File" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="uid" type="xs:string" />
<xs:attribute name="fullPath" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Classes" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Class" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="FullName" type="xs:string" minOccurs="0" />
<xs:element ref="Summary" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="Methods" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Method" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="MetadataToken" type="xs:string" minOccurs="0" msdata:Ordinal="1" />
<xs:element name="Name" type="xs:string" minOccurs="0" msdata:Ordinal="2" />
<xs:element ref="Summary" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="FileRef" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="uid" type="xs:string" />
</xs:complexType>
</xs:element>
<xs:element name="SequencePoints" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="SequencePoint" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="vc" type="xs:string" />
<xs:attribute name="uspid" type="xs:string" />
<xs:attribute name="ordinal" type="xs:string" />
<xs:attribute name="offset" type="xs:string" />
<xs:attribute name="sl" type="xs:string" />
<xs:attribute name="sc" type="xs:string" />
<xs:attribute name="el" type="xs:string" />
<xs:attribute name="ec" type="xs:string" />
<xs:attribute name="bec" type="xs:string" />
<xs:attribute name="bev" type="xs:string" />
<xs:attribute name="fileid" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="BranchPoints" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="BranchPoint" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="vc" type="xs:string" />
<xs:attribute name="uspid" type="xs:string" />
<xs:attribute name="ordinal" type="xs:string" />
<xs:attribute name="offset" type="xs:string" />
<xs:attribute name="sl" type="xs:string" />
<xs:attribute name="path" type="xs:string" />
<xs:attribute name="offsetend" type="xs:string" />
<xs:attribute name="fileid" type="xs:string" />
<xs:attribute name="offsetchain" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="MethodPoint" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="vc" type="xs:string" />
<xs:attribute name="uspid" type="xs:string" />
<xs:attribute name="ordinal" type="xs:string" />
<xs:attribute name="offset" type="xs:string" />
<xs:attribute name="sl" type="xs:string" />
<xs:attribute name="sc" type="xs:string" />
<xs:attribute name="el" type="xs:string" />
<xs:attribute name="ec" type="xs:string" />
<xs:attribute name="bec" type="xs:string" />
<xs:attribute name="bev" type="xs:string" />
<xs:attribute name="fileid" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="visited" type="xs:string" />
<xs:attribute name="cyclomaticComplexity" type="xs:string" />
<xs:attribute name="sequenceCoverage" type="xs:string" />
<xs:attribute name="branchCoverage" type="xs:string" />
<xs:attribute name="isConstructor" type="xs:string" />
<xs:attribute name="isStatic" type="xs:string" />
<xs:attribute name="isGetter" type="xs:string" />
<xs:attribute name="isSetter" type="xs:string" />
<xs:attribute name="skippedDueTo" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="skippedDueTo" type="xs:string" />
<xs:attribute name="hash" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
简短的回答 是您需要手动将 [XmlInclude(typeof(SequencePoint))]
添加到您的 MethodPoint
class:
[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;
}
您还需要让 SequencePoint
从 MethodPoint
继承,如果它还没有这样做的话。
您需要这样做是因为,当您使用 xsd.exe 从 XML 样本 生成 XSD,然后使用 c# class 反过来,当属性 xsi:type="SomePolymoirphicSubType"
出现在 XML 中时,它显然不会自动将多态子类型属性添加到基类型,即使它看起来应该如此。
解释如下。 xsi:type
属性是 {http://www.w3.org/2001/XMLSchema-instance}type
的缩写,是 w3c standard attribute that allows an element to explicitly assert its type, e.g. when it is a polymorphic subtype of the expected element type. XmlSerializer
supports this attribute and will use it to determine the actual type of object to deserialize for such a polymorphic type. However, it requires to be informed in advance of all possible types using 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:
<MethodPoint
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xsi:type="SequencePoint" />
然后如果我使用 var serializer = new XmlSerializer(typeof(MethodPoint))
反序列化它,我会得到一个 SequencePoint
,而不是它的基础 class。如果我使用 xsd.exe 为这些 class 生成模式,我会得到:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="MethodPoint" nillable="true" type="MethodPoint" />
<xs:complexType name="MethodPoint" />
<xs:complexType name="SequencePoint">
<xs:complexContent mixed="false">
<xs:extension base="MethodPoint" />
</xs:complexContent>
</xs:complexType>
<xs:element name="SequencePoint" nillable="true" type="SequencePoint" />
</xs:schema>
注意到 xs:extension
了吗?这就是 XSD 表示多态子类型的方式。然后如果我 运行 xsd.exe 向后重新生成我的 classes,我得到:
[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 {
}
/// <remarks/>
[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
就在那里,生成的 classes 等同于原始文件。到目前为止一切正常。
但是,似乎在从示例 XML 文件推断 XSD 时,xsd.exe 没有发现 xsi:type
属性的存在。例如,如果我从上面的普通 XML 创建一个 XSD,结果是:
<xs:schema id="MethodPoint" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="MethodPoint" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded" />
</xs:complexType>
</xs:element>
</xs:schema>
多态子类型完全缺失。从此 XSD 生成的 类 将无法反序列化 XML.
因此,从带有 xsd.exe 的 XML 样本生成 c# classes 似乎不如从适当的 XSD 生成它们可靠。具体来说,在 XML 文件中出现 xsi:type
的情况下,您将需要手动修复生成的 classes 或生成的 XSD 以实现所需的层次结构。这可能是工具中的限制或错误。
(limitation/bug也会出现在内部使用xsd.exe
的Paste XML as Classes中。)