Можете ли вы десериализовать и более старую версию 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 для десериализации.

Десериализовать, используя старый класс, и повторно сериализовать, используя новый?

Camilo Terevinto 21.12.2020 18:56

Конечно, просто десериализуйте старую структуру в классы, скопируйте данные в новую структуру классов и выполните сериализацию из новых объектов.

Robert Harvey 21.12.2020 18:57

Да, если схема требует объекты. Deserialize просматривает только теги в xml и игнорирует объекты в классах, которые не соответствуют xml. В вашем случае вы изменили имя objectinfo на objinfo, что приведет к ошибкам.

jdweng 21.12.2020 19:01
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
3
81
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предполагая, что вы используете 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.

Демонстрационная рабочий пример здесь.

Спасибо. Немного подправить и должно получиться.

Paul Tracy 21.12.2020 20:27

Другие вопросы по теме