1. Вступ
XML — абревіатура від eXtensible Markup Language. Уявіть собі дуже суворий і балакучий JSON, який без кінця повторює: «я структурований, повірте мені!». XML — текстовий формат, у якому дані обрамлені тегами:
<Player>
<Name>Aragorn</Name>
<Health>100</Health>
</Player>
Навіщо нам серіалізувати обʼєкти в XML у наші дні?
- XML і далі широко використовують в інтеграції між великими (часто «legacy») системами, де потрібні не лише структура, а й валідація за суворими схемами (XSD).
- XML часто застосовують у корпоративних конфігураціях (наприклад, App.config і Web.config у .NET старіших версій).
- XML добре підходить для завдань, де важлива «самоописуваність» структури даних.
Цікавий факт: XML від початку проєктували так, щоб бути якнайбільш «розширюваним» і валідованим; звідси й назва. Його можна перевірити на відповідність схемі, чого досі немає у JSON «з коробки».
XmlSerializer: головний герой
У .NET за серіалізацію обʼєктів у XML відповідає клас System.Xml.Serialization.XmlSerializer.
- Він перетворює публічні властивості та поля обʼєкта на елементи XML і, навпаки, за XML відновлює обʼєкт.
- Працює лише з публічними типами та членами класів.
- Не серіалізує приватні поля й властивості — лише те, що публічне!
- Потребує наявності порожнього конструктора в серіалізованому класі.
Зверніть увагу: Якщо ваш клас не відповідає цим вимогам, XmlSerializer просто не зможе з ним працювати — кине виняток на етапі серіалізації або десеріалізації.
2. Простий приклад — серіалізація обʼєкта в XML
Розгляньмо, як серіалізувати наш улюблений клас Player у XML.
Крок 1. Описуємо клас
public class Player
{
public string Name { get; set; }
public int Health { get; set; }
public bool IsAlive { get; set; }
// Важливо: потрібен публічний конструктор без параметрів!
public Player() { }
// Необовʼязково: для зручності
public Player(string name, int health, bool isAlive)
{
Name = name;
Health = health;
IsAlive = isAlive;
}
}
Крок 2. Серіалізуємо у файл
using System.Xml.Serialization;
Player aragorn = new Player("Aragorn", 100, true);
// 1. Створюємо серіалізатор для типу Player
XmlSerializer serializer = new XmlSerializer(typeof(Player));
// 2. Відкриваємо файл для запису (створиться, якщо не існує)
using FileStream fs = new FileStream("player.xml", FileMode.Create);
// 3. Серіалізуємо обʼєкт у XML
serializer.Serialize(fs, aragorn);
Результат (player.xml):
<?xml version="1.0"?>
<Player xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Aragorn</Name>
<Health>100</Health>
<IsAlive>true</IsAlive>
</Player>
Візуальна схема найпростішого процесу
Обʼєкт у памʼяті ---> XmlSerializer.Serialize() ---> XML-файл на диску
3. Десеріалізація — «оживлюємо» обʼєкт із XML
Коли потрібно прочитати раніше серіалізований обʼєкт, процес зворотний:
using FileStream fs = new FileStream("player.xml", FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(Player));
Player player = (Player)serializer.Deserialize(fs);
Console.WriteLine($"Імʼя: {player.Name}, Здоровʼя: {player.Health}, Живий: {player.IsAlive}");
У результаті програма виведе: Імʼя: Aragorn, Здоровʼя: 100, Живий: True
4. Серіалізація в рядок — не лише у файл
Серіалізація в рядок
Не завжди потрібно серіалізувати обʼєкт у файл. Іноді, наприклад, слід передати XML як рядок мережею або показати на екрані.
using System.IO;
using System.Xml.Serialization;
Player player = new Player("Frodo", 42, true);
XmlSerializer serializer = new XmlSerializer(typeof(Player));
StringWriter stringWriter = new StringWriter();
serializer.Serialize(stringWriter, player);
string xmlString = stringWriter.ToString();
Console.WriteLine(xmlString); // Увесь рядок XML — на екрані!
Десеріалізація з рядка
Аналогічно можна десеріалізувати обʼєкт не з файлу, а з рядка:
string xml = "<Player Name=\"Frodo\"><HP>42</HP></Player>";
XmlSerializer serializer = new XmlSerializer(typeof(Player));
using StringReader stringReader = new StringReader(xml);
Player frodo = (Player)serializer.Deserialize(stringReader);
Console.WriteLine(frodo.Name); // Frodo
5. Налаштування XML: атрибути для керування структурою
Іноді стандартна поведінка вас не влаштовує. XML виходить надто багатослівним або теги не збігаються з потрібними. На допомогу приходять різні «магічні» атрибути — вони прямо вказують серіалізатору, як відображати члени класу.
Найкорисніші:
— задає імʼя елемента.[XmlElement]
— робить поле атрибутом XML, а не елементом.[XmlAttribute]
— вилучає властивість із серіалізації.[XmlIgnore]
і[XmlArray]
— керують пакуванням колекцій.[XmlArrayItem]
Приклад використання:
public class Player
{
[XmlAttribute]
public string Name { get; set; }
[XmlElement("HP")]
public int Health { get; set; }
[XmlIgnore]
public bool IsTempSessionPlayer { get; set; }
}
Підсумковий XML:
<Player Name="Aragorn">
<HP>100</HP>
</Player>
Таблиця основних атрибутів для серіалізації
| Атрибут | На що впливає | Приклад використання |
|---|---|---|
|
Перетворює властивість на атрибут XML | |
|
Змінює імʼя тега | замість |
|
Повністю вилучає властивість із серіалізації | — |
|
Змінює імʼя «обгортки» колекції | |
|
Змінює імʼя елемента колекції | |
Приклад складної серіалізації колекції:
public class GameWorld
{
[XmlArray("Heroes")]
[XmlArrayItem("Hero")]
public List<Player> Players { get; set; } = new List<Player>();
}
XML:
<GameWorld>
<Heroes>
<Hero Name="Legolas">
<HP>90</HP>
</Hero>
<!-- ... -->
</Heroes>
</GameWorld>
Більше про налаштування XML дізнаєтеся в наступних лекціях! :P
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ