文章目录
1. XML解析概述
1.1 XML解析
读取XML文件中所有的元素和数据,封装成JavaBean,或者在java中使用这些数据
1.2 解析方式
- DOM解析
Document Object Model 文档对象模型,在内存中创建一颗DOM树。可以对这棵树进行查询,修改,删除和添加。
优点:可以方便的操作XML中任何一个节点,可以进行增删改查的操作。
缺点:如果这个XML文件很大的时候,可能会出现内存泄漏的风险。
- SAX解析
事件驱动型解析方式,读取一行解析一行。
优点:理论上可以解析任意大小的XML文件。
缺点:不能对XML文件进行修改,只能读取。读取完毕之后不能再访问之前已经访问过的页面。
1.3 常见的XML解析开发包
开发工具包 | 说明 |
---|---|
JAXP | Oracle官方提供的API,同时支持DOM和SAX的开发 |
JDOM | JDOM是一个开源项目,它基于树型结构,利用纯JAVA的技术对XML文档实现解析、生成、序列化以及多种操作。 |
Dom4j | 是JDOM的升级品,用来读写XML文件的。具有性能优异、功能强大和极其易使用的特点,它的性能超过sun公司官方的dom技术,同时它也是一个开放源代码的软件,Hibernate也用它来读写配置文件。 |
Jsoup | jsoup 是一款Java 的HTML和XML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。 |
2. DOM解析原理和结构模型
- 解析原理
XML DOM 和 HTML DOM一样,XML DOM将整个XML文档加载到内存,生成一个DOM树,并获得一个Document对象,通过Document对象可以对DOM进行操作。
- 结构模型
3. 使用Jsoup
- 导包
3.1 获取Document对象
由于DOM方式解析XML文档所有都是节点,所有节点又都被封装到Document对象中,所以解析的重点就是获取Document对象。
- 根据文档字符串获取Document
static Document parse(String html)
: 通过给定的html字符串内容获取文档对象
package com.zmysna.xml;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.junit.Test;
/**
* 得到Document对象的三种方式
*/
public class Demo1Document {
/**
* 方式一:通过html的内容创建一个文档对象
*/
@Test
public void testDoc1() {
//创建字符串,包含html文件内容
String html = "<a href=\"#\">首页</a><a href=\"#\">门票</a>";
//根据html文档字符串获取Document对象
Document document = Jsoup.parse(html);
//输出document,注:输出的document会自动加上html中其它的标签。
System.out.println(document);
}
}
- 根据文件获取Document
static Document parse(File in, String charsetName)
根据文件和字符集获取文档对象。
/**
* 方式二:解析已经存在的html文件
*/
@Test
public void testDoc2() throws IOException {
//得到类路径下URL对象
URL url = Demo1Document.class.getResource("/index.html");
//通过URL对象得到文件的真实地址
String path = url.getPath();
//创建文件对象
File file = new File(path);
//通过文件对象和字符集得到Document对象
Document document = Jsoup.parse(file, "utf-8");
//输出Document对象的内容
System.out.println(document);
}
- 通过 url 获取文档对象
-
static Connection connect(String url)
通过url地址创建一个连接对象。 -
Document get()
通过Connection连接对象获得一个Document文档对象
/**
* 方式三:通过连接对象得到文档对象
*/
@Test
public void testDoc3() throws IOException {
//定义一个具体html网页的url,如:http://www.itcast.cn
String url = "http://www.itcast.cn";
//调用connect()方法,创建一个连接对象
Connection connection = Jsoup.connect(url);
//调用连接对象的get()方法,得到一个文档对象
Document document = connection.get();
System.out.println(document);
}
3.2 通过GET方法获取ELement元素对象
getElementById(String id) | 通过id得到一个元素 |
---|---|
getElementsByTag(String tagName) | 通过标签名得到一组元素 |
getElementsByClass(String className) | 通过类名得到一组元素 |
getElementsByAttribute(String key) | 通过属性名得到一组元素 |
package com.zmysna.xml;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
/**
* 使用GET方法得到元素
*/
public class Demo2Get {
public static void main(String[] args) throws IOException {
//获取资源文件index.xml路径地址
String path = Demo2Get.class.getResource("/index.html").getPath();
//获取的资源文件对象
File file = new File(path);
//解析资源文件并获取Document对象
Document document = Jsoup.parse(file, "utf-8");
//通过id得到home元素
Element home = document.getElementById("home");
//System.out.println(home);
//获取index.html中所有h3标签名称的元素列表并打印输出
Elements h3 = document.getElementsByTag("h3");
//h3.forEach(System.out::println);
//获取index.html中所有元素含有class属性值为item并打印输出
Elements item = document.getElementsByClass("item");
//item.forEach(System.out::println);
//获取所有包含type属性的元素并输出
Elements type = document.getElementsByAttribute("type");
type.forEach(System.out::println);
}
}
3.3 通过CSS选择器得到元素
//作用:通过CSS选择器得到一组元素
select(String cssQuery)
//作用:通过CSS选择器得到一个元素,如果匹配到多个,只返回第一个元素。
selectFirst(String cssQuery)
描述 | 语法 |
---|---|
根据id获取元素,id前面使用#符号 | #ID |
根据元素class属性获取元素 | .类名 |
根据元素名称获取元素 | 标签名 |
利用属性值来查找元素 | [属性名=‘属性值’] |
package com.zmysna.xml
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
/**
* 使用CSS选择器查询元素
*/
public class Demo3CssQuery {
public static void main(String[] args) throws IOException {
//1) 获取资源文件index.html路径地址
String path = Demo3CssQuery.class.getResource("/index.html").getPath();
//获取的资源文件对象
File file = new File(path);
//解析资源文件并获取Document对象
Document document = Jsoup.parse(file, "utf-8");
//获取id="footer"元素并输出元素名称
Element footer = document.selectFirst("#footer");
//System.out.println(footer);
//2) 含有class属性值为item并打印输出元素体内容
Elements items = document.select(".item");
//items.forEach(System.out::println);
//3) 获取index.html中所有h3标签名称的元素列表并打印输出元素名称
Elements h3 = document.select("h3");
//h3.forEach(System.out::println);
//4) 获取index.html中属性type值为"text"的所有元素列表并打印输出元素名称
Elements elements = document.select("[type='text']");
elements.forEach(System.out::println);
}
}
3.4 ELement中的方法
Element对象的方法 | 说明 |
---|---|
String attr("属性名") | 得到指定的属性值 |
Element children() | 得到当前元素的所有子元素 |
String tagName() | 得到当前元素的标签名 |
String text() | 得到当前元素主体内容 |
String html() | 得到当前元素中的Html() |
4. JsoupXPath
XPath 路径表达式的作用:DOM树中每个元素都有一个路径,可以通过这个路径来快速地找到某个指定的元素。不仅仅用在Jsoup中,其它的XML的DOM解析工具也是可以使用的,语法规则相同。
JsoupXpath 是一款纯Java开发的使用xpath解析HTML的解析器,JsoupXpath不是jsoup的一部分,是在jsoup基础上进行的扩展。
- 需要导包
)
4.1 核心类JXDocument和JXNode
- JXDocument
核心方法 | 说明 |
---|---|
JXDocument(Document doc) | 创建JXDocument对象 参数是:document对象 |
List<JXNode> selN(String xpath) | 通过xpath得到一组节点,节点是元素,属性,文本父类 |
JXNode selNOne(String xpath) | 通过xpath得到一个节点 |
- JXNode
方法 | 描述 |
---|---|
List<JXNode> sel(String xpath) | 在某个节点的基础上再次使用xpath, 再得到一组节点。相对路径的写法 |
Element getElement() | 通过节点对象得到元素对象 |
4.2 四种Xpath语法
- 绝对路径
- 相对路径
- 全文搜索
- 条件筛选
4.2.1 绝对路径
package com.zmysna.xml;
import cn.wanghaomiao.xpath.exception.XpathSyntaxErrorException;
import cn.wanghaomiao.xpath.model.JXDocument;
import cn.wanghaomiao.xpath.model.JXNode;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* 使用Xpath查询元素
*/
public class Demo4XPath {
JXDocument jxDocument; //它可以使用xpath
@Before
public void init() throws IOException {
//得到文件对象
File file = new File(Demo4XPath.class.getResource("/index.html").getPath());
//通过文件对象得到文档对象
Document document = Jsoup.parse(file, "utf-8");
//通过文档对象得到JXDocument对象
jxDocument = new JXDocument(document);
}
//使用绝对路径
@Test
public void testAbsolute() throws XpathSyntaxErrorException {
//定义Xpath表达式 /body/div/ul/li/a
String xpath = "/body/div/ul/li/a";
//使用jxDocument对象selN方法执行xpath获取元素节点列表
List<JXNode> jxNodes = jxDocument.selN(xpath);
//遍历输出每个节点
jxNodes.forEach(System.out::println);
}
}
4.2.2 相对路径
//使用相对路径
@Test
public void testRelative() throws XpathSyntaxErrorException {
//先采用jxDocument绝对路径的方式获取body节点
JXNode body = jxDocument.selNOne("/body");
//定义相对路径查找body下面一级的div节点列表
//JXNode中的sel()方法使用的是当前元素下的相对路径
List<JXNode> div = body.sel("/div/ul");
//打印输出所有的节点
div.forEach(System.out::println);
}
4.2.3 全文搜索路径
语法 | 说明 |
---|---|
//li | 查询所有的li |
//div/a/img | 查询所有div下面的a下面img |
//div//img/@src | 查询所有div下面img下src的属性值 |
//link/@href | 查询所有link下href属性值 |
//全文搜索
@Test
public void testGlobalSearch() throws XpathSyntaxErrorException {
//直接全文搜索所有的li元素列表并打印
List<JXNode> list1 = jxDocument.selN("//li");
//list1.forEach(System.out::println);
//直接全文搜索所有的div,再逐层级搜索下面的a元素下的img元素列表并打印
List<JXNode> list2 = jxDocument.selN("//div/a/img");
//list2.forEach(System.out::println);
//搜索任何一级div下的所有子孙img的src的属性值
List<JXNode> list3 = jxDocument.selN("//div//img/@src");
//list3.forEach(System.out::println);
//直接获取link元素里面href属性的值,注意属性要用@符号
List<JXNode> list4 = jxDocument.selN("//link/@href");
list4.forEach(System.out::println);
}
4.2.4 条件筛选
//条件过滤
@Test
public void testFilter() throws XpathSyntaxErrorException {
//搜索li,属性为class="nav-active"的元素并打印
List<JXNode> list1 = jxDocument.selN("//li[@class='nav-active']");
//list1.forEach(System.out::println);
//搜索li,属性为data-slide-to大于0的元素,再查询data-slide-to的属性值
List<JXNode> list2 = jxDocument.selN("//li[@data-slide-to>0]/@data-slide-to");
//list2.forEach(System.out::println);
//搜索a标签,属性为href="login.html"的元素,得到它的文本。
List<JXNode> list3 = jxDocument.selN("//a[@href='login.html']/text()");
//list3.forEach(System.out::println);
//搜索a标签,属性为href="index.html"的元素,得到它的HTML。
List<JXNode> list4 = jxDocument.selN("//a[@href='index.html']/html()");
list4.forEach(System.out::println);
}