一、SAX解析原理简介
原理:SAX方式采用事件处理的方式解析XML文件,涉及到两个部分:解析器和事件处理器。
SAX解析器从XML文件第一行开始往下读,读取一行处理一行(
不能往回读取
)。解析器每读取一行将会触发特定的事件,然后调用事件处理器中处理该事件的方法。
解析器:可以使用Jaxp的API创建,创建SAX解析器后就可以指定它解析某个XML文件。
事件处理器:由程序员编写,程序员通过事件处理器中的方法的参数,就可以很轻松地得到SAX解析器解析到的数据,从而可以决定如果对数据进行处理。
解析过程:解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的某个一个部分,都会去调用事件处理器中的一个方法。解析器在调用事件处理器中的方法时,会把当前解析到的XML内容当作方法的参数传给事件处理器。
SAX解析方式优点:SAX解析方式占用内存少,解析速度快;缺点是:只适合做文档的读取,不适合做文档的增删查改。
二、解析步骤
方法一:创建解析工厂 ——> 获取解析器 ——> 获取读取器 ——> 设置事件处理器 ——> 读取XML文档并解析;
方法二:
创建解析工厂 ——> 获取解析器 ——> 解析XML文档;
如下图所示,事件处理器有下面四种,一般情况下就使用内容处理器:ContentHander
三、内容处理器的实现
1. 实现ContentHander接口
ContentHander接口一共有11个内容事件处理方法,常用的有
characters、startDocument、endDocument
三个方法,其它方法也必须实现,可以为空。
2. 继承DefaultHander类
DefaultHander实现了
ContentHander接口,我们自己写的类可以继承
DefaultHander覆盖需要用到的方法。
DefaultHander类似于适配器类,开发中用的最多的同样是覆盖
characters、startDocument、endDocument
三个方法。
例如:
public class SAXContemtHander extends DefaultHandler
{
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
{
//触发标签的开始事件调用此函数
//qName为标签的名字
//attributes为标签的属性的集合
//you can do something
}
@Override
public void characters(char[] ch, int start, int length)
{
//触发标签的内容调用此函数
//String text = new String(ch,start,length); text表示解析的内容
//you can do something
}
@Override
public void endElement(String uri, String localName, String qName)
{
//触发标签的结束事件调用此函数
//qName为标签的名字
//you can do something
}
}
四、代码实现
方法一:
//1. 创建解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//2. 得到解析器
SAXParser parser = factory.newSAXParser();
//3. 获取读取器
XMLReader reader = parser.getXMLReader();
//4. 设置事件处理器
reader.setContentHandler(内容处理器的对象);
//5. 解析XML文档内容
reader.parse(pathString);
方法二:
//1. 创建解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//2. 得到解析器
SAXParser parser = factory.newSAXParser();
//3. 解析XML文档
parser.parse(new File(xmlPathString, 内容处理器的对象);
五、例子程序
本例子将XML文件中的数据解析成JavaBean对象,并把对象放到List容器中。
1. XML数据样本:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<学生信息>
<学生 姓名="陈小宝" 学号="201207203" 学院="计算机">
<语文>90</语文>
<数学>100</数学>
<英语>90</英语>
<艺术>92</艺术>
<计算机>100</计算机>
</学生>
<学生信息>
2. 内容处理器
package cn.liyin.jaxp;
import com.liyin.Domain.Student;
import java.util.LinkedList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* 继承DefaultHandler类,覆盖自己需要用到的事件处理方法 比实现ContentHander
* 接口要好的多,ContentHander要实现全部的接口方法
*
* 此类作用:将XML内容解析到保存JavaBean对象的List中
*
* @author 忘川
*/
public class SAXContemtHander extends DefaultHandler
{
private String currentTag = null;
private Student student = null;
private List list = new LinkedList();
public List getStudents()
{
return list;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
currentTag = qName;
if ("学生".equals(currentTag))
{
student = new Student();
student.setName(attributes.getValue("姓名"));
student.setStudentId(attributes.getValue("学号"));
student.setAcademy(attributes.getValue("学院"));
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException
{
//技巧:调用常量字符串的equals方法与变量比较可以有效防止由于变量
//等于null从而引发的空指针异常问题
if ("语文".equals(currentTag))
{
student.setChinese(Integer.parseInt(new String(ch, start, length)));
}
if ("数学".equals(currentTag))
{
student.setMath(Integer.parseInt(new String(ch, start, length)));
}
if ("英语".equals(currentTag))
{
student.setEnglish(Integer.parseInt(new String(ch, start, length)));
}
if ("艺术".equals(currentTag))
{
student.setArt(Integer.parseInt(new String(ch, start, length)));
}
if ("计算机".equals(currentTag))
{
student.setComputer(Integer.parseInt(new String(ch, start, length)));
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
if ("学生".equals(qName))
{
list.add(student);
student = null;
}
currentTag = null;
}
}
3. JavaBean模型
package com.liyin.Domain;
/**
*
* @author 忘川
*/
public class Student
{
private String name;
private String studentId;
private String academy;
private int chinese;
private int math;
private int english;
private int art;
private int computer;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getStudentId()
{
return studentId;
}
public void setStudentId(String studentId)
{
this.studentId = studentId;
}
public String getAcademy()
{
return academy;
}
public void setAcademy(String academy)
{
this.academy = academy;
}
public int getChinese()
{
return chinese;
}
public void setChinese(int chinese)
{
this.chinese = chinese;
}
public int getMath()
{
return math;
}
public void setMath(int math)
{
this.math = math;
}
public int getEnglish()
{
return english;
}
public void setEnglish(int english)
{
this.english = english;
}
public int getArt()
{
return art;
}
public void setArt(int art)
{
this.art = art;
}
public int getComputer()
{
return computer;
}
public void setComputer(int computer)
{
this.computer = computer;
}
}
4. Junit测试代码
@Test
public void test() throws ParserConfigurationException, SAXException, IOException
{
//1. 创建解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//2. 得到解析器
SAXParser parser = factory.newSAXParser();
//3. 获取读取器
XMLReader reader = parser.getXMLReader();
//4. 设置事件处理器
SAXContemtHander hander = new SAXContemtHander();
reader.setContentHandler(hander);
//5. 解析XML文档内容
reader.parse("./data/Students_XML.xml");
List list = hander.getStudents();
}