Java高级特性 第14节 解析XML文档(2) - SAX 技术
一、SAX解析XML文档
SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。
1. SAX解析原理:
加载一点,读取一点,处理一点。对内存要求比较低。
SAX解析工具内置在jdk中:org.xml.sax.*

2. SAX解析工具核心:
核心的API:
- SAXParser类: 用于读取和解析xml文件对象
- parse(File f, DefaultHandler dh)方法: 解析xml文件
- 参数一: File:表示 读取的xml文件
- 参数二: DefaultHandler: SAX事件处理程序。使用DefaultHandler的子类
3. 解析步骤:
- 第一步:创建对象
1)创建SAXParser对象
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
2)调用parse方法
/**
* 参数一: xml文档
* 参数二: DefaultHandler的子类 MyDefaultHandler()为自定义
*/
parser.parse(new File(".\\src\\Go\\person.xml"), new MyDefaultHandler());
注意: 这里创建SAXParser对象 不能直接通过构造函数来创造,因为用到了单例工厂模式。
DefaultHandler类的API:后三个最重要
- void startDocument() : 在读到文档开始时调用void endDocument() :在读到文档结束时调用
- void startElement(String uri, String localName, String qName, Attributes attributes) : 读到开始标签时调用
- void endElement(String uri, String localName, String qName) :读到结束标签时调用
- void characters(char[] ch, int start, int length) : 读到文本内容时调用
- 第二步:自定义类继承DefaultHandler重写方法
这些都是要重写的,举个例子:
public class MyDefaultHandler extends DefaultHandler {
/**
* 开始文档时调用
*/
@Override
public void startDocument() throws SAXException {
System.out.println("MyDefaultHandler.startDocument()");
}
/**
* 开始标签时调用
* @param qName: 表示开始标签的标签名
* @param attributes: 表示开始标签内包含的属性列表
*/
@Override
public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
System.out.println("MyDefaultHandler.startElement()-->"+qName);
}
/**
* 结束标签时调用
* @param qName: 结束标签的标签名称
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("MyDefaultHandler.endElement()-->"+qName);
}
/**
* 读到文本内容的时调用
* @param ch: 表示当前读完的所有文本内容
* @param start: 表示当前文本内容的开始位置
* @param length: 表示当前文本内容的长度
* char[]( 张三 20) 100
* 98 2
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
//得到当前文本内容
String content = new String(ch,start,length);
System.out.println("MyDefaultHandler.characters()-->"+content);
}
/**
* 结束文档时调用
*/
@Override
public void endDocument() throws SAXException {
System.out.println("MyDefaultHandler.endDocument()");
}
}
xml文件:
<?xml version="1.0" encoding="utf-8"?>
<contactList>
<contact id="001" name="eric">
<name>张三</name>
<age>20</age>
<phone>134222223333</phone>
<email>zhangsan@qq.com</email>
<qq>432221111</qq>
</contact>
<contact id="002" name="jacky">
<name>eric</name>
<age>20</age>
<phone>134222225555</phone>
<email>lisi@qq.com</email>
<qq>432222222</qq>
</contact>
</contactList>
结果:
MyDefaultHandler.startDocument()
MyDefaultHandler.startElement()-->contactList
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->contact
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->name
MyDefaultHandler.characters()-->张三
MyDefaultHandler.endElement()-->name
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->age
MyDefaultHandler.characters()-->20
MyDefaultHandler.endElement()-->age
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->phone
MyDefaultHandler.characters()-->134222223333
MyDefaultHandler.endElement()-->phone
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->email
MyDefaultHandler.characters()-->zhangsan@qq.com
MyDefaultHandler.endElement()-->email
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->qq
MyDefaultHandler.characters()-->432221111
MyDefaultHandler.endElement()-->qq
MyDefaultHandler.characters()--> MyDefaultHandler.endElement()-->contact
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->contact
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->name
MyDefaultHandler.characters()-->eric
MyDefaultHandler.endElement()-->name
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->age
MyDefaultHandler.characters()-->20
MyDefaultHandler.endElement()-->age
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->phone
MyDefaultHandler.characters()-->134222225555
MyDefaultHandler.endElement()-->phone
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->email
MyDefaultHandler.characters()-->lisi@qq.com
MyDefaultHandler.endElement()-->email
MyDefaultHandler.characters()--> MyDefaultHandler.startElement()-->qq
MyDefaultHandler.characters()-->432222222
MyDefaultHandler.endElement()-->qq
MyDefaultHandler.characters()--> MyDefaultHandler.endElement()-->contact
MyDefaultHandler.characters()--> MyDefaultHandler.endElement()-->contactList
MyDefaultHandler.endDocument()
注意:结果中出现MyDefaultHandler.characters()–>空白 ,是因为<contactList> <contact>之间也是有文本的,是换行和空格被characters方法读取了。
二、DOM解析和SAX解析总结
| DOM解析 | SAX解析 |
| 原理: 一次性加载xml文档,不适合大容量的文件读取 | 原理: 加载一点,读取一点,处理一点。适合大容量文件的读取 |
| DOM解析可以任意进行增删改成 | SAX解析只能读 |
| DOM解析任意读取任何位置的数据,甚至往回读 | 取SAX解析只能从上往下,按顺序读取,不能往回读 |
| DOM解析面向对象的编程方法(Node,Element,Attribute),Java开发者编码比较简单。 | SAX解析基于事件的编程方法。java开发编码相对复杂 |
三、使用SAX读取XML数据实例
books.xml:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="1">
<name>冰与火之歌</name>
<author>乔治马丁</author>
<year>2014</year>
<price>89</price>
</book>
<book id="2">
<name>安徒生童话</name>
<year>2004</year>
<price>77</price>
<language>English</language>
</book>
</bookstore>
SAXParserHandler.java:
public class SAXParserHandler extends DefaultHandler {
String value = null;
Book book = null;
private ArrayList<Book> bookList = new ArrayList<Book>();
public ArrayList<Book> getBookList() {
return bookList;
}
int bookIndex = 0;
/**
* 用来标识解析开始
*/
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
System.out.println("SAX解析开始");
}
/**
* 用来标识解析结束
*/
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
System.out.println("SAX解析结束");
}
/**
* 解析xml元素
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
//调用DefaultHandler类的startElement方法
super.startElement(uri, localName, qName, attributes);
if (qName.equals("book")) {
bookIndex++;
//创建一个book对象
book = new Book();
//开始解析book元素的属性
System.out.println("======================开始遍历某一本书的内容=================");
//不知道book元素下属性的名称以及个数,如何获取属性名以及属性值
int num = attributes.getLength();
for(int i = 0; i < num; i++){
System.out.print("book元素的第" + (i + 1) + "个属性名是:" + attributes.getQName(i));
System.out.println("---属性值是:" + attributes.getValue(i));
if (attributes.getQName(i).equals("id")) {
book.setId(attributes.getValue(i));
}
}
}
else if (!qName.equals("name") && !qName.equals("bookstore")) {
System.out.print("节点名是:" + qName + "---");
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
//调用DefaultHandler类的endElement方法
super.endElement(uri, localName, qName);
//判断是否针对一本书已经遍历结束
if (qName.equals("book")) {
bookList.add(book);
book = null;
System.out.println("======================结束遍历某一本书的内容=================");
}
else if (qName.equals("name")) {
book.setName(value);
}
else if (qName.equals("author")) {
book.setAuthor(value);
}
else if (qName.equals("year")) {
book.setYear(value);
}
else if (qName.equals("price")) {
book.setPrice(value);
}
else if (qName.equals("language")) {
book.setLanguage(value);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
value = new String(ch, start, length);
if (!value.trim().equals("")) {
System.out.println("节点值是:" + value);
}
}
}
SAXTest.java:
public class SAXTest {
/**
* @param args
*/
public static void main(String[] args) {
//锟斤拷取一锟斤拷SAXParserFactory锟斤拷实锟斤拷
SAXParserFactory factory = SAXParserFactory.newInstance();
//通锟斤拷factory锟斤拷取SAXParser实锟斤拷
try {
SAXParser parser = factory.newSAXParser();
//锟斤拷锟斤拷SAXParserHandler锟斤拷锟斤拷
SAXParserHandler handler = new SAXParserHandler();
parser.parse("books.xml", handler);
System.out.println("~!~!~!共有" + handler.getBookList().size() + "本书");
for (Book book : handler.getBookList()) {
System.out.println(book.getId());
System.out.println(book.getName());
System.out.println(book.getAuthor());
System.out.println(book.getYear());
System.out.println(book.getPrice());
System.out.println(book.getLanguage());
System.out.println("----finish----");
}
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Java高级特性 第14节 解析XML文档(2) - SAX 技术的更多相关文章
- Java高级特性 第15节 解析XML文档(3) - JDOM和DOM4J技术
一.JDOM解析 特征: 1.仅使用具体类,而不使用接口. 2.API大量使用了Collections类. Jdom由6个包构成: Element类表示XML文档的元素 org.jdom: 解析xml ...
- Java高级特性 第13节 解析XML文档(1) - DOM和XPath技术
一.使用DOM解析XML文档 DOM的全称是Document Object Model,也即文档对象模型.在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树 ...
- Java高级特性 第12节 XML技术
一.XML简介 1. XML介绍 XML是可扩展标记语言(Extensible Markup Language ),XML是一种数据格式,类似 HTML,是使用标签进行内容描述的技术,与HTML不同的 ...
- 浅谈用java解析xml文档(四)
继续接上一文,这一阵子因为公司项目加紧,导致最后一个解析xml文档的方式,还没有总结,下面总结使用dom4J解析xml. DOM4J(Document Object Model for Java) 使 ...
- 浅谈用java解析xml文档(三)
接上一篇,本文介绍使用JDOM解析xml文档, 首先我们还是应该知道JDOM从何而来,是Breet Mclaughlin和Jason Hunter两大Java高手的创作成果,2000年初, JDOM作 ...
- java解析xml文档(dom)
DOM解析XML文档 读取本地的xml文件,通过DOM进行解析,DOM解析的特点就是把整个xml文件装载入内存中,形成一颗DOM树形结构,树结构是方便遍历和和操纵. DOM解析的特性就是读取xml文件 ...
- java 解析XML文档
Java 解析XML文档 一.解析XML文档方式: 1.DOM方式:将整个XML文档读取到内存中,按照XML文件的树状结构图进行解析. 2.SAX方式:基于事件的解析,只需要加载XML中的部分数据,优 ...
- 浅谈用java解析xml文档(二)
上一文中总结了dom解析xml文档的方式,本文开始总结使用SAX解析xml 的方式及它的优缺点! SAX(Simple API for XML),是指一种接口,或者一个软件包. 首先我们应该知道SAX ...
- Java解析XML文档(简单实例)——dom解析xml
一.前言 用Java解析XML文档,最常用的有两种方法:使用基于事件的XML简单API(Simple API for XML)称为SAX和基于树和节点的文档对象模型(Document Object ...
随机推荐
- el和jstl标签库讲解视频
https://www.bilibili.com/video/av22415283/?p=1
- linux下anaconda和keras配置过程
连接服务器,使用ssh协议. 下载anaconda bash Anaconda3-5.1.0-Linux-x86_64.sh(安装过程需要输入yes来添加环境变量,需要输入一次安装路径.) 因为环境变 ...
- Problem C: 平面上的点和线——Point类、Line类 (III)
Description 在数学上,平面直角坐标系上的点用X轴和Y轴上的两个坐标值唯一确定,两点确定一条线段.现在我们封装一个“Point类”和“Line类”来实现平面上的点的操作. 根据“append ...
- fdisk -l查看硬盘分区信息及硬盘分区介绍
原文:https://blog.csdn.net/a1809032425/article/details/79692035 linux fdisk 命令和df区别是什么? fdisk工具是分区工具:d ...
- react native 打包上架
https://www.jianshu.com/p/ce71b4a8a246 react-native bundle --entry-file index.ios.js --platform ios ...
- 团队-student_blog-最终程序
托管平台地址:https://github.com/gengwenhao/student_blog 小组名称:逛逛踹电脑 程序运行方法: 其他附加内容:demo版本:http://blog.gengw ...
- Oracle误删除数据和表的恢复办法包括truncate
在工作中我们操作数据库的时候经常会发生一个不该发生的问题:用户意外的删除一个非常重要的表或者是表中的数据而且没有备份,需要尽快的恢复,以下就是解决的办法: 主要是利用Oracle回收站的闪回特性ora ...
- C# copy() 与 Clone()区别
copy() 与 Clone()都创建了一个新对象 DataTable dt=new DataTable();DataTable dtcopy=dt.copy(); //copy复制的是值和 ...
- Ubuntu和Linux的区别
大家听别人介绍自己的Ubuntu时,会听到“我的操作系统是Linux的”.其实,这样介绍是缺乏严谨性滴.我们只要知道两点,基本上就搞清楚Linux和Ubuntu的关系: 1. 严格来说,Linu ...
- 11.2.0.1单实例DGduplicate过程
记录一次duplicate完整过程1)环境说明数据库版本oracle11.2.0.1,os linux 6.6备库应用的归档,最近一次是三个月前,由于DG环境以前是好的,因此直接迁移数据即可.本次使用 ...