Serializacja i deserializacja XML-a
XML – czym jest?
XML, czyli Extensible Markup Language jest popularnym sposobem zapisu danych w formie tekstowej. Przez drzewiastą strukturę i słowny zapis wartości oraz nazw właściwości jest łatwy do zrozumienia. Przy pracy z XML mamy kilka możliwości. Możemy go deserializować do postaci obiektów oraz serializować obiekty do xml-a. Możemy także załadować strukturę do pamięci i przetwarzać je z wykorzystaniem DOM API lub z wykorzystaniem nowszego LINQ to XML API. Dzisiaj skupię się na serializacji obiektów z wykorzystaniem wcześniej przygotowanych klas.
Przygotowanie klasy do serializacji
Jeśli jesteśmy szczęśliwymi posiadaczami schematu dokumentu w postaci pliku *.XSD lub w naszym xml-u nie ma wartości opcjonalnych, możemy wykorzystać program XSD.EXE (dziś tylko o nim wspominam,
a w następnym poście powiem o nim nieco więcej). Możemy również sami wygenerować potrzebne nam klasy. Wiedząc jak wygląda schemat
(np. z dokumentacji) jesteśmy w stanie napisać wszystkie niezbędne klasy. Serializacja xml-a w dużej mierze wykorzystuje atrybuty, może pamiętasz jak o nich pisałem https://mateuszstanek.pl/2018/02/03/atrybut-c/. Standardowa biblioteka do obsługi serializacji xml-owej dodaje ich kilka, dzięki czemu będziemy mogli z sukcesem przetwarzać nasze obiekty
i xml-e. Kilka najważniejszych z nich to:
- xmlRoot – określa właściwości głównego elementu.
- xmlElement – określa parametry mapowania właściwości na element.
- xmlAttribute – określa parametry mapowania właściwości na atrybut.
- xmlIgnore – określa, iż oznaczona właściwość ma zostać pominięta przy serializacji/deserializacji.
Z ich pomocą jesteśmy w stanie obsłużyć większość przypadków użycia.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
[XmlRoot(ElementName ="Data")] public class TransferData { [XmlAttribute(AttributeName ="Name")] public string UserName { get; set; } [XmlAttribute(AttributeName = "Date")] public DateTime TimeStamp { get; set; } [XmlElement("DataObject")] public List<KeyValueData> DataSet { get; set; } [XmlElement(ElementName ="ElementsCount")] public int DataCount { get { return DataElementsCount; } set { //noithing to do } } [XmlIgnore] public int DataElementsCount { get { return DataSet?.Count ?? 0; } } } |
Dziwne podwojenie DataCount jest moją próbą pokazania jak działa XmlIgnore.
Plik xml wygląda mniej więcej tak :
1 2 3 4 5 6 7 8 9 10 11 12 |
<?xml version="1.0" encoding="utf-8"?> <RootElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Atrybut1="wartoscAtrybutu1" abrybut2="wartosc"> <Element1> <Element1ofElement1>Value</Element1ofElement1> <Element2ofElement1>Value2</Element2ofElement1> </Element1> <Element1> <Element1ofElement1>Value</Element1ofElement1> <Element2ofElement1>Value2</Element2ofElement1> </Element1> <Element2>Value of element 2</Element2> </RootElement> |
Serializacja- deserializacja
Skoro mamy już klasę przygotowaną, pora ją zserializować. Do serializacji oprócz naszych danych potrzebujemy XmlSerializera oraz strumienia,
do którego go zapiszemy.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var serialize = new XmlSerializer(typeof(TransferData)); TransferData testObject = new TransferData(); testObject.UserName = "Mateusz Stanek"; testObject.TimeStamp = DateTime.Now; testObject.DataSet = new List<KeyValueData>(); testObject.DataSet.Add(new KeyValueData { Key = "Path" , Value="Some path"}); testObject.DataSet.Add(new KeyValueData { Key = "Reference number", Value = "1287394" }); testObject.DataSet.Add(new KeyValueData { Key = "TestObject", Value = "Object123" }); using (var stream = new StreamWriter("SerializedObject.xml", false)) { serialize.Serialize(stream, testObject); } |
Deserializacja jest równie prosta, wykorzystujemy ten sam serializer, używamy jednak metodę deserialize, która przyjmuje tylko strumień danych wejściowych. Należy pamiętać, iż deserializer zwraca nam obiekt, który należy rzutować na wybrany przez nas typ.
1 2 3 4 5 6 7 8 |
var serialize = new XmlSerializer(typeof(TransferData)); TransferData readedData = null; using (var stream = new StreamReader("SerializedObject.xml")) { readedData = (TransferData) serialize.Deserialize(stream); } |
Przykład Serializacji na GitHubie https://github.com/Matejkos/BlogProjects/tree/master/OperationsOnXML
To be Continued