xsi:type attribute messing up C# XML deserialization(xsi:type 属性搞乱了 C# XML 反序列化)
问题描述
我使用 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 反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:xsi:type 属性搞乱了 C# XML 反序列化
- MoreLinq maxBy vs LINQ max + where 2022-01-01
- 如何用自己压缩一个 IEnumerable 2022-01-01
- C# 中多线程网络服务器的模式 2022-01-01
- C#MongoDB使用Builders查找派生对象 2022-09-04
- 良好实践:如何重用 .csproj 和 .sln 文件来为 CI 创建 2022-01-01
- WebMatrix WebSecurity PasswordSalt 2022-01-01
- 输入按键事件处理程序 2022-01-01
- 带有服务/守护程序应用程序的 Microsoft Graph CSharp SDK 和 OneDrive for Business - 配额方面返回 null 2022-01-01
- 在哪里可以找到使用中的C#/XML文档注释的好例子? 2022-01-01
- Web Api 中的 Swagger .netcore 3.1,使用 swagger UI 设置日期时间格式 2022-01-01