Skip to content

Commit 2650847

Browse files
committed
blog7
1 parent 1d042e2 commit 2650847

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Fork of Jsoup in [https://github.com/jhy/jsoup](https://github.com/jhy/jsoup)
2020

2121
### [Jsoup代码解读之六-parser(下)](https://github.com/code4craft/jsoup/blob/master/blogs/jsoup6.md)
2222

23+
### [Jsoup代码解读之七-select](https://github.com/code4craft/jsoup/blob/master/blogs/jsoup7.md)
24+
2325
-------
2426

2527
## 协议:

blogs/jsoup7.md

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,48 @@ Jsoup代码解读之七-实现一个CSS Selector
55

66
当当当!终于来到了Jsoup的特色:CSS Selector部分。selector也是[webmagic](https://github.com/code4craft/webmagic)开发的一个重点。附上一张street fighter的图,希望以后webmagic也能挑战Jsoup!
77

8-
w3c的CSS Selector规范:[http://www.w3.org/TR/CSS2/selector.html](http://www.w3.org/TR/CSS2/selector.html)
9-
108
Jsoup的select包里,类结构如下:
119

1210
![uml][2]
1311

14-
Jsoup的select核心是`Evaluator``Evaluator`是一个抽象类,它只有一个方法:
12+
在最开始介绍的Jsoup的时候,就已经说过`NodeVisitor``Selector`了。`Selector`是select部分的对外facade,而`NodeVisitor`则是遍历树的底层API,CSS Selector也是根据`NodeVisitor`实现的遍历。
13+
14+
Jsoup的select核心是`Evaluator`。Selector所传递的表达式,会经过`QueryParser`,最终编译成一个`Evaluator``Evaluator`是一个抽象类,它只有一个方法:
1515

1616
```java
1717
public abstract boolean matches(Element root, Element element);
1818
```
1919

20-
注意这里传入了root,是为了某些情况下对树进行遍历时用的。在我们调用document.select(css)方法之后,Jsoup会将
20+
注意这里传入了root,是为了某些情况下对树进行遍历时用的。
21+
22+
Evaluator的设计简洁明了,所有的Selector表达式单词都会编译到对应的Evaluator。例如`#xx`对应`Id``.xx`对应`Class``[]`对应`Attribute`。这里补充一下w3c的CSS Selector规范:[http://www.w3.org/TR/CSS2/selector.html](http://www.w3.org/TR/CSS2/selector.html)
2123

24+
当然,只靠这几个还不够,Jsoup还定义了`CombiningEvaluator`(对Evaluator进行And/Or组合),`StructuralEvaluator`(结合DOM树结构进行筛选)。
2225

26+
这里我们可能最关心的是,“div ul li”这样的父子结构是如何实现的。这个的实现方式在`StructuralEvaluator.Parent`中,贴一下代码了:
27+
28+
```java
29+
static class Parent extends StructuralEvaluator {
30+
public Parent(Evaluator evaluator) {
31+
this.evaluator = evaluator;
32+
}
33+
34+
public boolean matches(Element root, Element element) {
35+
if (root == element)
36+
return false;
37+
38+
Element parent = element.parent();
39+
while (parent != root) {
40+
if (evaluator.matches(root, parent))
41+
return true;
42+
parent = parent.parent();
43+
}
44+
return false;
45+
}
46+
}
47+
```
48+
49+
这里Parent包含了一个`evaluator`属性,会根据这个evaluator去验证所有父节点。注意Parent是可以嵌套的,所以这个表达式"div ul li"最终会编译成`And(And(Parent(Tag("div")),Tag("ul")),Tag("li"))`这样的Evaluator组合。
2350

2451
[1]: http://static.oschina.net/uploads/space/2013/0830/180244_r1Vb_190591.jpg
2552

0 commit comments

Comments
 (0)