您可以将旧版本的 xml 反序列化为更新的结构吗
Posted
技术标签:
【中文标题】您可以将旧版本的 xml 反序列化为更新的结构吗【英文标题】:Can you deserialize and older version of xml into a newer structure 【发布时间】:2021-03-31 12:08:14 【问题描述】:我正在尝试更新正在反序列化的对象。取一个对象,重命名,使用部件并添加一个新对象来保存剩余的对象。 .NET 中有没有办法将旧的 XML 反序列化为新格式?
例如
旧结构:
<objectinfo>
<element1></element1>
<element2></element2>
<element3></element3>
<element4></element4>
</objectinfo>
新结构:
<objinfo>
<element1></element1>
<element2></element2>
</objinfo>
<newobject>
<element3></element3>
<element4></element4>
</newobject>
注意我使用XmlSerializer
来反序列化。
【问题讨论】:
使用旧类反序列化并使用新类重新序列化? 好的,只需将旧结构反序列化为类,将数据复制到新的类结构中,然后从新对象中序列化即可。 是的,前提是架构确实需要对象。反序列化只查看 xml 中的标签,并将忽略与 xml 不匹配的类中的对象。在您的情况下,您将 objectinfo 的名称更改为 objinfo,这会出错。 【参考方案1】:假设您使用XmlSerializer
进行反序列化,如果您的<objectinfo>
是根XML 元素的直接子元素,则反序列化为一些与旧类型相同的DTO 类型并手动或通过@ 映射到新对象987654323@很容易解决问题。
但是,如果被修改的对象深深地嵌套在被反序列化的对象层次结构中,那么 DTO 策略就不那么方便了,因为XmlSerializer
不提供通用的代理 DTO 替换机制。在这种情况下,另一种方法是手动处理 XmlSerializer.UnknownElement
事件中的未知元素。
为了做到这一点,一般来说,引入以下 XML 反序列化的接口和扩展方法:
public interface IUnknownElementHandler
void OnUnknownElement(object sender, XmlElementEventArgs e);
public static partial class XmlSerializationHelper
public static T LoadFromXml<T>(this string xmlString, XmlSerializer serializer = null)
serializer = serializer ?? new XmlSerializer(typeof(T)).AddUnknownElementHandler();
using (var reader = new StringReader(xmlString))
return (T)serializer.Deserialize(reader);
public static T LoadFromFile<T>(string filename, XmlSerializer serializer = null)
serializer = serializer ?? new XmlSerializer(typeof(T)).AddUnknownElementHandler();
using (var reader = new FileStream(filename, FileMode.Open))
return (T)serializer.Deserialize(reader);
public static XmlSerializer AddUnknownElementHandler(this XmlSerializer serializer)
serializer.UnknownElement += (o, e) =>
var handler = e.ObjectBeingDeserialized as IUnknownElementHandler;
if (handler != null)
handler.OnUnknownElement(o, e);
;
return serializer;
然后,假设您的新数据模型看起来像像这样,其中Root
是***对象,ContainerType
包含正在重组的元素:
[XmlRoot(ElementName = "Root")]
public class Root
public ContainerType ContainerType get; set;
[XmlRoot(ElementName = "ContainerType")]
public partial class ContainerType
[XmlElement(ElementName = "objinfo")]
public Objinfo Objinfo get; set;
[XmlElement(ElementName = "newobject")]
public Newobject Newobject get; set;
[XmlRoot(ElementName = "objinfo")]
public class Objinfo
[XmlElement(ElementName = "element1")]
public string Element1 get; set;
[XmlElement(ElementName = "element2")]
public string Element2 get; set;
[XmlRoot(ElementName = "newobject")]
public class Newobject
[XmlElement(ElementName = "element3")]
public string Element3 get; set;
[XmlElement(ElementName = "element4")]
public string Element4 get; set;
将OnUnknownElement
处理程序添加到ContainerType
,如下所示:
public partial class ContainerType : IUnknownElementHandler
#region IUnknownElementHandler Members
void IUnknownElementHandler.OnUnknownElement(object sender, XmlElementEventArgs e)
var container = (ContainerType)e.ObjectBeingDeserialized;
var element1 = e.Element.SelectSingleNode("element1");
var element2 = e.Element.SelectSingleNode("element2");
if (element1 != null || element2 != null)
container.Objinfo = container.Objinfo ?? new Objinfo();
if (element1 != null)
container.Objinfo.Element1 = element1.InnerText;
if (element2 != null)
container.Objinfo.Element2 = element2.InnerText;
var element3 = e.Element.SelectSingleNode("element3");
var element4 = e.Element.SelectSingleNode("element4");
if (element3 != null || element4 != null)
container.Newobject = container.Newobject ?? new Newobject();
if (element3 != null)
container.Newobject.Element3 = element3.InnerText;
if (element4 != null)
container.Newobject.Element4 = element4.InnerText;
#endregion
然后,当您使用上述LoadFromFile
方法从文件中反序列化您的Root
时:
var root = XmlSerializationHelper.LoadFromFile<Root>(filename);
过时的未知 XML 元素将由 ContainerType
处理程序进行后处理。
演示小提琴here.
【讨论】:
谢谢。稍微调整一下就可以了。以上是关于您可以将旧版本的 xml 反序列化为更新的结构吗的主要内容,如果未能解决你的问题,请参考以下文章
将 xml 反序列化为对象时出错:System.FormatException 输入字符串格式不正确
将 Xml 反序列化为对象时出错 - xmlns='' 不是预期的