- •А.А. Волосевич
- •Содержание
- •1. Работа с числами
- •2. Представление даты и времени
- •3. Работа со строками и текстом
- •4. Преобразование информации
- •5. Сравнение для выяснения равенства
- •6. Сравнение для выяснения порядка
- •7. Жизненный цикл объектов
- •7.1. Алгоритм сборки мусора
- •7.2. Финализаторы и интерфейс iDisposable
- •7.3. Слабые ссылки
- •8. Перечислители и итераторы
- •9. Стандартные интерфейсы коллекций
- •10. Массивы и класс System.Array
- •11. Типы для работы с коллекциями-списками
- •12. Типы для работы с коллекциями-множествами
- •13. Типы для работы с коллекциями-словарями
- •14. Типы для создания пользовательских коллекций
- •15. Технология linq to Objects
- •1. Оператор условия Where().
- •2. Операторы проекций.
- •3. Операторы упорядочивания.
- •4. Оператор группировки GroupBy().
- •5. Операторы соединения.
- •6. Операторы работы с множествами.
- •7. Операторы агрегирования.
- •8. Операторы генерирования.
- •9. Операторы кванторов и сравнения.
- •10. Операторы разбиения.
- •11. Операторы элемента.
- •12. Операторы преобразования.
- •16. Работа с объектами файловой системы
- •17. Ввод и вывод информации
- •17.1. Потоки данных и декораторы потоков
- •2. Классы для работы с потоками, связанными с хранилищами.
- •3. Декораторы потоков.
- •4. Адаптеры потоков.
- •17.2. Адаптеры потоков
- •18. Основы xml
- •19. Технология linq to xml
- •20. Дополнительные возможности обработки xml
- •21. Сериализация времени выполнения
- •22. Контракты данных и xml-сериализация
- •23. Состав и взаимодействие сборок
- •24. Метаданные и получение информации о типах
- •25. Позднее связывание и кодогенерация
- •26. Атрибуты
- •27. Динамическое связывание
- •28. Файлы конфигурации
- •29. Диагностика и мониторинг
- •30. Процессы и домены
- •31. Основы многопоточного программирования
- •32. Синхронизация потоков
- •32.1. Критические секции
- •32.2. Синхронизация на основе подачи сигналов
- •32.3. Неблокирующие средства синхронизации
- •32.4. Разделение данных между потоками
- •33. Библиотека параллельных задач
- •33.1. Параллелизм на уровне задач
- •33.2. Параллелизм при императивной обработке данных
- •33.3. Параллелизм при декларативной обработке данных
- •33.4. Обработка исключений и отмена выполнения задач
- •33.5. Коллекции, поддерживающие параллелизм
- •34. Асинхронный вызов методов
- •Литература
20. Дополнительные возможности обработки xml
В дополнение к LINQ to XML, платформа .NET содержит несколько программных интерфейсов для работы с XML. Для этого обычно используются классы из пространств имён вида System.Xml.* (сборка System.Xml.dll).
Классы XmlReader и XmlWriter – это основа механизма последовательного чтения, обработки и записи XML-документов. Такой подход выгодно использовать, когда документ слишком велик, чтобы читать его в память целиком, или содержит ошибки в структуре.
Для чтения XML-документов применяется класс XmlReader и его наследники XmlTextReader (чтение на основе текстового потока), XmlNodeReader (разбор XML из объектов XmlNode) и XmlValidatingReader (чтение с проверкой схемы XML-документа). Класс XmlReader содержит статический метод Create(), создающий объект для чтения на основе Stream, TextReader или строки URI (частный случай URI – имя файла):
XmlReader reader = XmlReader.Create("planets.xml");
Метод Create() принимает в качестве дополнительного аргумента объект класса XmlReaderSettings, который задаёт различные опции чтения данных:
// игнорируем при чтении комментарии и пробельные символы
var settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreWhitespace = true;
XmlReader reader = XmlReader.Create("planets.xml", settings);
Объект XmlReader извлекает XML-конструкции из документа при помощи метода Read()1. Тип текущей конструкции можно узнать, используя свойство NodeType, значениями которого являются элементы перечисления XmlNodeType. В табл. 15 приведены основные элементы этого перечисления. С конструкцией работают, применяя свойства Name (имя элемента), Value (данные элемента) и некоторые другие.
Таблица 15
Основные элементы перечисления XmlNodeType
Значение |
Пример |
CDATA |
<![CDATA[ This is CDATA info ]]> |
Comment |
<!-- первые четыре планеты --> |
Document |
<planets> (корневой элемент) |
Element |
<planet> |
EndElement |
</planet> |
ProcessingInstruction |
<?perl lower-to-upper-case ?> |
Text |
Mercury |
Whitespace |
\r \t \n (перевод строки, табуляция) |
XmlDeclaration |
<?xml version="1.0" encoding="utf-8" ?> |
Следующий пример демонстрирует разбор XML-файла и печать разобранных конструкций:
var settings = new XmlReaderSettings {IgnoreWhitespace = true};
using (var r = XmlReader.Create("planets.xml", settings))
{
while (r.Read())
{
Console.Write("{0}\t", r.Depth);
switch (r.NodeType)
{
case XmlNodeType.Element:
case XmlNodeType.EndElement:
Console.WriteLine(r.Name);
break;
case XmlNodeType.Text:
case XmlNodeType.Comment:
case XmlNodeType.XmlDeclaration:
Console.WriteLine(r.Value);
break;
}
}
}
Для чтения атрибутов текущего элемента можно использовать индексатор XmlReader, указав имя или позицию атрибута (если атрибута не существует, индексатор вернёт значение null):
// переписанный фрагмент оператора switch из предыдущего примера
switch (r.NodeType)
{
case XmlNodeType.Element:
Console.WriteLine(r.Name);
string attribute = r["units"];
Console.WriteLine(attribute ?? string.Empty);
break;
. . .
}
Набор методов класса XmlReader, начинающихся с префикса MoveTo (MoveToNextElement() и т. п.), может использоваться для перехода к следующей XML-конструкции в потоке. Вернуться к просмотренным конструкциям нельзя.
Класс XmlWriter – это абстрактный класс для создания XML-данных. Подчеркнём, что XML-данные всегда могут быть сформированы в виде простой строки и затем записаны в любой поток. Однако такой подход не лишён недостатков – возрастает вероятность неправильного формирования структуры XML из-за элементарных ошибок. Класс XmlWriter и его наследники (например, XmlTextWriter) предоставляют более «помехоустойчивый» способ генерации XML-документа.
Приведём пример работы с классом XmlWriter.
// опция для формирования отступов в документе
var settings = new XmlWriterSettings {Indent = true };
using (var writer = XmlWriter.Create("customers.xml", settings))
{
// начинаем с XML-декларации
writer.WriteStartDocument();
// открывающий тег с двумя атрибутами
writer.WriteStartElement("customer");
writer.WriteAttributeString("id", "1");
writer.WriteAttributeString("status", "archived");
// вложенный элемент со строковым содержимым
writer.WriteElementString("name", "Alex");
// так пишутся элементы с не строковым содержимым
// для этого используется метод WriteValue()
writer.WriteStartElement("birthdate");
writer.WriteValue(new DateTime(1975, 8, 4));
writer.WriteEndElement();
// закрывающие теги (принцип стека)
writer.WriteEndElement();
writer.WriteEndDocument();
}
Этот пример формирует следующий XML-документ:
<?xml version="1.0" encoding="utf-8"?>
<customer id="1" status="archived">
<name>Alex</name>
<birthdate>1975-08-04T00:00:00</birthdate>
</customer>
Классы XmlNode, XmlAttribute, XmlElement, XmlDocument служат для представления XML-документа в виде дерева объектов. Программный интерфейс, основанный на использовании данных классов, являлся предшественником LINQ to XML. В связи с этим ограничимся только простым примером, демонстрирующим работу с указными классами:
public static void OutputNode(XmlNode node)
{
Console.WriteLine("Type= {0} \t Name= {1} \t Value= {2}",
node.NodeType, node.Name, node.Value);
if (node.Attributes != null)
{
foreach (XmlAttribute attr in node.Attributes)
{
Console.WriteLine("Type={0} \t Name={1} \t Value={2}",
attr.NodeType, attr.Name, attr.Value);
}
}
// если есть дочерние элементы, рекурсивно обрабатываем их
if (node.HasChildNodes)
{
foreach (XmlNode child in node.ChildNodes)
{
OutputNode(child);
}
}
}
// пример использования метода OutputNode()
var doc = new XmlDocument();
doc.Load("planets.xml");
OutputNode(doc.DocumentElement);