如何解决您可以将旧版本的 xml 反序列化为更新的结构吗
我正在尝试更新被反序列化的对象。取一个对象,重命名,使用部件并添加一个新对象来保存剩余的对象。 .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
进行反序列化。
解决方法
假设您使用 XmlSerializer
进行反序列化,如果您的 <objectinfo>
是根 XML 元素的直接子元素,则反序列化为与旧类型相同的某个 DTO 类型并映射到手动或通过 automapper 新建对象很容易解决问题。
但是,如果被修改的对象深深嵌套在正在反序列化的对象层次结构中,那么 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
}
然后,当您使用上述 Root
方法从文件中反序列化 LoadFromFile
时:
var root = XmlSerializationHelper.LoadFromFile<Root>(filename);
过时的、未知的 XML 元素将由 ContainerType
处理程序进行后处理。
演示小提琴here。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。