Jsoup代码解读之二-DOM相关对象
Jsoup代码解读之二-DOM相关对象
之前在文章中说到,Jsoup使用了一套自己的DOM对象体系,和Java XML API互不兼容。这样做的好处是从XML的API里解脱出来,使得代码精炼了很多。这篇文章会说明Jsoup的DOM结构,DOM的遍历方式。在下一篇文章,我会并结合这两个基础,分析一下Jsoup的HTML输出功能。
DOM结构相关类
我们先来看看nodes包的类图:

这里可以看到,核心无疑是Node类。
Node类是一个抽象类,它代表DOM树中的一个节点,它包含:
- 父节点
parentNode以及子节点childNodes的引用 - 属性值集合
attributes - 页面的uri
baseUri,用于修正相对地址为绝对地址 - 在兄弟节点中的位置
siblingIndex,用于进行DOM操作
Node里面包含一些获取属性、父子节点、修改元素的方法,其中比较有意思的是absUrl()。我们知道,在很多html页面里,链接会使用相对地址,我们有时会需要将其转变为绝对地址。Jsoup的解决方案是在attr()的参数开始加"abs:“,例如attr(“abs:href”),而absUrl()就是其实现方式。我写的爬虫框架webmagic里也用到了类似功能,当时是自己手写的,看到Jsoup的实现,才发现自己是白费劲了,代码如下:
URL base;
try {
try {
base = new URL(baseUri);
} catch (MalformedURLException e) {
// the base is unsuitable, but the attribute may be abs on its own, so try that
URL abs = new URL(relUrl);
return abs.toExternalForm();
}
// workaround: java resolves '//path/file + ?foo' to '//path/?foo', not '//path/file?foo' as desired
if (relUrl.startsWith("?"))
relUrl = base.getPath() + relUrl;
// java URL自带的相对路径解析
URL abs = new URL(base, relUrl);
return abs.toExternalForm();
} catch (MalformedURLException e) {
return "";
}
Node还有一个比较值得一提的方法是abstract String nodeName(),这个相当于定义了节点的类型名(例如Document是'#Document',Element则是对应的TagName)。
Element也是一个重要的类,它代表的是一个HTML元素。它包含一个字段tag和classNames。classNames是"class"属性解析出来的集合,因为CSS规范里,“class"属性允许设置多个,并用空格隔开,而在用Selector选择的时候,即使只指定其中一个,也能够选中其中的元素。所以这里就把"class"属性展开了。Element还有选取元素的入口,例如select、getElementByXXX,这些都用到了select包中的内容,这个留到下篇文章select再说。
Document是代表整个文档,它也是一个特殊的Element,即根节点。Document除了Element的内容,还包括一些输出的方法。
Document还有一个属性quirksMode,大致意思是定义处理非标准HTML的几个级别,这个留到以后分析parser的时候再说。
DOM树的遍历
Node还有一些方法,例如outerHtml(),用作节点及文档HTML的输出,用到了树的遍历。在DOM树的遍历上,用到了NodeVisitor和NodeTraversor来对树的进行遍历。NodeVisitor在上一篇文章提到过了,head()和tail()分别是遍历开始和结束时的方法,而NodeTraversor的核心代码如下:
public void traverse(Node root) {
Node node = root;
int depth = 0;
//这里对树进行后序(深度优先)遍历
while (node != null) {
//开始遍历node
visitor.head(node, depth);
if (node.childNodeSize() > 0) {
node = node.childNode(0);
depth++;
} else {
//没有下一个兄弟节点,退栈
while (node.nextSibling() == null && depth > 0) {
visitor.tail(node, depth);
node = node.parent();
depth--;
}
//结束遍历
visitor.tail(node, depth);
if (node == root)
break;
node = node.nextSibling();
}
}
}
这里使用循环+回溯来替换掉了我们常用的递归方式,从而避免了栈溢出的风险。
实际上,Jsoup的Selector机制也是基于NodeVisitor来实现的,可以说NodeVisitor是更加底层和灵活的API。
Jsoup代码解读之二-DOM相关对象的更多相关文章
- Jsoup代码解读之四-parser
Jsoup代码解读之四-parser 作为Java世界最好的HTML 解析库,Jsoup的parser实现非常具有代表性.这部分也是Jsoup最复杂的部分,需要一些数据结构.状态机乃至编译器的知识.好 ...
- Jsoup代码解读之六-防御XSS攻击
Jsoup代码解读之八-防御XSS攻击 防御XSS攻击的一般原理 cleaner是Jsoup的重要功能之一,我们常用它来进行富文本输入中的XSS防御. 我们知道,XSS攻击的一般方式是,通过在页面输入 ...
- Jsoup代码解读之三-Document的输出
Jsoup代码解读之三-Document的输出 Jsoup官方说明里,一个重要的功能就是output tidy HTML.这里我们看看Jsoup是如何输出HTML的. HTML相关知识 分析代码前 ...
- Jsoup代码解读之五-实现一个CSS Selector
Jsoup代码解读之七-实现一个CSS Selector 当当当!终于来到了Jsoup的特色:CSS Selector部分.selector也是我写的爬虫框架webmagic开发的一个重点.附上一张s ...
- Jsoup代码解读之一-概述
Jsoup代码解读之一-概述 今天看到一个用python写的抽取正文的东东,美滋滋的用Java实现了一番,放到了webmagic里,然后发现Jsoup里已经有了…觉得自己各种不靠谱啊!算了,静下心来学 ...
- mybatis源码解读(二)——构建Configuration对象
Configuration 对象保存了所有mybatis的配置信息,主要包括: ①. mybatis-configuration.xml 基础配置文件 ②. mapper.xml 映射器配置文件 1. ...
- 2017.2.7 开涛shiro教程-第六章-Realm及相关对象(二)
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第六章 Realm及相关对象(二) 1.Authenticatio ...
- JavaScript -- 时光流逝(十二):DOM -- Element 对象
JavaScript -- 知识点回顾篇(十二):DOM -- Element 对象 (1) element.accessKey: 设置或返回accesskey一个元素,使用 Alt + 指定快捷键 ...
- 优秀开源代码解读之JS与iOS Native Code互调的优雅实现方案
简介 本篇为大家介绍一个优秀的开源小项目:WebViewJavascriptBridge. 它优雅地实现了在使用UIWebView时JS与ios 的ObjC nativecode之间的互调,支持消息发 ...
随机推荐
- phpcms自定义分页
在global.func.php中找到分页函数function pages($num, $curr_page, $perpage = 20, $urlrule = '', $array = array ...
- HTML5 Placeholder实现input背景文字提示效果
这篇文章我们来看看什么是input输入框背景文字提示效果,如下图所示: 这种效果现在网上非常的普遍流行,但大部分是使用JavaScript实现的.但HTML5给我们提供了新的纯HTML的实现方式,不需 ...
- PHP利用递归法获取多级类别的树状数组
数据结构:category(id, pid, name),对应:信息ID,父项ID,类别名 测试数据: $aryCate = array( array('id' => 1, 'pid' => ...
- Java+Python+Jython环境变量配置
一.Java 环境变量配置: 新建系统变量JAVA_HOME 和CLASSPATH 变量名:JAVA_HOME 变量值:C:\Program Files\Java\jdk1.7.0变量名:CLASSP ...
- UVA1351-----String Compression-----区间DP(记忆化搜索实现)
本文出自:http://blog.csdn.net/dr5459 题目地址: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&a ...
- 总结:C#变量,占位符等相关知识
新年耽误了不少时间,好久没认真的坐下来学习了,新年也快完了,又要开始正式学习了,按着视频教学学习,用了一天的时间,学习了下简单的变量及其相关的输入输出和应用,学了几种最基本的类型: int(整型) c ...
- 试用cmd markdown
欢迎使用 Cmd Markdown 编辑阅读器 我们理解您需要更便捷更高效的工具记录思想,整理笔记.知识,并将其中承载的价值传播给他人,Cmd Markdown 是我们给出的答案 -- 我们为记录思想 ...
- CSS3六边形
<!DOCTYPE html> <!-- saved from url=(0043)http://dbox.whosemind.net/demo/liufang.html --> ...
- Java通过JDBC链接数据库,数据库中wen
连接数据库设置编码 jdbc:mysql://地址:3306/数据库名?characterEncoding=utf8
- 前端页面优化:javascript图片延迟加载
自己写了个简单的图片延迟加载小插件. 功能如下: 页面刷新,当前屏幕图片直接加载真实地址,body被卷去的部分和下方未显示的部分的img均加载通用图片如:loding.gif 随着屏幕上下滚动加载相应 ...