C#如何使用XPath从XML中筛选数据?完整教程

来源:Nginx教程作者:公主头衔:草根站长
导读:本期聚焦于公主创作的《C#如何使用XPath从XML中筛选数据?完整教程》,敬请观看详情。如果需要在XML文档中按条件提取节点,XPath是绕不开的查询语言,C#里对它也有成熟的封装。通过XmlDocument的SelectSingleNode和SelectNodes可以直接执行XPath表达式,适合一次性加载中小型文档。XPathNavigator则提供只读游标式遍历,配合XPathNodeIterator能处理更大的文件并减少内存占用。本文从基本的节点定位讲起,覆盖属性筛选、层级关系、多条件组合以及contains和starts-with等函数。对于带有命名空间的XML,还会说明为什么必须使用XmlNamespaceManager注册前缀,否则查询结果会返回空。最后对比两种API的异常行为和线程安全性,给出数据筛选时的选择建议。

对XML文档进行条件查询时,XPath表达式可以精准描述节点路径和约束条件。C#标准库提供两种主要方式执行XPath:基于XmlDocument的SelectSingleNode和SelectNodes方法,以及基于XPathDocument的XPathNavigator只读游标。前者会把整个文档加载到内存并构建DOM树,适合结构修改和中小型文件;后者按只读方式遍历,内存峰值更低。理解二者的执行模型,能帮助你在不同数据规模下选择合适的API。

C#如何使用XPath从XML中筛选数据?完整教程

C#中执行XPath的两种入口

XmlDocument属于System.Xml命名空间,它提供SelectSingleNode和SelectNodes两个核心方法。SelectSingleNode返回匹配表达式的第一个节点,没有匹配时返回null;SelectNodes返回XmlNodeList集合。两个方法都可以不带命名空间管理器直接使用,只要XML中没有默认命名空间或带前缀的节点。

另一种入口是XPathDocument与XPathNavigator。XPathDocument专为XPath查询设计,内部采用只读模型,创建速度比XmlDocument更快,占用内存更低。通过CreateNavigator方法拿到XPathNavigator后,可以使用Compile将表达式编译为XPathExpression,再执行Select方法。如果同一个表达式需要反复执行,编译后复用会减少解析开销。

下面的示例演示XmlDocument加载本地XML并读取book节点。代码中使用了绝对路径/catalog/book/title,这要求根元素必须是catalog。

<catalog>
  <book id="bk101" category="programming">
    <title>C# Guide</title>
    <author>Zhang</author>
    <price>59.00</price>
  </book>
  <book id="bk102" category="database">
    <title>SQL Cookbook</title>
    <author>Li</author>
    <price>45.00</price>
  </book>
</catalog>
using System;
using System.Xml;

class Program
{
    static void Main()
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(@"C:\temp\books.xml");

        XmlNode titleNode = doc.SelectSingleNode("/catalog/book/title");
        Console.WriteLine(titleNode?.InnerText);

        XmlNodeList bookList = doc.SelectNodes("//book");
        foreach (XmlNode book in bookList)
        {
            Console.WriteLine(book.Attributes["id"].Value);
        }
    }
}

运行后会先输出第一个title文本,再遍历所有book节点并打印id属性。这里//book中的双斜杠表示从文档任意位置搜索,不依赖层级。

常用XPath筛选表达式与函数

基础路径能够定位节点,但真正的数据筛选依赖谓词和函数。谓词写在方括号中,用来对节点集合做条件过滤。按属性筛选的写法是//book[@category='database'],它返回category属性等于database的book节点。如果需要数值比较,可以使用XPath的比较运算符,例如//book[price > 40]。要注意在C#字符串中传入时,大于号在代码里需要转义为&gt;,否则会破坏XPath字符串的XML语义。

多条件组合通过and和or连接,例如//book[@category='database' and price > 40]。字符串匹配可以使用contains函数,例如//book[contains(title,'C#')]表示标题包含C#的book。starts-with函数用于前缀匹配,last和position则用于序号筛选,例如//book[position()=1]取第一个book。

下面代码演示属性筛选、数值比较和字符串函数。XmlNodeList返回后可以直接foreach遍历,节点属性仍通过Attributes访问。

XmlDocument doc = new XmlDocument();
doc.Load(@"C:\temp\books.xml");

XmlNodeList databaseBooks = doc.SelectNodes("//book[@category='database']");
Console.WriteLine("database分类数量: " + databaseBooks.Count);

XmlNodeList priceBooks = doc.SelectNodes("//book[price > 40]");
foreach (XmlNode book in priceBooks)
{
    Console.WriteLine(book.SelectSingleNode("title").InnerText);
}

XmlNodeList containsBooks = doc.SelectNodes("//book[contains(title,'C#')]");
foreach (XmlNode book in containsBooks)
{
    Console.WriteLine("包含C#: " + book.Attributes["id"].Value);
}

还有一点需要区分:SelectSingleNode在匹配不到时返回null,如果直接调用InnerText会抛出NullReferenceException。因此生产代码中应当先判空,或者使用空值传播运算符。

命名空间查询为什么需要XmlNamespaceManager

如果XML文档带有默认命名空间,例如根元素声明xmlns="http://ipipp.com/books",那么所有没有前缀的元素都属于该命名空间。此时直接写//book往往返回空集合,因为XPath会认为book在空命名空间下,与实际节点所属命名空间不一致。

解决办法是创建XmlNamespaceManager,把前缀映射到命名空间URI,然后在XPath表达式中使用该前缀。注意这里的映射前缀不必与XML原文中的前缀相同,只要URI一致即可。比如XML里没有前缀,查询时仍然可以注册前缀bk指向同一个URI,然后使用//bk:book。

<catalog xmlns="http://ipipp.com/books">
  <book id="bk101">
    <title>C# Guide</title>
  </book>
</catalog>
XmlDocument doc = new XmlDocument();
doc.Load(@"C:\temp\books_ns.xml");

XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("bk", "http://ipipp.com/books");

XmlNode node = doc.SelectSingleNode("//bk:book/bk:title", nsmgr);
Console.WriteLine(node?.InnerText);

如果XML中带有多个命名空间,可以多次调用AddNamespace。XmlNamespaceManager依赖NameTable保证字符串比较性能,因此必须使用doc.NameTable或XPathDocument对应的NameTable初始化。忽略这一点也可能导致选择失败。

XPathNavigator与XmlDocument的区别及选择建议

XmlDocument是可变DOM,适合需要在筛选后修改节点内容、删除节点或新增属性的场景。缺点是加载完整DOM会占用较多内存,如果XML文件很大,构建和查询都比较慢。XPathDocument与XPathNavigator则采用只读游标模式,遍历过程不构建可变对象,内存占用明显更低。

如果需要多次执行不同XPath,可以选择XPathNavigator的Compile方法。编译后的XPathExpression对象可以重复使用,避免每次Select都重新解析表达式。XPathNodeIterator提供MoveNext遍历结果,用Current属性获取当前节点,再通过SelectSingleNode继续向下查询。

XPathDocument xpathDoc = new XPathDocument(@"C:\temp\books.xml");
XPathNavigator nav = xpathDoc.CreateNavigator();

XPathExpression expr = nav.Compile("//book[@category='programming']");
XPathNodeIterator iterator = nav.Select(expr);

while (iterator.MoveNext())
{
    XPathNavigator current = iterator.Current;
    Console.WriteLine(current.SelectSingleNode("title").Value);
}

综合来看,小规模XML并且需要修改数据时使用XmlDocument最直接;只读查询和大文件优先XPathDocument。XPath本身语法与C#版本无关,掌握谓词、函数和命名空间映射后,可以将同一套表达式迁移到其他支持XPath的语言中。

C#XPathXML筛选修改时间:2026-10-05 09:10:35

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1005/65931.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。