Работа с XML в .NET - Чтение документов с XmlDocument

ОГЛАВЛЕНИЕ

Чтение документов с XmlDocument

Класс XmlDocument реализует W3C Document Object Model (DOM) Level 1 Core и Core DOM Level 2. XmlDocument наиболее полезен в том случае, если нужно загрузить XML-документ в память для того, чтобы изменить атрибуты узлов, добавить или удалить новые элементы. DOM представляет XML-документ как дерево, хранящееся в памяти, с элементом-документом, являющимся корнем. Например, вот такой XML-документ, созданный нами ранее 

<Заказы>
    <Заказ Адрес="Уфа" Дата="21.04.2004">
        <Товар Название="Товар_А" Цена="100" />
        <Товар Название="Товар_Б" Цена="150" />
        <Товар Название="Товар_В" Цена="370" />
     </Заказ>
    <Заказ Адрес="Москва" Дата="24.04.2004">
        <Товар Название="Товар_Г" Цена="400" />
    </Заказ>
    <Заказ Адрес="Омск" Дата="28.04.2004">
        <Товар Название="Товар_Д" Цена="255" />
    </Заказ>
</Заказы>

будет представлен в виде такого дерева

 

Каждый узел в таком дереве является объектом класса XmlNode. Узел имеет только одного родителя и может иметь несколько атрибутов и дочерних узлов.

В нашем приложении XmlDocument применяется для загрузки данных о заказах из XML-файла. Рассмотрим эту функцию.

private void menuItemOpenDocument_Click(object sender, System.EventArgs e)
{
    OpenFileDialog dlg = new OpenFileDialog();
    dlg.Filter = "Файлы XML (*.xml)|*.xml";
    if (dlg.ShowDialog() != DialogResult.OK)
        return;

    XmlDocument doc = new XmlDocument();
    orders.Clear();

    try
    {
        doc.Load(dlg.FileName);
        // получаем все заказы
        XmlNodeList ordersList = doc.DocumentElement.ChildNodes;

        foreach (XmlNode nodeOrder in ordersList)
        {
             Order order = new Order(nodeOrder.Attributes["Адрес"].Value, DateTime.Parse(nodeOrder.Attributes["Дата"].Value));
             // получаем все товары из заказа
             XmlNodeList goodsList = nodeOrder.ChildNodes;

             foreach (XmlNode nodeGood in goodsList)
                 order.AddGood(nodeGood.Attributes["Название"].Value, float.Parse(nodeGood.Attributes["Цена"].Value));
             orders.Add(order);
        }

        ShowOrders();
    }
    catch (Exception ex)
    {
        MessageBox.Show("Ошибка: " + ex.Message);
    }

Функция Load() загружает XML-документ, выбранный пользователем. В случае возникновения ошибки при чтении файла или разборе XML-документа выбрасывается исключение XmlException и документ остается пустым. Есть и перегруженная версия функции, принимающая в качестве параметра объект Stream. Для получения корневого элемента документа существует свойство DocumentElement, возвращающий объект XmlElement если документ не пуст или null в противном случае. Для получения всем потомков узла существует свойство ChildNodes. В нашем примере мы получили корневой элемент документа, соответствующий тегу "Заказы", и перебрали дочерние элементы - теги "Заказ". Для получения значений атрибутов тега было использовано свойство Attributes. В нашем случае мы получали значение атрибутаа по имени, но можно было получить его по порядковому номеру или имени и пространству имен. Тег для товара в заказе является дочерним по отношению к тегу заказа, поэтому для получения всех товаров из заказа мы так же воспользовались свойством ChildNodes.

Кроме перебора всех узлов XML-документа существуют и другие способы нахождения нужной информации. Можно найти нужны узлы XML-документа, воспользовавшись выражением XPath (методы SelectSingleNode и SelectNodes) - этот способ мы рассмотрим далее. Или можно получить список XmlNodeList всех тегов определенного имени. Для получения дат всех заказов можно получить все теги "Заказ", и получить значение их атрибута "Дата".

XmlNodeList orders = doc.GetElementsByTagName("Заказ");
foreach (XmlNode node in orders)
    Console.WriteLine(elemList[i].Attributes["Дата"]); }

Наш формат хранения данных очень прост и однозначен. В реальных случаях для разбора документов приходится использовать имя тега, его значение и тип, о которых мы говорили выше. 

Класс XmlDocument обычно используется для изменения существующих XML-документ. Однако, можно загрузить XML-документ из текстовой строки методом LoadXML класса XmlDocumentа, а затем добавить в него новые узлы и сохранить в файл. При этом мы используем загруженный документ как шаблон, хотя можно создавать документ и с нуля. Приведем пример использования функции LoadXML .

XmlDocument doc = new XmlDocument();
doc.LoadXml("<Заказы></Заказы>");
XmlNode order = doc.CreateElement("Заказ");

XmlAttribute attrDate = doc.CreateAttribute("Дата");
attrDate.Value = DateTime.Today.ToShortDayString();
order.Attributes.Append(attrDate);

XmlAttribute attrAdr = doc.CreateAttribute("Адрес");
attrAdr.Value = "Уфа";
order.Attributes.Append(attrAdr);

doc.DocumentElement.AppendChild(order);

doc.Save("заказы.xml");

Вначале мы создаем пустой список заказов, вызывая LoadXml. Затем создаем узел для заказа и добавляем к нему атрибуты для даты и адреса методом CreateAttribute. Затем добавляем узел для заказа к корневому элементу документа функцией AppendChild и сохраняем документ в файл.