XPath 常用语法
2024-03-17 17:33:41

XPath 不会经常用,但是需要的时候又想不起来一些特性该怎么用,所以整理了一些比较常见的用法。
在 C# 中,主要用 XmlNode.SelectSingleNodeXmlNode.SelectNodes 方法 方法查询,前者查询单个节点,后者查询多个节点。

节点类型

先复习一下节点的类型。在XML中有5种主要的节点类型,它们是:

  1. 元素节点(Element Node):表示XML文档的元素,包括标签、属性和内容。
  2. 属性节点(Attribute Node):用于描述元素节点的属性。
  3. 文本节点(Text Node):包含元素节点内的文本内容。
  4. 注释节点(Comment Node):用于添加注释或说明性文本到XML文件中。
  5. CDATA节(CDATA Section):用于在XML文档中包含需要保留原始格式的文本数据。


此外,还有两种特殊类型的节点:
6. 处理指令节点(Processing Instruction Node):用于向XML解析器提供额外的指令或信息,通常位于XML文档的开头。
7. 命名空间节点(Namespace Node):用于定义和管理XML文档中的命名空间。

这些节点类型共同构成了XML文档的结构和内容。
在日常开发中,主要就是对前三种类型节点的查询与读写。

选择节点

1
2
3
4
5
6
7
SelectNodes(".");              // 当前节点
SelectNodes(".."); // 父节点
SelectNodes("Item"); // 从当前节点中查找子节点
SelectNodes("*"); // 任意节点
SelectNodes("/Root"); // 文档的根节点
SelectNodes("//Item"); // 查找文档中所有的 "Item" 节点,无论节点有多深
SelectNodes("//Item[Child]"); // 选择包含有子节点 "Child" 的节点

按属性过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
/* 选择属性节点 */
SelectNodes("//Item/@Name"); // 选择所有名为 "Name" 的属性节点
SelectNodes("//Item/@*"); // 选取所有属性节点

SelectNodes("//Item[@Id]"); // 包含属性名为 "Id" 的节点
SelectNodes("//Item[@Name='jack']"); // 要求属性等于指定的值

// 没有用引号的表示是数字,可以用逻辑表运算符
SelectNodes("//Item[@Id < 10]"); // 属性 Id 值小于 10 的节点

SelectNodes("//*[@Id=3][@Age=18]"); // 逻辑与,要求同时满足条件
SelectNodes("//*[@Id=3 and @Age=18]"); // 逻辑与,要求同时满足条件
SelectNodes("//*[@Id=3 or @Age=18]"); // 逻辑或,满足条件之一即可

按位置过滤

1
2
// 按索引返回,与数组一样,不过索引从1开始
SelectNodes("//Item[1]");

逻辑运算符

逻辑运算符通常用于属性过滤时。

  • =:等于
  • !=:不等于
  • >:大于
  • >=:大于等于
  • <:小于
  • <=:小于等于
  • and:逻辑与
  • or:逻辑或

函数

node

返回当前节点下的子节点,无论是什么类型。

1
SelectNodes("/Root/node()");

text

获取文本节点内容。
XML内容:

1
2
3
<Root>
<Node>jack</Node>
</Root>

取得文本节点值有两种方式:

1
2
var node = doc.SelectSingleNode("/Root/Node");
Debug.WriteLine(node.InnerText);

方式二就是使用text()函数:

1
2
var node = doc.SelectSingleNode("/Root/Node/text()");
Debug.WriteLine(node.Value); // jack

position

返回节点位置,下标从1开始

1
2
/* position 表示结果列表中的索引 */
SelectNodes("//Item[position() <= 5]"); // 选取前面5个节点

last

最后一个元素。

1
2
3
/* last 选择列表中最后一个节点 */
SelectNodes("//Item[last()]"); // 最后一个节点
SelectNodes("//Item[last() - 1]"); // 倒数第2个节点

contains

属性值是否包含指定字符串。

1
2
/* start-with、ends-with、contains */
SelectNodes("//Item[contains(@name, 'xxx')]");

starts-with

属性值是否以指定字符串开始。

1
SelectNodes("//Item[starts-with(@name, 'xxx')]");

ends-with

属性值是否以指定字符串结束。

1
SelectNodes("//Item[ends-with(@name, 'xxx')]");

测试发现 C# 不支持此函数

name

返回当前节点的名称。

1
SelectNodes("//*[contains(name(), 'Item')]");  // 所有元素节点名中包含 "Item" 的节点

substring

字串查询。

1
SelectNodes("//*[substring(name(), 1, 4) = 'Node']");  // 从位置1取4个字符

实践

索引筛选出多个结果

假设 XML 内容如下:

1
2
3
4
5
6
<Employees>
<Employee Id="1">
<Employee Id="2" />
</Employee>
<Employee Id="3" />
</Employees>

如果用SelectNodes("//Item[1]")会查询出几个结果呢?答案是两个。因为这句话的意思是查询任意位置,名为 Item 的第1个节点
由于<Employee Id="2" />处于父节点中第一个符合条件的,所以也会被筛选出来。

参考

XPath 教程
XPath 函数
Xpath语法格式整理