您可以将 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 很容易解决问题。

但是,如果被修改的对象深深嵌套在被反序列化的对象层次结构中,那么 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.