問題描述
我使用 XSD.exe 根據 XML 模式(.xsd 文件)自動生成 C# 對象.我正在反序列化 OpenCover 輸出,但其中一個部分類沒有正確生成.
I used XSD.exe to automatically generate C# objects based on the XML schemas (.xsd files). I'm deserializing OpenCover output, but one of the partial classes didn't get generated correctly.
這是導致異常的行:
<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 類的簡化版本:
Here's a shortened version of the 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 對象也是唯一在屬性中包含冒號的對象.如您所見,該類不包含 xsi:type
屬性,而且我知道由于冒號,簡單地添加它是行不通的.xsi
前綴怎么處理?
Now I've been going through a lot of .xml files, but the OpenCover output files are the only ones that contain a colon inside an attribute. The MethodPoint object is also the only object that contains a colon in an attribute. As you can see, the class does not contain the xsi:type
attribute, and I know that simply adding it won't work because of the colon. How do you deal with the xsi
prefix?
這是從 OpenCover XML 文件之一生成的原始 .xsd
Here is the raw .xsd generated from one of the OpenCover XML files
<?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
類:
[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
繼承,如果它還沒有這樣做的話.
You also need to make SequencePoint
inherit from MethodPoint
if it does not already do so.
您需要這樣做是因為,當您使用 xsd.exe 從 XML 樣本生成 XSD 時,然后依次使用 c# 類,它顯然不會將多態子類型屬性添加到基礎當屬性 xsi:type="SomePolymoirphicSubType"
出現在 XML 中時自動鍵入,即使它看起來應該如此.
You need to do this because, when you use xsd.exe to generate an XSD from an XML sample, and then c# classes in turn, it apparently doesn't add polymorphic subtype attributes to base types automatically when the attribute xsi:type="SomePolymoirphicSubType"
appears in the XML, even though it seems it should.
解釋如下.xsi:type
屬性是 {http://www.w3.org/2001/XMLSchema-instance}type
的縮寫,是一個 w3c 標準屬性 允許元素顯式聲明其類型,例如當它是預期元素類型的多態子類型時.XmlSerializer
支持這個屬性并將使用它確定要為這種多態類型反序列化的對象的實際類型.但是,需要使用 提前通知它所有可能的類型.aspx" rel="noreferrer">XmlIncludeAttribute
.因此,如果我創建以下類型層次結構:
The explanation is as follows. The xsi:type
attribute, short for {http://www.w3.org/2001/XMLSchema-instance}type
, is a 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
. Thus, if I create the following type hierarchy:
[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
,而不是它的基類.如果我使用 xsd.exe 為這些類生成架構,我會得到:
Then if I deserialize it using var serializer = new XmlSerializer(typeof(MethodPoint))
, I get back a SequencePoint
, not its base class. And if I use xsd.exe to generate a schema for these classes, I get:
<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 以重新生成我的類,我會得到:
Notice the xs:extension
? That's how the XSD indicates a polymorphic subtype. And then if I run xsd.exe backwards to regenerate my classes, I get:
[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
在那里,生成的類與原始類等效.到目前為止,一切都運行良好.
As you can see, the XmlIncludeAttribute
is there and the resulting classes are equivalent to the originals. Everything is working perfectly so far.
但是,似乎在從示例 XML 文件推斷 XSD 時,xsd.exe 并沒有發現 xsi:type
屬性的存在.例如,如果我從上面的普通 XML 創建一個 XSD,結果是:
But, it seems that when inferring an XSD from a sample XML file, xsd.exe doesn't pick up on the presence of the xsi:type
attribute. For instance, if I create an XSD from the trivial XML above, the result is:
<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.
The polymorphic subtype is completely missing. Classes generated from this XSD will not be able to deserialize that XML.
因此,使用 xsd.exe 從 XML 示例生成 c# 類似乎不如從適當的 XSD 生成它們可靠.具體來說,如果 xsi:type
出現在 XML 文件中,您將需要手動修復生成的類或生成的 XSD 以實現所需的層次結構.這可能是工具中的限制或錯誤.
So it seems that generating c# classes from an XML sample with xsd.exe just isn't as reliable as generating them from a proper XSD. Specifically, in cases where xsi:type
appears in the XML file, you will need to manually fix either the generated classes or the generated XSD to implement the required hierarchy. This may be either a limitation or a bug in the tool.
(限制/錯誤也將出現在 將 XML 粘貼為類,它在內部使用 xsd.exe
.)
(The limitation/bug will also appear in Paste XML as Classes which uses xsd.exe
internally.)
這篇關于xsi:type 屬性搞亂了 C# XML 反序列化的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!