您可以将 xml 的旧版本反序列化为更新的结构吗
Can you deserialize and older version of xml into a newer structure
我正在尝试更新正在反序列化的对象。取一个对象,重命名,使用零件并添加一个新对象来容纳其余对象。 .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
to deserialize, if your <objectinfo>
is an immediate child of the root XML element, then deserializing to some DTO type identical to old type and mapping to the new object manually or via 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; }
}
向 ContainerType
添加一个 OnUnknownElement
处理程序,如下所示:
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
处理程序进行后处理。
演示 fiddle here.
我正在尝试更新正在反序列化的对象。取一个对象,重命名,使用零件并添加一个新对象来容纳其余对象。 .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
to deserialize, if your <objectinfo>
is an immediate child of the root XML element, then deserializing to some DTO type identical to old type and mapping to the new object manually or via 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; }
}
向 ContainerType
添加一个 OnUnknownElement
处理程序,如下所示:
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
处理程序进行后处理。
演示 fiddle here.