JavaRush /Курси /C# SELF /Валідація XML за до...

Валідація XML за допомогою XSD-схем

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

1. Навіщо потрібна валідація XML

XML — формат дуже гнучкий, місцями навіть занадто. На відміну від суворо типізованих даних, XML «терпить» помилки, і якщо ви забудете закрити тег або хтось запише не те імʼя атрибута, програма може видати помилку вже під час розбору файлу… або взагалі не помітити проблему, що гірше.

Валідація за XSD (XML Schema Definition) — це спосіб переконатися, що ваш XML-файл повністю відповідає заздалегідь описаному контракту: як називаються теги, у якому вони порядку, які типи мають, чи є вони обовʼязковими та скільки їх може бути. Це схоже на паспортний контроль для ваших даних — схема каже: «Тебе сюди не пустять без потрібного поля або якщо поле не тієї довжини!»

Валідація важлива в корпоративних системах, для обміну даними між різними системами, API — скрізь, де небажане «мовчазне» прийняття кривих структур.

XSD (XML Schema Definition) — це окремий XML-документ, що формалізує структуру іншого XML. У XSD ви описуєте: які теги допустимі, які обовʼязкові, які типи мають атрибути та вкладені елементи, шаблони для рядків, обмеження для чисел, навіть можливі значення (через обмеження і перелічення).

XML XSD (опис структури)
<person age="23">Ivan</person>
<element name="person" ... />
<item price="1000"/>
<element name="item" type="..." />

XSD за змістом подібний до JSON Schema у світі JSON.

2. Приклад XSD і пов’язаного XML

Приклад XML

<person age="23">
  <name>Ivan</name>
  <email>ivan@example.com</email>
</person>

Приклад XSD

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:element name="person">
     <xs:complexType>
       <xs:sequence>
         <xs:element name="name" type="xs:string"/>
         <xs:element name="email" type="xs:string" minOccurs="0"/>
       </xs:sequence>
       <xs:attribute name="age" type="xs:positiveInteger" use="required"/>
     </xs:complexType>
   </xs:element>
</xs:schema>

Що описує ця схема:

  • Кореневий елемент — <person>.
  • Усередині <person> мають іти елементи <name> (обовʼязковий) і <email> (необовʼязковий).
  • У <person> має бути атрибут age з додатним цілим значенням.

3. Валідація XML за допомогою XSD у .NET

У .NET типовий підхід — використовувати простори імен System.Xml та System.Xml.Schema.

Схема роботи:

  1. Завантажити XML-файл
  2. Завантажити XSD-схему
  3. Підʼєднати схему для валідації XML
  4. Запустити процес валідації та обробити можливі помилки

Ось базовий приклад:

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;

// 1. Обробник помилок валідації
void ValidationCallBack(object? sender, ValidationEventArgs e)
{
    Console.WriteLine($"Помилка валідації: {e.Message}");
}

string xmlPath = "person.xml";
string xsdPath = "person.xsd";

// 2. Завантажуємо схему
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", xsdPath);

XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas = schemas;
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += ValidationCallBack;

// 3. Відкриваємо XML з урахуванням налаштувань
using XmlReader reader = XmlReader.Create(xmlPath, settings);
while (reader.Read())
{
    // Просто проходимо по документу — валідація відбувається «на льоту»
}

Console.WriteLine("Валідацію завершено!");

Пояснення:

  • Усі помилки валідації буде перехоплено в обробнику подій ValidationCallBack.
  • Якщо помилок немає — документ відповідає схемі (ValidationType.Schema).
  • Якщо є невідповідності (відсутній age, некоректна електронна адреса, додано зайве поле тощо) — вони зʼявляться в консолі.

Різні типи помилок і зворотний зв’язок

Валідація за XSD може «сваритися» з різних причин. Ось найпоширеніші сценарії та приклади помилок:

  • Відсутній обовʼязковий елемент (minOccurs="1" за замовчуванням)
  • Зайвий тег, не описаний у XSD
  • Атрибут неправильного типу (age="abc" замість числа)
  • Рядки не відповідають шаблону (описано через <xs:pattern>)

Типова помилка:

Помилка валідації: Елемент 'age' з текстовим вмістом 'abc' недопустимий. Очікувалося значення типу 'xs:positiveInteger'.

4. Складніші XSD-схеми: типи, перелічення, шаблони

XSD — це фактично мова опису допустимих даних. Ось кілька просунутих прикладів:

Перелічення допустимих значень

<xs:element name="gender">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:enumeration value="male"/>
      <xs:enumeration value="female"/>
      <xs:enumeration value="diverse"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>

Обмеження довжини рядка

<xs:element name="code">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:length value="8"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>

Шаблон для email (спрощений)

<xs:element name="email">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:pattern value="\w+@\w+\.\w+"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>

Можна створювати власні типи, успадковувати їх, використовувати вкладені елементи — практично як в ООП!

5. Валідація складного документа

Уявімо, що наш навчальний застосунок тепер експортує список студентів у XML. Додаймо трохи коду!

Приклад XML

<students>
  <student id="1">
    <name>Elena</name>
    <grade>5</grade>
  </student>
  <student id="2">
    <name>Alexey</name>
    <grade>4</grade>
  </student>
</students>

XSD-схема

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="students">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="student" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="name" type="xs:string"/>
              <xs:element name="grade">
                <xs:simpleType>
                  <xs:restriction base="xs:integer">
                    <xs:minInclusive value="1"/>
                    <xs:maxInclusive value="5"/>
                  </xs:restriction>
                </xs:simpleType>
              </xs:element>
            </xs:sequence>
            <xs:attribute name="id" type="xs:integer" use="required"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Валідація в коді (з тими самими прийомами):

// Шляхи до файлів
string xmlPath = "students.xml";
string xsdPath = "students.xsd";

XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", xsdPath);

XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas = schemas;
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += ValidationCallBack;

using XmlReader reader = XmlReader.Create(xmlPath, settings);
while (reader.Read()) { /* усе, як раніше */ }

6. Корисні нюанси

Як вказати схему безпосередньо в XML (xsi:schemaLocation)

На практиці часто трапляються XML-файли, де безпосередньо в кореневому елементі є атрибути xsi:schemaLocation або xsi:noNamespaceSchemaLocation:

<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="students.xsd">
    ...
</students>

Це не запускає валідацію автоматично, але деяким валідаторам і редакторам допомагає знайти схему для перевірки. У .NET це не обовʼязково, проте формально коректно.

Валідація «на льоту» і в памʼяті — з XDocument

Якщо ви працюєте з LINQ to XML (XDocument), можна також валідувати XML-документ у памʼяті, не використовуючи файли:

using System.Xml.Linq;
using System.Xml.Schema;

// Завантаження схеми
XmlSchemaSet schema = new XmlSchemaSet();
schema.Add("", "students.xsd");

// Завантаження XML у пам’ять
XDocument doc = XDocument.Load("students.xml");

// Валідація
doc.Validate(schema,
    (o, e) => Console.WriteLine($"Помилка: {e.Message}"),
    true // Перевіряти попередження (зазвичай надмірно)
);

Цей підхід зручний, якщо ви програмно створюєте або модифікуєте XML і хочете переконатися, що не породили некоректний XML, який порушує схему.

7. Типові помилки під час валідації XML з XSD

Помилка №1: забули підʼєднати схему або вказали неправильний шлях до XSD.
У результаті валідація не виконується, і XML-файл проходить «крізь охорону», навіть якщо в ньому є помилки. Часто шлях указують відносний, а застосунок шукає файл у неочікуваному місці. Для тестів краще використовувати абсолютний шлях або розмістити схему поруч із виконуваним файлом.

Помилка №2: не збігаються простори імен (namespace).
Якщо ваша схема використовує простір імен, ви маєте передати його другим аргументом під час додавання схеми в XmlSchemaSet.Add. Інакше валідація завершиться помилкою, навіть якщо структура XML коректна. Якщо простору імен немає — передавайте порожній рядок.

Помилка №3: невідповідність порядку елементів.
Якщо в схемі чітко задано <xs:sequence>, то порядок елементів має значення. XML, у якому правильні елементи йдуть у неправильному порядку, вважатиметься помилковим.

Помилка №4: у XML вказано кілька просторів імен.
Якщо документ використовує більше ніж один namespace, це може призвести до неочікуваних збоїв під час валідації. Підтримка кількох просторів імен потребує особливої уваги та точного налаштування схеми.

Помилка №5: не збираються і не зберігаються помилки.
Виведення помилок прямо в консоль може підійти для налагодження, але не для продукційного застосунку. Краще збирати помилки у список і показувати користувачеві в зручному вигляді — особливо під час масової перевірки файлів (наприклад, на веб-сервері).

1
Опитування
Робота з XML-даними, рівень 48, лекція 4
Недоступний
Робота з XML-даними
Налаштування серіалізації XML
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ