xsi:type属性搞乱了C#XML反序列化

Kie*_*ock 3 c# xml xsd deserialization opencover

我使用XSD.exe根据XML模式(.xsd文件)自动生成C#对象.我正在反序列化OpenCover输出,但其中一个部分类没有正确生成.

这是导致异常的行:

<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" />
Run Code Online (Sandbox Code Playgroud)

这是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;
}
Run Code Online (Sandbox Code Playgroud)

现在我已经浏览了很多.xml文件,但OpenCover输出文件是唯一一个在属性中包含冒号的文件.MethodPoint对象也是唯一包含属性冒号的对象.如您所见,该类不包含该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>
Run Code Online (Sandbox Code Playgroud)

dbc*_*dbc 9

简短的回答是你需要手动添加[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;
}
Run Code Online (Sandbox Code Playgroud)

如果还没有SequencePoint继承,你还需要继承MethodPoint.

您需要这样做,因为当您使用xsd.exe从XML示例生成XSD,然后依次生成c#类时,当属性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
{
}
Run Code Online (Sandbox Code Playgroud)

并按如下顺序排列:

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);
Run Code Online (Sandbox Code Playgroud)

我得到以下XML:

<MethodPoint 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 xsi:type="SequencePoint" />
Run Code Online (Sandbox Code Playgroud)

然后,如果我使用它反序列化var serializer = new XmlSerializer(typeof(MethodPoint)),我会返回一个SequencePoint,而不是它的基类.如果我使用xsd.exe为这些类生成模式,我得到:

<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>
Run Code Online (Sandbox Code Playgroud)

请注意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 {
}

/// <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 {
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它就XmlIncludeAttribute在那里,结果类等同于原始类.到目前为止,一切都很完美.

但是,似乎在从示例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>
Run Code Online (Sandbox Code Playgroud)

多态子类型完全缺失.从此XSD生成的类将无法反序列化该XML.

因此,使用xsd.exe从XML样本生成c#类似乎不如从正确的XSD生成它们那样可靠.具体而言,如果xsi:type出现在XML文件中,则需要手动修复生成的类或生成的XSD以实现所需的层次结构.这可能是工具中的限制或错误.

(限制/错误也将出现在粘贴XML中作为xsd.exe内部使用的.)