带命名空间与无命名空间的XML如何统一反序列化不抛出异常
问题根因
你当前的ExportData类通过XmlRoot特性硬编码了固定命名空间,因此只能匹配对应命名空间的XML文件,无命名空间的文件会因节点不匹配抛出异常。
解决方案
推荐优先使用动态检测命名空间+序列化器缓存的方案,兼容性最好、实现成本最低:
// 全局缓存序列化器,解决XmlSerializer动态构造的内存泄漏问题 private static readonly ConcurrentDictionary<string, XmlSerializer> _serializerCache = new(); public static ExportData DeserializeXml(Stream xmlStream) { // 重置流位置避免读空 xmlStream.Position = 0; using var reader = XmlReader.Create(xmlStream, new XmlReaderSettings { IgnoreWhitespace = true }); // 定位到根节点获取实际命名空间 reader.MoveToContent(); string rootNs = reader.NamespaceURI; // 缓存中存在对应序列化器直接用,不存在则新建 var serializer = _serializerCache.GetOrAdd(rootNs, ns => new XmlSerializer(typeof(ExportData), new XmlRootAttribute("ExportData") { Namespace = ns, IsNullable = false })); // 再次重置流后执行反序列化 xmlStream.Position = 0; return (ExportData)serializer.Deserialize(xmlStream); }
该方案无需修改你现有ExportData类的任何特性配置,可兼容任意命名空间的根节点
如果不需要严格校验命名空间,也可以选择自定义XmlReader全局忽略命名空间:
// 自定义XmlReader包装类,统一返回空命名空间 public class NamespaceIgnoringXmlReader : XmlReaderWrapper { public NamespaceIgnoringXmlReader(XmlReader reader) : base(reader) { } public override string NamespaceURI => ""; } // 调用示例 var ser = new XmlSerializer(typeof(ExportData)); using var sr = new StreamReader(xmlFilePath); using var rawReader = XmlReader.Create(sr, new XmlReaderSettings { IgnoreWhitespace = true }); using var nsIgnoringReader = new NamespaceIgnoringXmlReader(rawReader); var result = (ExportData)ser.Deserialize(nsIgnoringReader);
该方案需要自行实现XmlReaderWrapper抽象类,将所有基础方法转发到内部封装的XmlReader实例,仅重写NamespaceURI属性即可
内容的提问来源于stack exchange,提问作者CorrieJanse
相关产品推荐
相关产品推荐

