如何反序列化包含未知xsi:type属性的XML?
处理XML反序列化中未知xsi:type的问题
问题场景
反序列化XML时,<AutxObject>节点的xsi:type可能新增未知类型,但所有节点都包含固定且始终存在的子节点(如ID、Name、ProcessID等),需要忽略类型差异,直接读取这些固定字段。
XML示例
<AutxObject xsi:type="TYPEA"> <ID>6cbe7c6f-79e8-4006-b7e9-11e25e2a0f8e</ID> <Name>Queue</Name> <ProcessID>eaab59cd-2be4-46fe-86c4-ee96c340c061</ProcessID> <IsRemoteExecutionEnabled>false</IsRemoteExecutionEnabled> <IsolationPlatform>x86</IsolationPlatform> <IsolationSessionType>Current</IsolationSessionType> <Items /> <RootPath>Global Objects</RootPath> </AutxObject> <AutxObject xsi:type="TYPEB"> <ID>9c643856-5f0c-497a-b212-a2e456d1a821</ID> <Name>Sample</Name> <ProcessID>eaab59cd-2be4-46fe-86c4-ee96c340c061</ProcessID> <IsRemoteExecutionEnabled>false</IsRemoteExecutionEnabled> <IsolationPlatform>x86</IsolationPlatform> <IsolationSessionType>Current</IsolationSessionType> <Items /> <RootPath>Global Objects</RootPath> <Type> <ID>75f2bd69-8bfc-41ba-a3fc-32e1a438b23a</ID> <Name>Object</Name> <FullName>System.Object</FullName> <Assembly>mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</Assembly> </Type> </AutxObject>
现有类定义
[XmlInclude(typeof(TYPEA))] [XmlInclude(typeof(TYPEB))] public class GlobalVariable { [XmlElement("ID")] public Guid Id { get; set; } [XmlElement("Name")] public string Name { get; set; } = string.Empty; [XmlElement("RootPath")] public string RootPath { get; set; } = string.Empty; } [XmlType(TypeName = "TYPEA")] public class TYPEA: GlobalVariable { } [XmlType(TypeName = "TYPEB")] public class TYPEB: GlobalVariable { }
解决方案
1. 完善基类,包含所有固定子节点
首先将所有固定存在的子节点添加到GlobalVariable基类中,确保所有需要读取的字段都被映射:
public class GlobalVariable { [XmlElement("ID")] public Guid Id { get; set; } [XmlElement("Name")] public string Name { get; set; } = string.Empty; [XmlElement("RootPath")] public string RootPath { get; set; } = string.Empty; [XmlElement("ProcessID")] public Guid ProcessId { get; set; } [XmlElement("IsRemoteExecutionEnabled")] public bool IsRemoteExecutionEnabled { get; set; } [XmlElement("IsolationPlatform")] public string IsolationPlatform { get; set; } = string.Empty; [XmlElement("IsolationSessionType")] public string IsolationSessionType { get; set; } = string.Empty; // 忽略不需要解析的节点,或用XmlNode保留原始内容 [XmlElement("Items")] public XmlNode? Items { get; set; } }
2. 方法一:手动遍历XmlReader反序列化
直接遍历XML节点,将每个<AutxObject>节点反序列化为GlobalVariable,完全忽略xsi:type:
var autxObjects = new List<GlobalVariable>(); var serializer = new XmlSerializer(typeof(GlobalVariable)); using (var reader = XmlReader.Create("your-xml-file-path.xml")) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element && reader.Name == "AutxObject") { var obj = (GlobalVariable)serializer.Deserialize(reader)!; autxObjects.Add(obj); } } }
3. 方法二:处理UnknownType事件(适用于父类包含列表的场景)
如果XML有根节点,且用包含AutxObject列表的父类反序列化,可通过UnknownType事件将未知类型映射到基类:
// 定义根节点类 [XmlRoot("Root")] public class RootObject { [XmlElement("AutxObject")] public List<GlobalVariable> AutxObjects { get; set; } = new(); } // 反序列化时处理未知类型 var serializer = new XmlSerializer(typeof(RootObject)); serializer.UnknownType += (sender, e) => { // 遇到未知xsi:type时,用GlobalVariable实例接收 e.ObjectBeingDeserialized = new GlobalVariable(); }; using (var reader = XmlReader.Create("your-xml-file-path.xml")) { var root = (RootObject)serializer.Deserialize(reader)!; // 使用root.AutxObjects }
内容的提问来源于stack exchange,提问作者sumit kumar
相关产品推荐
相关产品推荐

