Операции Descendants и DescendantsAndSelf
25LINQ --- LINQ to XML --- Операции Descendants и DescendantsAndSelf
Descendants
Операция Descendants может быть вызвана на последовательности элементов или документов и возвращает последовательность элементов, содержащую все элементы-потомки каждого исходного элемента или документа.
Операция Descendants имеет два прототипа, описанные ниже:
- Первый прототип Descendants
-
public static IEnumerable<XElement> Descendants<T> ( this IEnumerable<T> source ) where T : XContainer
Эта версия вызывается на последовательности элементов или документов и возвращает последовательность документов, содержащую потомков каждого исходного элемента или документа.
Отличие этой операции от метода XContainer.Descendants в том, что этот метод вызывается на последовательности элементов или документов, а не на отдельном элементе или документе.
- Второй прототип Descendants
-
public static IEnumerable<XElement> Descendants<T> ( this IEnumerable<T> source, XName name ) where T : XContainer
Эта версия во всем подобна первой, за исключением того, что в выходной последовательности возвращаются только те элементы, которые соответствуют указанному имени.
Для демонстрации первого прототипа используется в основном тот же пример, что и для операции DescendantNodes из предыдущей статьи, вызывая вместо нее операцию Descendants. Вывод должен быть таким же, только без узлов, не являющихся элементами. То есть комментарии в выводе не появятся:
XDocument xDoc = new XDocument(
new XElement("Employees",
new XElement("Employee",
new XAttribute("type", "Programmer"),
new XComment("Это программист"),
new XElement("FirstName", "Alex"),
new XElement("LastName", "Erohin")),
new XElement("Employee",
new XAttribute("type", "Editor"),
new XElement("FirstName", "Elena"), new XElement("LastName", "Volkova"))));
// Получаем все элементы Employee
IEnumerable<XElement> elements = xDoc.Element("Employees").Elements("Employee");
foreach (XElement e in elements)
{
Console.WriteLine("Исходный элемент: {0} значение = {1}", e.Name, e.Value);
}
Console.WriteLine();
foreach (XNode node in elements.Descendants())
{
Console.WriteLine("Узел-потомок: " + node);
}
В данном примере выводятся только элементы-потомки двух элементов Employee. Результат работы этого примера выглядит следующим образом:
Сравнивая эти результаты с примером операции DescendantNodes из предыдущей статьи, можно заметить некоторые неожиданные отличия. Конечно, потомки помечены как элементы, а не узлы, и комментарий отсутствует, но при этом отсутствуют также узлы-потомки, такие как Alex и Elena. Разумеется, эти узлы также не являются элементами. Это объекты XText. API-интерфейс LINQ to XML обрабатывает текстовые узлы настолько гладко, что о них легко забыть.
Для демонстрации второго прототипа используется тот же код, что и в первом примере, за исключением дополнительного указания имени, которому должны соответствовать элементы-потомки, чтобы второй прототип операции Descendant вернул их:
...
foreach (XNode node in elements.Descendants("LastName"))
{
Console.WriteLine("Узел-потомок: " + node);
}
Результат этого примера выглядит следующим образом:
Как и можно было ожидать, возвращены только элементы LastName.
DescendantsAndSelf
Операция DescendantsAndSelf может быть вызвана на последовательности элементов и возвращает последовательность, содержащую каждый исходный элемент и его потомков.
Операция DescendantsAndSelf имеет два прототипа, которые описаны ниже:
- Первый прототип DescendantsAndSelf
-
public static IEnumerable<XElement> DescendantsAndSelf ( this IEnumerable<XElement> source )
Эта версия вызывается на последовательности элементов и возвращает последовательность элементов, содержащую каждый исходный элемент и его потомков.
- Второй прототип DescendantsAndSelf
-
public static IEnumerable<XElement> DescendantsAndSelf ( this IEnumerable<XElement> source, XName name)
Эта версия подобна первой, но принимает дополнительный параметр, указывающий имя, которому должны соответствовать возвращаемые элементы.
Для демонстрации работы первой версии DescendantsAndSelf используется тот же код, что и в примере применения первого прототипа операции Descendants, с заменой ее на операцию DescendantsAndSelf, как показано ниже:
...
foreach (XNode node in elements.DescendantsAndSelf())
{
Console.WriteLine("Узел-потомок: " + node);
}
После запуска этого примера должны отобразиться все исходные элементы и их элементы-потомки. Результаты показаны ниже:
Таким образом, вывод тот же, что и у операции Descendants, за исключением того, что он также включает сами исходные элементы — элементы Employee. Пусть не вводит в заблуждение наличие комментария в результатах. Это не потому, что он был возвращен операцией DescendantsAndSelf, а потому, что отображается элемент Employee, который был возвращен операцией.
Для демонстрации второго прототипа DescendantsAndSelf применяется тот же пример, что и для первого прототипа, но с добавлением имени, которому должны соответствовать возвращаемые элементы:
...
foreach (XNode node in elements.DescendantsAndSelf("FirstName"))
{
Console.WriteLine("Узел-потомок: " + node);
}
Результат этого примера выглядит так:
Результат включает только элементы-потомки, соответствующие указанному имени. Здесь не слишком очевидно, что была вызвана операция DescendantsAndSelf, а не Descendants, поскольку исходные элементы не возвращены по причине несоответствия их имени указанному.
Опять-таки, как и со всеми операциями, которые возвращают элементы из множества уровней дерева XML, принимающих аргумент — имя, которому должны соответствовать возвращаемые элементы, вряд ли понадобятся AndSelf-версии операций, поскольку маловероятно, что будет много уровней одноименных операций.