XML反序列化存储类型时触发异常问题求助
问题描述
反序列化其他开发者提供的XML到C#类时,持续抛出InvalidOperationException异常,提示“未识别指定类型:name='string', namespace='http://www.w3.org/2001/XMLSchema'”,异常触发于DevListViewItem类的Tag属性处。若将Tag设为string类型,可正常读取文本,但无法保留类型信息用于后续序列化。
XML示例
<?xml version="1.0" encoding="utf-8"?> <ArrayOfDevListViewItem xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <DevListViewItem> <Index>0</Index> <Key>0</Key> <Tag xsi:type="xsd:string">[Category] = 0 And [CanOpen] = False</Tag> <Group /> <Text>Can Open?</Text> <Subitem1>[Category] = 0 And [CanOpen] = False</Subitem1> <Subitem1Integer>0</Subitem1Integer> <Subitem2Integer>0</Subitem2Integer> <Subitem3Integer>0</Subitem3Integer> <ExtraData /> <IsRead>true</IsRead> <Iconindex>0</Iconindex> <Sort /> <Condition>false</Condition> <Checked>false</Checked> <HasInfoButton>false</HasInfoButton> <HasExecuteButton>false</HasExecuteButton> <IsBold>false</IsBold> </DevListViewItem> </ArrayOfDevListViewItem>
现有C#代码
public class FilterXMLSchema { public class Tag { [XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")] public string Type { get; set; } [XmlText] public string Text { get; set; } } public class DevListViewItem { [XmlElement(ElementName = "Index")] public int Index { get; set; } [XmlElement(ElementName = "Key")] public string Key { get; set; } [XmlElement(ElementName = "Tag")] public Tag Tag { get; set; } [XmlElement(ElementName = "Group")] public object Group { get; set; } [XmlElement(ElementName = "Text")] public string Text { get; set; } [XmlElement(ElementName = "Subitem1")] public string Subitem1 { get; set; } [XmlElement(ElementName = "Subitem1Integer")] public int Subitem1Integer { get; set; } [XmlElement(ElementName = "Subitem2Integer")] public int Subitem2Integer { get; set; } [XmlElement(ElementName = "Subitem3Integer")] public int Subitem3Integer { get; set; } [XmlElement(ElementName = "ExtraData")] public object ExtraData { get; set; } [XmlElement(ElementName = "IsRead")] public bool IsRead { get; set; } [XmlElement(ElementName = "Iconindex")] public int Iconindex { get; set; } [XmlElement(ElementName = "Sort")] public object Sort { get; set; } [XmlElement(ElementName = "Condition")] public bool Condition { get; set; } [XmlElement(ElementName = "Checked")] public bool Checked { get; set; } [XmlElement(ElementName = "HasInfoButton")] public bool HasInfoButton { get; set; } [XmlElement(ElementName = "HasExecuteButton")] public bool HasExecuteButton { get; set; } [XmlElement(ElementName = "IsBold")] public bool IsBold { get; set; } public override string ToString() { return string.Format("{0}", Text); } } public class ArrayOfDevListViewItem { [XmlElement(ElementName = "DevListViewItem", Namespace = "")] public List<DevListViewItem> DevListViewItem = new(); [XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2001/XMLSchema")] public string Xsi; [XmlAttribute(AttributeName = "xsd", Namespace = "http://www.w3.org/2001/XMLSchema")] public string Xsd; [XmlText] public string Text; } }
解决方案
问题核心是XML中的xsi:type="xsd:string"标记未被正确处理:序列化器试图将其解析为自定义类型,但你的Tag类定义与该逻辑不匹配。以下是两种可行解决方式:
方法一:用object类型+注册已知类型
将Tag改为object类型,并通过XmlInclude注册可能的类型(比如string),让序列化器自动识别并保留xsi:type信息:
public class FilterXMLSchema { [XmlInclude(typeof(string))] public class DevListViewItem { // 其他属性保持不变 [XmlElement(ElementName = "Tag")] public object Tag { get; set; } // 其他属性保持不变 } // 其他类保持不变 }
反序列化后Tag会自动转为string类型,后续序列化时也能正确输出xsi:type标记。
方法二:自定义Tag类并跳过类型解析
如果要保留自定义Tag类,需手动处理xsi:type属性,避免序列化器将其当作类型标记:
// 保持Tag类定义不变 public class Tag { [XmlAttribute("type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")] public string Type { get; set; } [XmlText] public string Text { get; set; } }
创建序列化器时,通过XmlAttributeOverrides告诉序列化器不要解析Tag的xsi:type:
var overrides = new XmlAttributeOverrides(); var attrs = new XmlAttributes(); attrs.XmlElements.Add(new XmlElementAttribute("Tag")); overrides.Add(typeof(DevListViewItem), "Tag", attrs); var serializer = new XmlSerializer(typeof(ArrayOfDevListViewItem), overrides); // 执行反序列化操作
此方式会将xsi:type的值存入Tag.Type,文本存入Tag.Text,完全保留原类型信息。
额外优化:修正命名空间声明处理
原代码中ArrayOfDevListViewItem的Xsi和Xsd属性定义错误,XML中的xmlns:xsi/xsd是命名空间声明,需用XmlNamespaceDeclarations处理:
public class ArrayOfDevListViewItem { [XmlElement(ElementName = "DevListViewItem")] public List<DevListViewItem> DevListViewItem = new(); [XmlNamespaceDeclarations] public XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces(); }
初始化时添加命名空间:
var array = new ArrayOfDevListViewItem(); array.Namespaces.Add("xsd", "http://www.w3.org/2001/XMLSchema"); array.Namespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
内容的提问来源于Stack Exchange,提问作者Gazz
相关产品推荐
相关产品推荐

