在C#中处理XML文档时,XDocument是常用的XML操作类,其提供的Descendants方法可以快速获取XML文档中的后代节点,但很多时候我们需要递归查找所有子节点,这时候就需要结合递归逻辑来扩展Descendants的使用方式。

XDocument Descendants基础用法
Descendants是XDocument和XElement类都具备的方法,它的作用是返回当前元素或文档中所有后代节点的集合,也可以传入指定的节点名称,只返回对应名称的后代节点。基础的使用示例如下:
using System;
using System.Xml.Linq;
class Program
{
static void Main()
{
// 加载XML字符串
string xmlContent = @"<root>
<parent>
<child1>子节点1</child1>
<child2>
<subChild>子子节点</subChild>
</child2>
</parent>
</root>";
XDocument doc = XDocument.Parse(xmlContent);
// 获取所有名称为child1的后代节点
var child1Nodes = doc.Descendants("child1");
foreach (var node in child1Nodes)
{
Console.WriteLine(node.Value);
}
}
}
上述代码会输出子节点1,这是因为Descendants("child1")只返回名称为child1的后代节点,不会返回其他名称的节点。
递归查找所有子节点的实现思路
如果需要查找所有子节点,不管节点名称是什么,同时可能需要对节点做自定义处理,就可以结合递归逻辑来实现。核心思路是:先获取当前元素的所有直接子元素,然后对每个子元素进行处理,再递归处理该子元素的子元素,直到没有更多子元素为止。
这里可以结合Descendants方法先获取根元素下的所有后代元素,再配合递归做更灵活的处理,比如过滤特定属性、特定层级的节点等。
基础递归查找所有子节点示例
下面的代码实现了递归遍历XDocument中的所有子节点,并输出每个节点的名称和值:
using System;
using System.Xml.Linq;
class Program
{
static void Main()
{
string xmlContent = @"<root>
<parent id=""1"">
<child1>子节点1</child1>
<child2>
<subChild>子子节点</subChild>
</child2>
</parent>
<parent id=""2"">
<child3>子节点3</child3>
</parent>
</root>";
XDocument doc = XDocument.Parse(xmlContent);
// 从根元素开始递归查找
RecursionAllNodes(doc.Root);
}
/// <summary>
/// 递归遍历所有子节点
/// </summary>
/// <param name="element">当前处理的XElement元素</param>
static void RecursionAllNodes(XElement element)
{
// 输出当前节点的名称
Console.WriteLine($"节点名称:{element.Name}");
// 如果当前节点有值,输出值
if (!string.IsNullOrEmpty(element.Value))
{
Console.WriteLine($"节点值:{element.Value}");
}
// 遍历当前节点的所有直接子元素
foreach (var child in element.Elements())
{
// 递归处理子元素
RecursionAllNodes(child);
}
}
}
运行上述代码,会依次输出root、parent、child1、child2、subChild、parent、child3这些节点的相关信息,实现了对所有子节点的递归查找。
结合Descendants的递归查找优化
如果只需要处理特定条件的节点,可以先使用Descendants筛选出初步的节点集合,再对集合中的节点做递归处理,提升查询效率。比如我们需要查找所有包含id属性的节点及其所有子节点:
using System;
using System.Xml.Linq;
class Program
{
static void Main()
{
string xmlContent = @"<root>
<parent id=""1"">
<child1>子节点1</child1>
<child2>
<subChild>子子节点</subChild>
</child2>
</parent>
<parent id=""2"">
<child3>子节点3</child3>
</parent>
<parent>
<child4>子节点4</child4>
</parent>
</root>";
XDocument doc = XDocument.Parse(xmlContent);
// 先使用Descendants获取所有parent节点
var parentNodes = doc.Descendants("parent").Where(p => p.Attribute("id") != null);
foreach (var parent in parentNodes)
{
Console.WriteLine($"找到带id的parent节点,id值:{parent.Attribute("id").Value}");
// 递归处理该parent节点的所有子节点
RecursionChildNodes(parent);
}
}
/// <summary>
/// 递归处理指定节点的所有子节点
/// </summary>
static void RecursionChildNodes(XElement element)
{
foreach (var child in element.Elements())
{
Console.WriteLine($"子节点名称:{child.Name},值:{child.Value}");
// 如果子节点还有子元素,继续递归
if (child.Elements().Any())
{
RecursionChildNodes(child);
}
}
}
}
上述代码先通过Descendants筛选出所有带id属性的parent节点,再递归遍历这些parent节点的所有子节点,避免了无意义的全文档遍历,提升了处理效率。
注意事项
- 递归查找时要注意XML的嵌套深度,如果XML嵌套层级过深,可能会导致栈溢出,这时候可以考虑改用栈或队列实现迭代遍历。
- Descendants方法返回的是所有后代节点,包括嵌套多层的节点,如果只需要直接子节点,应该使用
Elements()方法而不是Descendants。 - 处理XML节点时,要注意判断节点是否为空,避免出现空引用异常,比如获取节点属性时要先判断Attribute("属性名")是否为null。
递归查找所有子节点的核心是结合XDocument的节点遍历方法和递归逻辑,根据实际需求选择先筛选再递归或者全量递归的方式,就能灵活实现各种XML节点查找需求。
C#XDocumentDescendants递归查找子节点修改时间:2026-07-12 21:21:32