Я пытаюсь обновить десериализуемые объекты. Взять один объект, переименовать, использовать части и добавить новый объект, который будет содержать оставшиеся объекты. Есть ли способ в .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
для десериализации.
Конечно, просто десериализуйте старую структуру в классы, скопируйте данные в новую структуру классов и выполните сериализацию из новых объектов.
Да, если схема требует объекты. Deserialize просматривает только теги в xml и игнорирует объекты в классах, которые не соответствуют xml. В вашем случае вы изменили имя objectinfo на objinfo, что приведет к ошибкам.
Предполагая, что вы используете 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
.
Демонстрационная рабочий пример здесь.
Спасибо. Немного подправить и должно получиться.
Десериализовать, используя старый класс, и повторно сериализовать, используя новый?