前言
前面了解了XML的使用,语法,规范和DTD、Schema
真的了解XML吗? - XML 基础
继续对XML学习:XML解析
目录
- XML解析
- 解析方式
- 解析技术
- dom4j
4.1. 一个dom4j案例
4.2. dom4j操作详解 - XPath
5.1. 一个XPath案例 - Jsoup
6.1. Jsoup操作
6.2. Jsoup中的对象
6.3. 快速查询 - Jsoup和XPath
- 总结
XML解析
我们知道XML的作用是网络传输数据和存储数据
而解析就是:通过对XML文件的操作,将XML文件中的数据取出读取到内存中,然后就可以处理这些数据
操作XML文件:
- 将XML文件的数据读取到内存(解析)
- 将内存中的数据保存到XML文件(持久化)
当然XML主要还是解析,持久化很少用
解析方式
XML解析方式主流有三种:
- DOM(Document Object Model:文档对象模型):将标记语言文件一次性加载进内存,在内存中形成DOM树,所以速度较慢,占内存多
DOM是W3C组织推荐的处理XML的方式
JS操作HTML文件就是DOM的思想
DOM树:从根结点出发到各个子元素,类似与一个树形图
它可以对XML文件进行增删改查
有两个分支:jDom和dom4j
- SAX(Simple API for XML):它不是一次读取全部文件,而是读一行释放一行,基于事件驱动完成元素的解析,速度快,占内存少
不是官方标准,但是几乎所有的XML解析器都支持
只能进行查询 - Pull:Pull和SAX类似,都是轻量级的解析,是第三方开源的Java项目,在Android 内核中嵌入了Pull,只能进行解析(主要在移动端,不详细介绍)
解析技术
- JAXP:sun公司提供的解析器,支持DOM和SAX,但性能低、使用复杂,基本已经淘汰
- jdom:对DOM进行封装,简化了使用
- dom4j:在jdom的基础上进行了改进,在服务器端使用较多
- Jsoup:Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据(Jsoup主要还用来处理HTML的,但是同为标记语言,处理XML一样高效)
主要的解析器是dom4j和Jsoup,详细了解这两者
dom4j
百度百科:
dom4j是一个Java的XML API,是jdom的升级品,用来读写XML文件的。dom4j是一个十分优秀的JavaXML API,具有性能优异、功能强大和极其易使用的特点,它的性能超过sun公司官方的dom技术,同时它也是一个开放源代码的软件,可以在SourceForge上找到它。在IBM developerWorks上面还可以找到一篇文章,对主流的Java XML API进行的性能、功能和易用性的评测,所以可以知道dom4j无论在哪个方面都是非常出色的。如今可以看到越来越多的Java软件都在使用dom4j来读写XML,特别值得一提的是连Sun的JAXM也在用dom4j。这已经是必须使用的jar包, Hibernate也用它来读写配置文件
一个dom4j案例
-
首先将dom4j.jar包导入项目
-
准备好已经存储了数据的xml文件
两个book元素
这个是符合我们自定义的Schema约束的xml文件(详情:真的了解XML吗? - XML 基础):
books.xml:
<?xml version="1.0"?>
<books
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.W3Cshool.cn/xml books.xsd"
xmlns="http://www.W3Cshool.cn/xml">
<book sn="bookNum1">
<name>时间简史</name>
<author>霍金</author>
<price>75</price>
</book>
<book sn="bookNum2">
<name>三国演义</name>
<author>罗贯中</author>
<price>100</price>
</book>
</books>
- 新建一个类,通过dom4j编程获得xml的数据
package com.company.Test;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.List;
public class Book {
public static void main(String[] args) throws DocumentException {
//创建SAXReader对象
SAXReader saxReader = new SAXReader();
//SAXReader对象负责读取xml文件,返回Document
Document document = saxReader.read("src/com/company/xml/books.xml");
System.out.println("doucument对象:"+document);
//通过Document拿到根元素
Element rootElement = document.getRootElement();
System.out.println("根元素:"+rootElement);
//通过根元素获得所有book元素,存放到列表中
List<Element> books = rootElement.elements("book");
//迭代所有的book,获得子标签
for( Element book : books){
Element name = book.element("name");
System.out.println("name子元素:"+name);
Element author = book.element("author");
Element price = book.element("price");
System.out.println("书籍信息: 书名:"+name.getText()+",作者:"+author.getText()+",价格:"+price.getText());
}
}
}
这个结果中包含着一些信息:
- 通过dom4j获得的是Document树,从根元素出发可以找到子元素
- 验证了Schema约束确实是有前缀的,前缀就是命名空间,只是在书写的时候省略了
- 得到的一个元素中会包含多种信息
dom4j操作详解
这是dom4j压缩包里的内容:
docs是第三方类库的学习文档
lib是dom4j需要依赖的jar包
src是dom4j源码
学习dom4j的操作当然要去学习文档看看了:进入docs文档-》index.html进入官网
Quick start是快速入门案例
当然,我们不需要去深入研究dom4j,了解一下API就够了
有哪些常用的API呢?
- 解析XML文档,有DOMReader和SAXReader两种,看名字就知道,一种是DOM解析方法,一种是SAX解析方法
SAXReader saxReader = new SAXReader();
DOMReader domReader = new DOMReader();
Document document = saxReader.read("src/com/company/xml/books.xml");
SAXReader对象中read方法可以传入各种参数
而DOMReader对象的read方法仅能传入Document(Document是一个接口,具体实现还是靠实现类):
也就是要先将xml文件加载进内存,然后获得该Document再解析
- 获取元素
dom4j是将xml解析成树型,即要按照父子关系一步一步获得元素
先得到根元素:
Element rootElement = document.getRootElement();
再根据名字得到子元素:
List<Element> books = rootElement.elements("book");
Element name = book.element("name");
有两种方法:elements和element
当有多个子元素,可以使用elements方法得到一个列表List
当仅单个元素,可以用element方法获得Element (Element是一个接口)
- 操作元素
XML中元素里会有属性、文本
可以通过Element进行操作
有很多方法,大致就是:获得各种信息(文本、属性、命名空间等);添加元素、属性等
XPath
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言
XPath 是在XML文档中查找信息的语言;通过元素和属性进行查找;简化了 Dom4j 查找节点的过程
一些语法:
语法 | 意义 |
---|---|
/books/book | 从根元素开始逐层找,以”/”开头 |
//name | 直接获取所有 name 元素对象,以“//”开头 |
//books/* | 获取所有 student 元素的所有子元素对象 |
//book[1]或 //book[last()] | 获取所有 book元素的第一个或最后一个 |
//book[@sn] | 获取所有带 sn 属性的 book元素对象 |
//book[@sn=“bookNum1”] | 获取 sn 等于 bookNum1 的 book元素对象 |
一个XPath案例
-
先导入包
jaxen-1.1-beta-6.jar
-
有xml文件,且要分清是否有命名空间
我这个就是有命名空间的
- 开始编程
package com.company.Test;
import com.company.Entity.Book;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import java.util.HashMap;
public class BookXPath {
public static void main(String[] args) throws DocumentException {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/com/company/xml/books.xml");
System.out.println(document);
//查询sn为bookNum1的书籍
//如果xml没有命名空间,这种写法是对的
//XPath xPath = document.createXPath("/books/book[@sn='bookNum1']");
//如果xml有命名空间
//先创建hashmap存放命名空间
HashMap xmlmap = new HashMap();
xmlmap.put("ns","http://www.W3Cshool.cn/xml");
//创建xpth对象,并查找信息
XPath path = document.createXPath("/ns:books/ns:book[@sn='bookNum1']");
//将命名空间导入xpth
path.setNamespaceURIs(xmlmap);
//获取结点
Element book = (Element)path.selectSingleNode(document);
System.out.println(book);
//根据元素名获得信息
String name = book.elementText("name");
String author = book.elementText("author");
String price = book.elementText("price");
//封装成一个book类
Book aBook = new Book(name,author,Integer.parseInt(price));
System.out.println(aBook);
}
}
创建一个Entity包,创建一个Book实体类:
package com.company.Entity;
public class Book {
private String name;
private String author;
private Integer price;
public Book(String name, String author, Integer price) {
this.name = name;
this.author = author;
this.price = price;
}
@Override
public String toString() {
return "book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
如果XML没有命名空间,就可以很简单的直接在createXPath方法里写语法就可以
如果XML有命名空间,就需要设置一个HashMap,并将命名空间放入且命名一个key
注意语法(ns:book)
XPath path = document.createXPath("/ns:books/ns:book[@sn='bookNum1']");
path.setNamespaceURIs(xmlmap);
注意:map的命名空间的key别命名一些关键字如src等,这个会造成错误
通过Xpth可以较简单的获得元素
Xpath还可以在HTML中使用,不单单是XML
Jsoup
百度百科:
jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据
它的主要功能:
- 从一个URL,文件或字符串中解析HTML、XML;
- 使用DOM或CSS选择器来查找、取出数据;
- 可操作HTML、XML元素、属性、文本
显然,Jsoup主要是用来操作HTML的,但是同为标记语言,一样可以操作XML
Jsoup操作
-
同样要导入包:jsoup-1.13.1.jar
-
编写程序BookJsoup.class
package com.company.Test;
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;
public class BookJsoup {
public static void main(String[] args) throws IOException {
//获取Document文档
//获得student.xml的path
String path = "src/com/company/xml/books.xml";
//解析xml
Document document = Jsoup.parse(new File(path), "UTF-8");
//获取元素,Elements继承了ArrayList
Elements books = document.getElementsByTag("book");
System.out.println(books.size());
//获得第一个book
Element element = books.get(0);
//获得所有文本信息
String text = element.text();
System.out.println("文本是:"+text);
//获得name信息
String name = element.getElementsByTag("name").text();
System.out.println("第一本书的name:"+name);
}
}
可以看出,Jsoup的操作类似JavaScript,先获得dom树,再通过getElementsByTag等等操作得到元素、文本
Jsoup中的对象
- Jsoup对象:解析器,类似与SAXReader,通过parse方法解析xml文件,返回document
- Document对象:就是dom树
- Elements对象:继承了ArrayList,类似于存储Element的列表,和dom4j中自定义的List< Element>
- Element对象:元素对象
- Node对象:结点对象
对JavaScript有基础的,可以看出Jsoup和JS是真的像
常用的方法也是类似:
快速查询
我们如果想要获得第一个book的name元素的值
需要通过: books->book->name->text
而Jsoup提供了简单的查询方法:选择器
package com.company.Test;
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;
public class BookJsoup {
public static void main(String[] args) throws IOException {
//获取Document文档
//获得student.xml的path
String path = "src/com/company/xml/books.xml";
//解析xml
Document document = Jsoup.parse(new File(path), "UTF-8");
//选择器
Elements selectName = document.select("name");
System.out.println(selectName);
}
}
即可得到所有name元素
Jsoup和XPath
前面dom4j使用的快速查询的方法:XPath
一样可以和Jsoup一起使用(但是XPath与Jsoup关系并不大,XPath是操作dom树)
但是需要导入Jsoup的XPath包:JsoupXpath.jar
JsoupXpath下载地址
JsoupXpath包是一个中国人写的,随着版本的更替有了一些变化
在1.x的版本中,新建一个JXDocument对象是
import cn.wanghaomiao.xpath.model.JXDocument包
而在2.x版本已经更新了,JXDocument.create方法创建JXDocument
依赖也变成了import org.seimicrawler.xpath.JXDocument;
查询语法还是XPath的语法,不过要选择不同的查询方法
sel;selN;selNOne;SelOne
具体的用法可以看作者的github
总结
- XML的解析技术有:DOM;SAX;Pull
- 其中DOM是将Document全部加载进内存,形成dom树,可以进行增删改查,缺点是占用内存大,速度慢
- SAX是基于事件驱动,将Document一行一行的读取,释放;只能进行查询操作,占用内存小(仅一行),速度快
- Pull类似与SAX,使用与移动端,Android 内嵌了Pull
- 常用的解析器有dom4j和Jsoup
- 通过XPath可以进行快速查询