Работа с 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.
Кондратьев Денис