JavaRush /Курси /C# SELF /Робота з XmlSerializer

Робота з XmlSerializer для серіалізації в XML

C# SELF
Рівень 44 , Лекція 2
Відкрита

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]
    — задає імʼя елемента.
  • [XmlAttribute]
    — робить поле атрибутом XML, а не елементом.
  • [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>

Таблиця основних атрибутів для серіалізації

Атрибут На що впливає Приклад використання
[XmlAttribute]
Перетворює властивість на атрибут XML
<Player Name="Aragorn">...</Player>
[XmlElement]
Змінює імʼя тега
<HP>100</HP>
замість
<Health>100</Health>
[XmlIgnore]
Повністю вилучає властивість із серіалізації
[XmlArray]
Змінює імʼя «обгортки» колекції
<Heroes> ... <Heroes>
[XmlArrayItem]
Змінює імʼя елемента колекції
<Hero>...<Hero>

Приклад складної серіалізації колекції:

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

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ