Работа с XML в .NET - Поиск по документу с XPath

ОГЛАВЛЕНИЕ

Поиск по документу с XPath

XML Path Language (XPath) - язык, применяемый для получения наборов узлов XML-документа и адресации частей XML-документа. Он обеспечивает компактный, эффективный, логичный синтаксис для ссылок на узлы документа, тесно связан с XSLT и предоставляет стандартные средства для работы со строками, числами и булевскими значениями.

Пути в XPath формируются из названий узлов, разделенных слешами. Путь к товару будет описан следующим выражением.

Заказы/Заказ/Товар

Для идентификации элемента во всех местах документа нужно использовать два слеша в начале выражения:

//Товар 

Для указания неизвестных элементов в пути можно воспользоваться символом *. Например, можно задать вот такой путь для поиска руководителей отделов

Отделы/*/Руководитель

Для фильтрации элементов документа нужно использовать предикаты - выражения, заключенные в квадратные скобки. В предикатах могут участвовать атрибуты тегов и значения вложенных тегов. При этом, перед атрибутами тегов, участвующих в фильтрации, ставиться амперсанд @, а перед вложенными тегами - нет. Предикаты можно объединять ключевыми словами or и and. Для нахождения заказов из Москвы или Уфы нужно использовать такое выражение:

Заказы/Заказ[@Адрес = "Уфа" or @Адрес = "Москва"]

Для работы с XPath в .NET используются классы XPathNavigator и XPathNodeIterator. XPathNavigator выполняет XPath запросы, а перемещение по узлам, полученным в результате запроса осуществляется с помощью XPathNodeIterator. С помощью XPathNavigator можно перемещаться по документу в произвольном направлении. Для перехода к родительскому узлу есть метод MoveToParent, а для переход к первому дочернему узлу - MoveToFirstChild. Свойство HasChildren возвращает true если у текущего узла есть дочерние. Для перебора атрибутов текущего узла есть методы MoveToFirstAttribute, MoveToNextAttribute. В нашей программе мы используем XPath для поиска товаров, стоимостью более 300 рублей, и нахождения их суммарной стоимости. Рассмотрим эту функцию. 

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);

    // находим стоимость всех товаров
    XPathNavigator nav = doc.CreateNavigator();
    XPathNodeIterator it = (XPathNodeIterator)nav.Evaluate("Заказы/Заказ/Товар[@Цена > 300]");

    StringBuilder sb = new StringBuilder();
    sb.Append("Дорогие товары:");
    float total = 0;

    while (it.MoveNext())
    {
         sb.AppendFormat("\n{0}", it.Current.GetAttribute("Цена", ""));
         total += float.Parse(it.Current.GetAttribute("Цена", ""));
    }

    sb.AppendFormat("\n--------------------\nИтого: {0} рублей", total);

    // получаем все заказы
    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();

    // выводим адреса заказов
    MessageBox.Show(sb.ToString());
}
catch (Exception ex)
{
    MessageBox.Show("Ошибка: " + ex.Message);
}

На первом этапе мы создаем XmlDocument и загружаем XML-файл, указанный пользователем. Объект XPathNavigator создается вызовом метода CreateNavigator. Мы выполнили XPath-запрос с помощью метода Evalate, выполняющим произвольный запрос. Результатом может быть число, строка, булевское значение или набор узлов, как в нашем случае. Этот метод мы выбрали только для примера, т.к. для получения именно набора узлов лучше пользоваться методом Select. Он также принимает строку с XPath выражением, но сразу возвращает объект XPathNodeIterator. В нашем примере мы искали все товары, цена которых более 300 рублей. Для перебора всех узлов, найденных методом Evalate, вызываем метод MoveNext() и для каждого узла получаем значение атрибута Цена. Все найденные цены суммируются, а из значения сохраняются в текстовом виде в StringBuilder.

 

Кондратьев Денис