上一篇简单介绍了dom解析xml文件的用法,但是dom解析有一个缺点,就是dom解析前需要将xml文件一次性的读入内存当中,而SAX解析则解决了这个问题。
SAX:是Simple API for XML的简写,既是一种接口,也是一种软件包。
SAX是一种XML解析的替代方法。SAX不同于DOM解析,它逐行扫描文档,一边扫描一边解析,所以它内存占用少,对于大型文档的解析是个很好的优势。
首先是解析的步骤:
- 创建SAX解析器工厂对象; SAXParseFactory spf = SAXParserFactory.newInstance();
- 使用解析器工厂创建解析器实例;SAXParse saxParser = spf.newSAXParser();
- 创建xml内容解析器对象;PersonHandler ph = new PersonHandler();
- 开始解析文档调用的方法
- 结束解析文档调用的方法
- 解析开始元素调用的方法
- 解析结束元素调用的方法
- 解析文本内容调用的方法
- 创建xml文件输入流,开始解析xml文件:
SAX是从上往下依次解析xml文档的,所以解析的过程并不具备层次性,从输入流开始的地方解析,根据解析到的不同的元素、内容回调合适的方法进行解析,下面是一个以teacher.xml文件为例的解析实例, 将从xml文件中解析出来的teacher的id、name以及desc存入一个Teacher对象中,病输出:
teacher.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<teacher id="1">
<name>小白</name>
<desc>小白人</desc>
</teacher>
<teacher id="2">
<name>小黑</name>
<desc>小黑人</desc>
</teacher>
</person>
要存入的Teacher类定义如下:
package xml;
/**
* Created by zhuxinquan on 16-1-20.
*/
public class Teacher {
private int id;
private String name;
private String desc;
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
public Teacher() {
}
public Teacher(int id, String name, String desc) {
this.id = id;
this.name = name;
this.desc = desc;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
下面是SAX解析xml文件的源代码:
package xml;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* Created by zhuxinquan on 16-1-22.
*/
public class SaxParseDemo {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
//创建SAX解析器工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//根据工厂创建解析器对象
SAXParser sax = factory.newSAXParser();
PersonHandler ph = new PersonHandler();
//开始解析
sax.parse((InputStream) new FileInputStream("teacher.xml"), ph);
List<Teacher> list = ph.getTeachers();
System.out.println(list);
}
}
如同上面介绍的步骤一样,该文件主要定义解析器工厂、解析器对象以及声明内容解析对象,xml文件的主要解析在与定义的内容解析内容,如下:
package xml;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
/**
* SAX解析的内容处理器
* 进行回调使用
* Created by zhuxinquan on 16-1-22.
*/
public class PersonHandler extends DefaultHandler {
private List<Teacher> teachers = null;
private Teacher teacher;
private String tag;
//开始解析文档时调用的方法
public List<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(List<Teacher> teachers) {
this.teachers = teachers;
}
@Override
public void startDocument() throws SAXException {
teachers = new ArrayList<Teacher>();
}
/**
* 解析开始标签时调用的方法
* @param uri:命名空间
* @param localName:元素的本地名称,即元素名(标签名),不带前缀
* @param qName:带前缀的元素名称
* @param attributes:存储标签元素的属性
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if("teacher".equals(qName)){
teacher = new Teacher();
//取出属性并添加到teacher中
teacher.setId(Integer.parseInt(attributes.getValue("id")));
}
tag = qName;
}
//解析结束标签时调用的方法
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if("teacher".equals(qName)){
teachers.add(teacher);
}
tag = null;
}
//xml文档解析完成调用的方法
@Override
public void endDocument() throws SAXException {
System.out.println("XML解析完毕!");
}
//解析文本内容时调用的方法
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if(tag != null){
//取出属性并添加到teacher中
if("name".equals(tag)){
teacher.setName(new String(ch, start, length));
}else if("desc".equals(tag)){
teacher.setDesc(new String(ch, start, length));
}
}
}
}