Files
QieKan-3.0/docs/dev/xpath.md
T

166 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# XPath 路径表达式
[[toc]]
XPath 是一种用于在 XML/HTML 文档中定位节点的语言。Legado 源支持使用 XPath 规则提取网页内容,以 `//`
开头的规则会自动识别为 XPath 表达式。
_注:本文所有代码均通过 Chrome(版本 123.0.6312.86) 验证_
## 1. 轴 (Axes)
XPath 规范定义了 13 种轴,用于定位元素树上相对于当前元素的节点。
| 轴 | 说明 | 缩写 |
|:---------------------|:---------------------------|:-----|
| `attribute` | 元素的属性 | `@` |
| `self` | 元素本身 | `.` |
| `parent` | 当前元素的父元素 | `..` |
| `child` | 当前元素的子元素 | — |
| `ancestor` | 当前元素的所有直属祖先 | — |
| `ancestor-or-self` | 当前元素及其所有直属祖先 | — |
| `descendant` | 当前元素的所有递归子元素 | — |
| `descendant-or-self` | 当前元素及其所有递归子元素 | — |
| `following` | 当前元素之后出现的所有元素(无视层级,不含直属后代) | — |
| `following-sibling` | 当前元素之后出现的所有同级元素 | — |
| `preceding` | 当前元素之前出现的所有元素(无视层级,不含直属祖先) | — |
| `preceding-sibling` | 当前元素之前出现的所有同级元素 | — |
| `namespace` | 不支持 | — |
**语法**`轴名::表达式`
```js
> $x('//body/ancestor-or-self::*')
< [body, html]
```
## 2. 路径格式
XPath 通过"路径表达式"Path Expression)选取元素,形式上与文件系统路径类似。
| 概念 | 说明 |
|:-----|:----------------------------------|
| `/` | 路径内部分隔符 |
| 绝对路径 | 以 `/` 起首,后跟根元素,如 `/step/step/...` |
| 相对路径 | 除绝对路径外的其他写法,如 `step/step` |
| `.` | 当前元素 |
| `..` | 当前元素的父元素 |
### 选取语法
| 符号 | 说明 |
|:-----------|:------------|
| `/` | 选取根元素 |
| `//` | 选取任意位置的某个元素 |
| `nodename` | 选取指定名称的元素 |
| `@` | 选取某个属性 |
## 3. 示例
以下示例基于这段 HTML
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>标题</title>
<meta property="author" content="作者" />
</head>
<body>
<div>
<title lang="eng">Harry Potter</title>
<p>29.39</p>
<p>usd</p>
</div>
<div>
<title lang="cn">Cpp高级编程</title>
<p>39.95</p>
<p>rmb</p>
</div>
<div id="list">
<dl>
<dd><a href="/1"></a></dd>
<dd><a href="/2"></a></dd>
<dd><a href="/3"></a></dd>
</dl>
</div>
</body>
</html>
```
| 表达式 | 结果 | 说明 |
|:-----------------------|:---------------|:--------------|
| `$x('/')` | `[document]` | 选取根元素 |
| `$x('/html')` | `[html]` | 绝对路径选取 |
| `$x('html/head/meta')` | `[meta, meta]` | 相对路径选取 |
| `$x('//p')` | `[p, p, p, p]` | 选取所有 p 元素 |
| `$x('html/body//a')` | `[a, a, a]` | 选取 body 下所有 a |
| `$x('//@lang')` | `[lang, lang]` | 选取属性 |
| `$x('//meta/..')` | `[head]` | 选取父元素 |
## 4. 谓语条件 (Predicate)
谓语条件是对路径表达式的附加筛选条件,写在方括号 `[]` 中。
| 表达式 | 结果 | 说明 |
|:-------------------------------|:-------------------------------|:--------|
| `html/head/meta[1]` | `<meta charset="utf-8">` | 选取第一个 |
| `html/head/meta[last()]` | `<meta property="author" ...>` | 选取最后一个 |
| `html/head/meta[last()-1]` | `<meta charset="utf-8">` | 选取倒数第二个 |
| `html/head/meta[position()>1]` | `<meta property="author" ...>` | 位置大于 1 |
| `//title[@lang]` | 两个 title | 具有特定属性 |
| `//title[@lang="eng"]` | English title | 属性值匹配 |
| `/html/body/div[dl]` | `<div id="list">` | 包含特定子元素 |
| `/html/body/div[p>35.00]` | Cpp 高级编程 div | 子元素值条件 |
## 5. 通配符
| 符号 | 说明 |
|:-----|:--------|
| `*` | 匹配任何元素 |
| `@*` | 匹配任何属性名 |
```js
$x('//*') // 选取所有元素
$x('/*/*') // 选取所有第二层元素
$x('//title[@*]') // 选取所有带属性的 title
```
## 6. 多路径选择
`|` 合并多个表达式的选取结果:
```js
$x('//title | //a') // 选取所有 title 和 a 元素
```
## 7. 函数
XPath 函数的参数可以是静态字符串或表达式,函数可嵌套调用。XPath 索引从 **1** 开始。
| 函数 | 说明 | 示例 |
|:---------------------|:----------|:------------------------------------------------------|
| `boolean()` | 转换为布尔值 | `boolean(//title)``true` |
| `number()` | 转换为数字 | `number(//p[1])``29.39` |
| `round()` | 四舍五入 | `round(//p[1])``29` |
| `ceiling()` | 向上取整 | `ceiling(//p[1])``30` |
| `floor()` | 向下取整 | `floor(//p[1])``29` |
| `concat()` | 字符串拼接 | `concat("cost:", //p[1], //p[2])``'cost:29.39usd'` |
| `contains()` | 判断是否包含 | `contains(//p[1], "29.39")``true` |
| `count()` | 统计元素个数 | `count(//p)``4` |
| `id()` | 根据 id 选取 | `id("list")``[dl#list]` |
| `last()` | 同级元素集合数量 | `//p[last()]` |
| `name()` | 返回元素名 | `name(//*[@id])``'dl'` |
| `normalize-space()` | 去除前后空白 | `normalize-space(" test ")``'test'` |
| `not()` | 返回布尔反值 | `//title[not(@lang)]` |
| `position()` | 返回元素位置 | `//meta[position()=2]` |
| `starts-with()` | 检查字符串开头 | `//title[starts-with(., "Cpp")]` |
| `string()` | 转换为字符串 | `string(//p)``'29.39'` |
| `string-length()` | 返回字符串长度 | `string-length(string(//p))``5` |
| `substring()` | 截取字符串 | `substring(string(//p), 1, 3)``'29.'` |
| `substring-after()` | 某字符之后的字符串 | `substring-after(string(//p), ".")``'39'` |
| `substring-before()` | 某字符之前的字符串 | `substring-before(string(//p), ".")``'29'` |
| `sum()` | 对数字求和 | `sum(//p[1])``69.34` |
| `translate()` | 依次替换字符 | `translate("aabbcc", "ac", "V8")``'VVbb88'` |