# XPath 如何工作

> 原文： [https://docs.oracle.com/javase/tutorial/jaxp/xslt/xpath.html](https://docs.oracle.com/javase/tutorial/jaxp/xslt/xpath.html)

XPath 规范是各种规范的基础，包括 XSLT 和链接/寻址规范，如 `XPointer` 。因此，理解 XPath 是许多高级 XML 使用的基础。本节介绍 XSLT 上下文中的 XPath。

## XPath 表达式

通常，XPath 表达式指定选择一组 XML 节点的模式。然后，XSLT 模板在应用转换时使用这些模式。 （另一方面， `XPointer` 增加了定义**点**或**范围**的机制，以便 XPath 表达式可用于寻址）。

XPath 表达式中的节点不仅仅指向元素。它们还涉及文本和属性等。事实上，XPath 规范定义了一个抽象文档模型，它定义了七种节点：

*   根

*   元件

*   文本

*   属性

*   评论

*   加工指导

*   命名空间

XML 数据的根元素由**元素**节点建模。 XPath 根节点包含文档的根元素以及与文档相关的其他信息。

## XSLT / XPath 数据模型

与文档对象模型（DOM）一样，XSLT / XPath 数据模型由包含各种节点的树组成。在任何给定元素节点下，存在文本节点，属性节点，元素节点，注释节点和处理指令节点。

在这个抽象模型中，语法区别消失了，你留下了数据的标准化视图。例如，在文本节点中，文本是在 CDATA 部分中定义还是包含实体引用没有区别。文本节点将包含规范化数据，因为它在所有解析完成后存在。因此，文本将包含`&lt;` 字符，无论是否是`&lt; `等实体引用。` 或 CDATA 部分用于包括它。 （类似地，文本将包含`和`字符，无论是使用`&amp;` 还是在 CDATA 部分中传递的。`

在本节中，我们将主要处理元素节点和文本节点。有关其他寻址机制，请参阅 XPath 规范。

## 模板和上下文

XSLT 模板是一组格式说明，适用于 XPath 表达式选择的节点。在样式表中，XSLT 模板看起来像这样：

```
<xsl:template match="//LIST">
    ...
</xsl:template>

```

表达式 `// LIST` 从输入流中选择 `LIST` 节点的集合。模板中的其他说明告诉系统如何处理它们。

由这样的表达式选择的节点集定义了评估模板中其他表达式的上下文。该上下文可以被视为整个集合 - 例如，在确定它包含的节点数时。

上下文也可以被视为集合的单个成员，因为每个成员都是逐个处理的。例如，在 `LIST` 处理模板内，表达式 `@type` 指的是当前 `LIST` 节点的类型属性。 （类似地，表达式 `@ *` 指的是当前 LIST 元素的所有属性）。

## 基本 XPath 寻址

XML 文档是树状结构（分层）节点集合。与分层目录结构一样，指定 _ 路径 _ 指向层次结构中的特定节点（因此指定的名称：XPath）很有用。实际上，目录路径的大部分符号都是完整的：

*   正斜杠（/）用作路径分隔符。

*   从文档根开始的绝对路径以/开头。

*   来自给定位置的相对路径从其他任何东西开始。

*   双周期（..）表示当前节点的父节点。

*   单个句点（。）表示当前节点。

例如，在可扩展 HTML（XHTML）文档（看起来像 HTML 但根据 XML 规则很好地形成的 XML 文档）中，路径 `/ h1 / h2 /` 将指示 `h2 [ `h1` 下的 HTG3]元素。 （回想一下，在 XML 中，元素名称区分大小写，因此这种规范在 XHTML 中比在纯 HTML 中更好，因为 HTML 不区分大小写）。`

在诸如 XPath 的模式匹配规范中，规范 `/ h1 / h2` 选择位于 `h1` 元素下的所有 `h2` 元素。要选择特定的 `h2` 元素，可以使用方括号 `[]` 进行索引（就像用于数组的那些）。因此，路径 `/ h1 [4] / h2 [5]` 将在第四 `h1` 元件下选择第五 `h2` 元件。

* * *

**注 -** 在 XHTML 中，所有元素名称都是小写的。这是 XML 文档的一个相当常见的约定。但是，在像这样的教程中，大写名称更容易阅读。因此，对于 XSLT 课程的其余部分，所有 XML 元素名称都将为大写。 （另一方面，属性名称将保持小写）。

* * *

XPath 表达式中指定的名称是指元素。例如， `/ h1 / h2` 中的 `h1` 是指 `h1` 元素。要引用属性，请在属性名称前加上 `@` 符号。例如， `@type` 指的是元素的 type 属性。例如，假设您有一个带有 LIST 元素的 XML 文档，表达式 `LIST / @ type` 选择 `LIST` 元素的 type 属性。

* * *

**注 -** 因为表达式不是以 `/` 开头，所以引用指定了相对于当前上下文的列表节点 - 文档中的任何位置。

* * *

## 基本的 XPath 表达式

全系列的 XPath 表达式利用了 XPath 定义的通配符，运算符和函数。您将很快了解更多相关信息。在这里，我们将介绍一些最常见的 XPath 表达式，只是为了介绍它们。

表达式 `@type =“unordered”`指定名为`类型`的属性，其值为`无序`。诸如 `LIST / @ type` 的表达式指定 `LIST` 元素的类型属性。

你可以结合这两种符号来获得有趣的东西。在 XPath 中，通常与索引相关联的方括号表示法（ `[]` ）被扩展为指定选择标准。因此表达式 `LIST [@type =“unordered”]` 选择其类型值无序的所有 `LIST` 元素。

元素存在类似的表达。每个元素都有一个关联的字符串值，该字符串值通过连接位于该元素下的所有文本段而形成。 （有关该过程如何工作的更详细说明，请参见[元素的字符串值](#gchmn)）。

假设您使用由 `PROJECT` 元素和 `ACTIVITY` 元素组成的 XML 结构来模拟组织中正在发生的事情，这些元素具有项目名称的文本字符串，多个 `PERSON` 元素列出所涉及的人员，以及可选的 `STATUS` 元素来记录项目状态。以下是使用扩展方括号表示法的其他示例：

*   `/PROJECT[.="MyProject“]` ：选择名为`”MyProject“`的 `PROJECT` 。

*   `/ PROJECT [STATUS]` ：选择具有 `STATUS` 子元素的所有项目。

*   `/ PROJECT [STATUS =“Critical”]` ：选择具有字符串值 `Critical` 的 `STATUS` 子元素的所有项目。

## 结合索引地址

XPath 规范定义了相当多的寻址机制，它们可以以多种不同的方式组合。因此，XPath 为相对简单的规范提供了大量的表达能力。本节说明了其他有趣的组合：

*   `LIST [@type =“ordered”] [3]` ：选择`类型`类型的所有 `LIST` 元素，并返回第三个。

*   `LIST [3] [@type =“ordered”]` ：选择第三个 `LIST` 元素，但仅限于`类型`。

* * *

**注 -** [XPath 规范](http://www.w3.org/TR/xpath/)的第 2.5 节列出了更多地址运算符组合。这可以说是定义 XSLT 转换的规范中最有用的部分。

* * *

## 外卡

根据定义，非限定 XPath 表达式选择一组与指定模式匹配的 XML 节点。例如， `/ HEAD` 匹配所有顶级 `HEAD` 条目，而 `/ HEAD [1]` 仅匹配第一个。 [表 4-1](#gchlc) 列出了可以在 XPath 表达式中使用的通配符，以扩大模式匹配的范围。

表 4-1 XPath 通配符

<colgroup><col width="50%"> <col width="50%"></colgroup>
| 

外卡

 | 

含义

 |
| :-- | :-- |
| `*` | 匹配任何元素节点（不是属性或文本）。 |
| `node（）` | 匹配任何类型的节点：元素节点，文本节点，属性节点，处理指令节点，命名空间节点或注释节点。 |
| `@ *` | 匹配任何属性节点。 |

在项目数据库示例中， `/*/PERSON[.="Fred“]` 匹配任何名为 Fred 的 `PROJECT` 或 `ACTIVITY` 元素。

## 扩展路径寻址

到目前为止，您看到的所有模式都在层次结构中指定了确切的级别数。例如， `/ HEAD` 指定层次结构中第一级的任何 `HEAD` 元素，而 `/ * / *` 指定层次结构中第二级的任何元素。要在层次结构中指定不确定级别，请使用双正斜杠（ `//` ）。例如，XPath 表达式 `// PARA` 选择文档中的所有段落元素，无论它们位于何处。

`//` 模式也可以在路径中使用。所以表达式 `/ HEAD / LIST // PARA` 表示从/ `HEAD / LIST` 开始的子树中的所有段落元素。

## XPath 数据类型和运算符

XPath 表达式产生一组节点，一个字符串，一个布尔值（一个真/假值）或一个数字。 [表 4-2](#gchmt) 列出了可在 Xpath 表达式中使用的运算符：

表 4-2 XPath 运算符

<colgroup><col width="50%"> <col width="50%"></colgroup>
| 

操作者

 | 

含义

 |
| :-- | :-- |
| `&#124;` | 另类。例如， `PARA &#124; LIST` 选择所有 `PARA` 和 `LIST` 元素。 |
| `或`，`和` | 返回两个布尔值的和/或两个布尔值。 |
| `=` ，`！=` | 对于布尔，字符串和数字，相等或不相等。 |
| `&lt;` ，`&gt;` ，`&lt; =` ，`&gt; =` | 小于，大于，小于或等于，大于或等于数字。 |
| `+` ， `-` ， `*` ， `div` ， `mod` | 加，减，乘，浮点除法和模数（余数）运算（例如，6 mod 4 = 2）。 |

表达式可以在括号中分组，因此您不必担心运算符优先级。

* * *

**注 -** 运算符优先级是一个回答问题的术语，“如果你指定一个+ b * c，那是指（a + b）* c 还是+（b * c）？” （运算符优先级与表中显示的大致相同）。

* * *

## 元素的字符串值

元素的字符串值是所有后代文本节点的串联，无论多深。考虑这个混合内容的 XML 数据：

```
<PARA>This paragraph contains a <b>bold</b> word</PARA>

```

`&lt; PARA&gt;的字符串值。` 元素是**本段包含粗体字**。特别地，注意`&lt; B&gt;。` 是`&lt; PARA&gt;的孩子。` 并且文本`粗体`是`&lt; B&gt;的孩子了。` 。

关键是节点的所有子节点中的所有文本都连接在串联中以形成字符串值。

此外，值得理解的是，XPath 定义的抽象数据模型中的文本已完全规范化。那么 XML 结构是否包含实体引用`&amp; lt;` 或`&lt;在 `CDATA` 部分`中，元素的字符串值将包含`&lt;` 字符。因此，在使用 XSLT 样式表生成 HTML 或 XML 时，必须转换`&lt;的出现次数。` 至`&amp; lt;` 或将它们包含在 `CDATA` 部分中。同样，`&amp;` 必须转换为`&amp; amp;` 。

## XPath 函数

本节最后概述了 XPath 函数。您可以使用 XPath 函数来选择节点集合，方法与使用元素规范（例如您已经看过的元素规范）的方式相同。其他函数返回字符串，数字或布尔值。例如，表达式 `/ PROJECT / text（）`获取 `PROJECT` 节点的字符串值。

许多功能取决于当前的上下文。在前面的示例中， `text（）`函数的每次调用的上下文是当前选择的 `PROJECT` 节点。

有许多 XPath 函数 - 这里有太多不能详细描述。本节提供了一个简要列表，其中显示了可用的 XPath 功能，以及它们的功能摘要。有关函数的更多信息，请参见 [XPath 规范](http://www.w3.org/TR/xpath/)的第 4 节。

### 节点集功能

许多 XPath 表达式选择一组节点。实质上，它们返回一个节点集。一个功能也是如此。 `id（...）`函数返回具有指定 ID 的节点。 （仅当文档具有 DTD 时，元素才具有 ID，该 DTD 指定哪个属性具有 ID 类型）。

### 位置函数

这些函数返回基于位置的数值。

*   `last（）`：返回最后一个元素的索引。例如， `/ HEAD [last（）]` 选择最后一个 `HEAD` 元素。

*   `position（）`：返回索引位置。例如， `/ HEAD [position（）&lt; = 5]` 选择前五个 `HEAD` 元素。

*   `count（...）`：返回元素的数量。例如， `/ HEAD [count（HEAD）= 0]` 选择没有子标题的所有 `HEAD` 元素。

### 字符串函数

这些函数操作或返回字符串。

*   `concat（string，string，...）`：连接字符串值。

*   `starts-with（string1，string2）`：如果 `string1` 以 `string2` 开头，则返回 true。

*   `包含（string1，string2）`：如果 `string1` 包含 `string2` ，则返回 true。

*   `substring-before（string1，string2）`：在 `string2` 出现之前，返回 `string1` 的开头。

*   `substring-after（string1，string2）`：在 `string2` 出现后返回 `string1` 的剩余部分。

*   `substring（string，idx）`：返回从索引位置到结尾的子串，其中第一个 `char` 的索引= 1。

*   `substring（string，idx，len）`：从索引位置返回指定长度的子字符串。

*   `string-length（）`：返回上下文节点的字符串值的大小; context 节点是当前选择的节点 - 由 XPath 表达式选择的节点，其中应用了诸如 `string-length（）`的函数。

*   `string-length（string）`：返回指定字符串的大小。

*   `normalize-space（）`：返回当前节点的规范化字符串值（没有前导或尾随空格，以及转换为单个空格的空格字符序列）。

*   `normalize-space（string）`：返回指定字符串的规范化字符串值。

*   `translate（string1，string2，string3）`：转换 `string1` ，将 `string2` 中出现的字符替换为 `string3` 中的相应字符。

* * *

**注 -** XPath 定义了三种获取元素文本的方法： `text（）`， `string（object）`，以及元素隐含的字符串值在这样的表达式中的名称： `/ PROJECT [PERSON =“Fred”]` 。

* * *

### 布尔函数

这些函数操作或返回布尔值。

*   `not（...）`：取消指定的布尔值。

*   `true（）`：返回 true。

*   `false（）`：返回 false。

*   `lang（string）`：如果上下文节点的语言（由 `xml：Lang` 属性指定）与指定语言的（或子语言）相同，则返回 true;例如，Lang（“en”）对于`&lt; PARA_xml：Lang =“en”&gt; ...&lt; / PARA&gt;是真的。` 。

### 数字函数

这些函数操作或返回数值。

*   `sum（...）`：返回指定节点集中每个节点的数值之和。

*   `floor（N）`：返回不大于 _N_ 的最大整数。

*   `ceiling（N）`：返回不小于 _N_ 的最小整数。

*   `round（N）`：返回最接近 _N_ 的整数。

### 转换功能

这些函数将一种数据类型转换为另一种。

*   `string（...）`：返回数字，布尔值或节点集的字符串值。

*   `boolean（...）`：返回数字，字符串或节点集的布尔值（非零数字，非空节点集和非空字符串都是真正）。

*   `number（...）`：返回布尔值，字符串或节点集的数值（true 为 1，false 为 0，包含数字的字符串成为该数字，字符串值为节点集转换为数字）。

### 命名空间函数

这些函数可用于确定节点的命名空间特征。

*   `local-name（）`：返回当前节点的名称，减去名称空间前缀。

*   `local-name（...）`：返回指定节点集中第一个节点的名称，减去名称空间前缀。

*   `namespace-uri（）`：从当前节点返回名称空间 URI。

*   `namespace-uri（...）`：从指定节点集中的第一个节点返回名称空间 URI。

*   `name（）`：返回当前节点的扩展名（URI 加本地名）。

*   `name（...）`：返回指定节点集中第一个节点的扩展名（URI 加本地名）。

## 小结

XPath 运算符，函数，通配符和节点寻址机制可以以多种方式组合。到目前为止，您的介绍应该为您指定任何特定目的所需的模式提供良好的开端。