reference/docs/xpath.md
2022-09-30 09:43:06 +08:00

390 lines
9.4 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 备忘清单
===
这是一份 XPath 选择器备忘单,其中列出了常用的 `XPath` 定位方法和 `CSS` 选择器
XPath 选择器
--------
### 入门
XPath 即为 XML 路径语言XML Path Language它是一种用来确定XML文档中某部分位置的计算机语言。
- [Xpath test bed](http://www.whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm) _(whitebeam.org)_
在 Firefox 或 Chrome 控制台中测试:
```js
$x('/html/body')
$x('//h1')
$x('//h1')[0].innerText
$x('//a[text()="XPath"]')[0].click()
```
### 后代选择器
| Xpath | CSS |
|--------------|--------------|
| `//h1` | h1 |
| `//div//p` | div p |
| `//ul/li` | ul > li |
| `//ul/li/a` | ul > li > a |
| `//div/*` | div > * |
| `/` | :root |
| `/html/body` | :root > body |
<!--rehype:className=show-header-->
### 有序选择器
| Xpath | CSS |
|---------------------|----------------------|
| `//ul/li[1]` | ul > li:first-child |
| `//ul/li[2]` | ul > li:nth-child(2) |
| `//ul/li[last()]` | ul > li:last-child |
| `//li[@id="id"][1]` | li#id:first-child |
| `//a[1]` | a:first-child |
| `//a[last()]` | a:last-child |
<!--rehype:className=show-header-->
### 属性选择器
<!--rehype:wrap-class=col-span-2 row-span-2-->
| Xpath | CSS |
|---------------------------------|----------------------|
| `//*[@id="id"]` | #id |
| `//*[@class="class"]` | .class |
| `//input[@type="submit"]` | input[type="submit"] |
| `//a[@id="abc"][@for="xyz"]` | a#abc[for="xyz"] |
| `//a[@rel]` | a[rel] |
| `//a[starts-with(@href, '/')]` | a[href^='/'] |
| `//a[ends-with(@href, '.pdf')]` | a[href$='pdf'] |
| `//a[contains(@href, '://')]` | a[href*='`:`//'] |
| `//a[contains(@rel, 'help')]` | a[rel~='help'] |
<!--rehype:className=show-header-->
### 兄弟姐妹选择器
| Xpath | CSS |
|--------------------------------------|----------|
| `//h1/following-sibling::ul` | h1 ~ ul |
| `//h1/following-sibling::ul[1]` | h1 + ul |
| `//h1/following-sibling::[@id="id"]` | h1 ~ #id |
<!--rehype:className=show-header-->
### jQuery
| Xpath | CSS |
|----------------------------------|----------------------------|
| `//ul/li/..` | $('ul > li').parent() |
| `//li/ancestor-or-self::section` | $('li').closest('section') |
| `//a/@href` | $('a').attr('href') |
| `//span/text()` | $('span').text() |
<!--rehype:className=show-header-->
### 杂项选择器
| Xpath | CSS |
|-----------------------------------|---------------------------|
| `//h1[not(@id)]` | h1:not([id]) |
| `//button[text()="Submit"]` | 文字匹配 |
| `//button[contains(text(),"Go")]` | 文本包含(子字符串) |
| `//product[@price > 2.50]` | 算术 |
| `//ul[*]` | 有孩子 |
| `//ul[li]` | 有孩子(具体) |
| `//a[@name or @href]` | 或逻辑 |
| `//a | //div` | 联合(加入结果) |
<!--rehype:className=show-header-->
XPath 表达式
-----------
### 步骤和轴
| - | - | - | - |
|------|------|------|-----------------|
| `//` | `ul` | `/` | `a[@id='link']` |
| Axis | Step | Axis | Step |
### 前缀
| 前缀 | 例子 | 意思是 |
|--------|-----------------------|----------|
| `//` | `//hr[@class='edge']` | 任何地方 |
| `/` | `/html/body/div` | 根 |
| `./` | `./div/p` | 相对的 |
<!--rehype:className=show-header-->
### Axes
| Axis(轴) | 例子 | 意思是 |
|------|---------------------|------------|
| `/` | `//ul/li/a` | 孩子 |
| `//` | `//[@id="list"]//a` | 后裔 |
<!--rehype:className=show-header-->
XPath Predicates(谓词)
----------
### Predicates(谓词)
```bash
//div[true()]
//div[@class="head"]
//div[@class="head"][@id="top"]
```
仅当某些条件为真时才限制节点集。它们可以被链接起来。
### 操作符
```bash
# 比较
//a[@id = "xyz"]
//a[@id != "xyz"]
//a[@price > 25]
```
```bash
# 逻辑 (and/or)
//div[@id="head" and position()=2]
//div[(x and y) or not(z)]
```
### 使用节点
```bash
# 在函数内部使用它们
//ul[count(li) > 2]
//ul[count(li[@class='hide']) > 0]
```
```bash
# 返回具有 `<li>` 子级的 `<ul>`
//ul[li]
```
您可以在谓词中使用节点。
### 索引
```bash
//a[1] # 第一个<a>
//a[last()] # 最后一个<a>
//ol/li[2] # 第二个<li>
//ol/li[position()=2] # 和上面一样
//ol/li[position()>1] #:not(:first-child)
```
`[]` 与数字一起使用,或者使用 `last()``position()`
### 链接顺序
```bash
a[1][@href='/']
a[@href='/'][1]
```
顺序很重要,这两个是不同的。
### 嵌套谓词
```
//section[.//h1[@id='hi']]
```
如果它有一个具有 `id='hi'``<h1>` 后代,则返回 `<section>`
XPath 函数
---------
<!--rehype:body-class=cols-2-->
### 节点功能
```bash
name() # //[starts-with(name(), 'h')]
text() # //button[text()="Submit"]
# //button/text()
lang(str)
namespace-uri()
```
```bash
count() # //table[count(tr)=1]
position() # //ol/li[position()=2]
```
### 字符串函数
```bash
contains() # font[contains(@class,"head")]
starts-with() # font[starts-with(@class,"head")]
ends-with() # font[ends-with(@class,"head")]
```
```bash
concat(x,y)
substring(str, start, len)
substring-before("01/02", "/") #=> 01
substring-after("01/02", "/") #=> 02
translate()
normalize-space()
string-length()
```
### 布尔函数
```bash
not(expr) # button[not(starts-with(text(),"Submit"))]
```
### 类型转换
```bash
string()
number()
boolean()
```
XPath Axes
----
<!--rehype:body-class=cols-2-->
### 使用轴
```bash
//ul/li # ul > li
//ul/child::li # ul > li (same)
//ul/following-sibling::li # ul ~ li
//ul/descendant-or-self::li # ul li
//ul/ancestor-or-self::li # $('ul').closest('li')
```
----
| | | | |
|------|------|------------|------|
| `//` | `ul` | `/child::` | `li` |
| Axis | Step | Axis | Step |
表达式的步骤由 `/` 分隔,通常用于选择子节点。 这并不总是正确的:您可以使用 `::` 指定不同的“轴”。
### 子轴
```bash
# 都一样
//ul/li/a
//child::ul/child::li/child::a
```
`child::` is the default axis. This makes `//a/b/c` work.
```bash
# 都一样
# 这是因为 `child::li` 是真实的
//ul[li]
//ul[child::li]
```
```bash
# 都一样
//ul[count(li) > 2]
//ul[count(child::li) > 2]
```
### 后代或自我轴
```bash
# 都一样
//div//h4
//div/descendant-or-self::h4
```
`//``descendant-or-self::` 轴的缩写。
```bash
# 都一样
//ul//[last()]
//ul/descendant-or-self::[last()]
```
### 其他轴
<!--rehype:wrap-class=row-span-2-->
| Axis | Abbrev | Notes |
|--------------------|--------|-------|
| `ancestor` | | |
| `ancestor-or-self` | | |
| `attribute` | `@` | `@href``attribute::href` 的缩写 |
| `child` | | `div``child::div` 的缩写 |
| `descendant` | | |
| `descendant-or-self` | `//` | `//``/descendant-or-self::node()/`的缩写 |
| `namespace` | | |
| `self` | `.` | `.``self::node()` 的缩写 |
| `parent` | `..` | `..``parent::node()` 的缩写 |
| `following` | | |
| `following-sibling` | | |
| `preceding` | | |
| `preceding-sibling` | | |
<!--rehype:className=show-header-->
您还可以使用其他轴。
### 联合
```bash
//a | //span
```
使用 `|` 连接两个表达式。
XPath 更多示例
-------------
<!--rehype:body-class=cols-2-->
### 示例
```bash
//* # 所有元素
count(//*) # 计算所有元素
(//h1)[1]/text() # 第一个 h1 标题的文本
//li[span] # 找到一个 <li> 里面有一个 <span>
# ...扩展到 //li[child::span]
//ul/li/.. # 使用 .. 选择父级
```
### 查找(父)家长
```bash
//section[h1[@id='section-name']]
```
查找直接包含 `h1#section-name``<section>`
```bash
//section[//h1[@id='section-name']]
```
查找包含 `h1#section-name``<section>`
(与上面相同,但使用后代或自我而不是孩子)
### 最近的
```bash
./ancestor-or-self::[@class="box"]
```
`jQuery``$().closest('.box')` 一样工作。
### 属性
```bash
//item[@price > 2*@discount]
```
查找 `<item>` 并检查其属性
另见
--------
* [Devhints](https://devhints.io/xpath) _(devhints.io)_
* [Xpath test bed](http://www.whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm) _(whitebeam.org)_