Привет, Хабр!
Обработка XML-данных остаётся актуальной задачей несмотря на появление более крутых технологий для работы с данными. XML — это все еще гибкий и мощный инструмент для структурирования данных, который используется в самых разнообразных приложениях.
В статье рассмотрим как работать с XML в C#.
Работа с XML в C#
Начнем с базы.
XmlDocument
— это класс, который позволяет работать с XML в доменной модели. Можно загружать, изменять и сохранять XML-документы. Читать XML можно через методыLoad
и LoadXml
, которые считывают данные из файлов или строк. Создание новых узлов и атрибутов происходит с помощью методов CreateElement
и CreateAttribute
, после чего элементы добавляются в документ с помощью AppendChild
.
Cоздадим XML-документ, добавим в него элементы и атрибуты, а затем сохраним его:
using System;
using System.Xml;
class Program
{
static void Main()
{
// новый XML-документ
XmlDocument doc = new XmlDocument();
// корневой элемент
XmlElement root = doc.CreateElement("users");
doc.AppendChild(root);
// новый элемент
XmlElement user = doc.CreateElement("user");
root.AppendChild(user);
// атрибут для элемента user
XmlAttribute attr = doc.CreateAttribute("id");
attr.Value = "1";
user.Attributes.Append(attr);
// вложенные элементы в элемент user
XmlElement firstName = doc.CreateElement("firstName");
firstName.InnerText = "John";
user.AppendChild(firstName);
XmlElement lastName = doc.CreateElement("lastName");
lastName.InnerText = "Doe";
user.AppendChild(lastName);
// сейвим XML-документ в файл
doc.Save("users.xml");
}
}
Но есть способы получше.
XmlReader и XmlWriter
XmlReader
и XmlWriter
предоставляют более производительные альтернативы для чтения и записи XML по сравнению с DOM, т.к они работают в потоковом режиме. XmlReader
читает XML поэлементно.
Пример XmlReader:
using System;
using System.Xml;
class Program
{
static void Main()
{
// создаем XmlReader для чтения файла
using (XmlReader reader = XmlReader.Create("example.xml"))
{
while (reader.Read()) // чтение некст элемента
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "name")
{
Console.WriteLine(reader.ReadElementContentAsString()); // читаем содержимое элемента <name>
}
}
}
}
}
Здесь юзаем XmlReader
для поэлементного чтения XML-файла. Фильтруем элементы по типу узла XmlNodeType.Element
и имени name
, чтобы извлечь информацию только из тех элементов, которые нас интересуют.
Пример XmlWriter:
using System;
using System.Xml;
class Program
{
static void Main()
{
// создаем XmlWriter
using (XmlWriter writer = XmlWriter.Create("output.xml"))
{
writer.WriteStartDocument(); // начало документа
writer.WriteStartElement("users"); // начало корневого элемента <users>
writer.WriteStartElement("user"); // начало элемента <user>
writer.WriteElementString("name", "Ivan"); //добавление <name>
writer.WriteEndElement(); // закрытие элемента <user>
writer.WriteEndElement(); // закрытие корневого элемента <users>
writer.WriteEndDocument(); // закрытие документа
}
}
}
Используем XmlWriter
для создания нового XML-файла с простой структурой. Стартуем с создания корневого элемента <users>
, добавляем в него дочерний элемент <user>
с вложенным элементом <name>
, и последовательно закрываем все открытые элементы и документ.
XDocument
Также существует XDocument
и связанные с ним классы XElement
, XAttribute
.
XElement
— это отдельный элемент в XML-документе и он позволяет управлять содержимым элемента, включая его вложенные элементы, текст и атрибуты.
XAttribute
служит для работы с атрибутами XML-элементов. Атрибуты представляют собой пары имя-значение, которые прикрепляются к элементам.
Cоздадим простой XML-документ, который содержит инфу о нескольких юзерах, каждый из которых имеет уникальный идентификатор и имя:
using System;
using System.Xml.Linq;
class Program
{
static void Main()
{
// новый XML-документа
XDocument xmlDoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("users", // корневой элемент
new XElement("user", // дочерний элемент
new XAttribute("id", "1"), // атрибут элемента user
new XElement("name", "Ivan")
),
new XElement("user",
new XAttribute("id", "2"),
new XElement("name", "Kolya")
)
)
);
Console.WriteLine(xmlDoc.ToString());
// сохранение XML-документа в файл
xmlDoc.Save("users.xml");
}
}
XDocument
создаёт новый XML-документ.
XElement
используется для создания элементов users
и user
. Элемент users
служит корневым элементом, а user
— дочерним элементом, представляющим пользователя.
XAttribute
применяется для добавления атрибутов к элементу user
, в данном случае это идентификатор пользователя.
LINQ
Можно интегрировать LINQ с XML и сделать код более читабельным.
Например, так можно сделать чтение и запрос данных:
using System;
using System.Linq;
using System.Xml.Linq;
class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");
var books = from book in doc.Descendants("book")
where (int)book.Attribute("id") == 1
select new
{
Title = book.Element("title").Value,
Author = book.Element("author").Value
};
foreach (var book in books)
{
Console.WriteLine($"Title: {book.Title}, Author: {book.Author}");
}
}
}
А так сделать агрегацию данных из XML:
using System;
using System.Xml.Linq;
using System.Linq;
class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");
var bookCount = doc.Descendants("book").Count(); // cчитаем количество книг
var maxId = doc.Descendants("book").Max(book => (int)book.Attribute("id")); // Находим максимальный id
Console.WriteLine($"Total books: {bookCount}, Max ID: {maxId}");
}
}
Десериализация XML и обработка исключений
Для начала десериализации нужно создать класс, структура которого соответствует структуре XML документа. Этот класс должен содержать поля или свойства, соответствующие элементам XML.
Создаем экземпляр XmlSerializer
, указав тип объекта, который нужно десериализовать:
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
Также используемXmlSerializer
для чтения XML из файла или потока и его преобразования в объект. Чаще всего используется StreamReader
или StringReader
:
using (StreamReader reader = new StreamReader("path_to_file.xml"))
{
MyClass myObject = (MyClass)serializer.Deserialize(reader);
}
При десериализации могут возникать различные исключения, например, InvalidOperationException
при несоответствии XML схемы ожидаемому классу или XmlException
при синтаксических ошибках в XML. Обрабатывать эти исключения можно с помощью блоков try-catch
:
try
{
using (StreamReader reader = new StreamReader("path_to_file.xml"))
{
MyClass myObject = (MyClass)serializer.Deserialize(reader);
}
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Invalid XML format: {ex.Message}");
}
catch (XmlException ex)
{
Console.WriteLine($"XML Parsing Error at line {ex.LineNumber}: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"General error: {ex.Message}");
}
Рассмотрим класс Person
и XML файл, который содержит данные о человеке:
<Person>
<Name>Ivan</Name>
<Age>30</Age>
</Person>
Соответствующий класс Person
в C# будет выглядеть так:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Десериализация этого XML в объект Person
с XmlSerializer
выглядит так:
string xmlData = @"<Person><Name>John Doe</Name><Age>30</Age></Person>";
using (StringReader stringReader = new StringReader(xmlData))
{
XmlSerializer serializer = new XmlSerializer(typeof(Person));
Person person = (Person)serializer.Deserialize(stringReader);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
XML схемы и валидация в C#
XML схемы — это формальное описание структуры XML документа, в которым описаны все ограничения на содержимое и структуру элементов и атрибутов. Так можно автоматом проверять, что XML документы соответствуют заданным стандартам.
XML схема обычно определяет элементы и атрибуты, которые могут появляться в документе, их типы данных, и другие ограничения. Например, схема для описания книг в библиотеке может выглядеть так:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="library">
<xs:complexType>
<xs:sequence>
<xs:element name="book" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
<xs:element name="isbn" type="xs:string"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Для валидации XML документа в соответствии с XSD схемой, можно использовать классы XmlReader
и XmlReaderSettings
из пространства имен System.Xml.Schema
. Например:
using System;
using System.Xml;
using System.Xml.Schema;
class Program
{
static void Main()
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add(null, "library.xsd");
settings.ValidationType = ValidationType.Schema;
XmlReader reader = XmlReader.Create("library.xml", settings);
XmlDocument document = new XmlDocument();
document.Load(reader);
ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);
document.Validate(eventHandler);
}
static void ValidationEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Error)
{
Console.WriteLine("Error: {0}", e.Message);
}
else if (e.Severity == XmlSeverityType.Warning)
{
Console.WriteLine("Warning: {0}", e.Message);
}
}
}
Таким образом можно обеспечить, что XML документы точно соответствуют определенным структурам и правилам.
Современные приложения иногда потребляют очень много памяти. Приглашаем вас на бесплатный урок, на котором будут рассмотрены основные приемы эффективной работы и экономии памяти в современных .net приложениях, и как помогают в этом ArrayPool, Span.