SAX解析XML文件
前言:在进入正题之前,我觉得很有必要让大家回顾一下最常用的XML文件解析的两种方式:SAX解析 和 DOC解析
1. SAX解析 (Simple API for XML)
定义:SAX是Simple API for XML的缩写,它是事件驱动的,它并不需要读入整个文档,而文档的读入过程也就是SAX的解析过程。所谓事件驱动,是指一种基于回调(callback)机制的程序运行方法。
优点:1. 解析可以立即开始,解析速度快,数据量大的xml建议使用SAX解析提高解析速度。
2. 占用内存小,没有内存压力
缺点:不能对结点做修改
适用:读取XML文件
总结:我个人理解SAX解析就是一种懒解析,类似于懒加载机制一样。
2. DOC解析 (Document Object Model)
定义:DOM将XML文档作为一个树形结构,而树叶被定义为为节点。根据DOM,XML文档中的每个成分都是一个节点
优点:把XML文件在内存中构建属性结构,可以遍历和修改节点。
缺点:如果文件比较大,内存有压力,解析的时间会比较长。
适用:修改XML数据
总结:DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)
3. SAX解析和DOC解析的区别
- SAX解析速度快,占用内存资源小,可以快速读取XML文件,多适用于文件比较大的XML
- DOC解析速度慢,占用内存资源大,可以修改XML文件数据,多适用于文件比较小的XML
以上概念借用了其他大佬的博客总结出来的,为了让大家进一步加深对这两种解析器的理解。
4. SAX解析XML文件方式
SAX解析XML文件主要分为四大步骤,接下来让我们一起看下大致的解析过程吧!
- 得到xml文件对应的资源,可以是xml的输入流,文件或uri
- 得到SAX解析工厂(SAXParserFactory)
- 由解析工厂生产一个SAX解析器(SAXParser)
- 传入输入流和handler给解析器,调用parse()方法解析
@Test
public void testSaxParser()throws Exception{
//1.得到xml文件对应的资源,可以是xml的输入流,文件和uri
Resource resource = new ClassPathResource("student.xml");
InputStream inputStream = resource.getInputStream();
//2.得到SAX解析工厂(SAXParserFactory)
SAXParserFactory saxparserFactory = SAXParserFactory.newInstance();
//3.由解析工厂生产一个SAX解析器(SAXParser)
SAXParser saxparser = saxparserFactory.newSAXParser();
//4.传入输入流和handler给解析器,调用parse()解析
saxparser.parse(inputStream, new XmlParseHandler());
}
1). student.xml文件代码清单
<root>
<student id="1">
<name>张三</name>
<sex>男</sex>
<age>18</age>
</student>
<student id="2">
<name>李四</name>
<sex>女</sex>
<age>18</age>
</student>
</root>
2). Student代码清单
public class Student {
private int id;
private String name;
private String sex;
private int age;
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 getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
3). XmlParseHandler.java代码清单
public class XmlParseHandler extends DefaultHandler {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 记录当前解析到的节点名称
*/
private String currentTag;
/**
* 定义存储Student对象的集合
*/
List<Student> listStu;
/**
* 定义student对象
*/
private Student student;
/**
* 文档解析结束后调用
*/
@Override
public void endDocument() throws SAXException {
listStu.forEach(e -> {
logger.info(e.toString());
});
logger.info("文档解析结束...");
}
/**
* 节点解析结束后调用
*
* @param uri : 命名空间的uri
* @param localName : 标签的名称
* @param qName : 带命名空间的标签名称
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
logger.info("节点解析结束...");
if (qName.equals("student")) {
this.listStu.add(this.student);
}
this.currentTag = null;
}
/**
* 文档解析开始调用
*/
@Override
public void startDocument() throws SAXException {
logger.info("文档开始解析...");
listStu = new ArrayList<>(10);
}
/**
* 节点解析开始调用
*
* @param uri : 命名空间的uri
* @param localName : 标签的名称
* @param qName : 带命名空间的标签名称
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
logger.info("节点开始解析...");
if (qName.equals("student")) {
student = new Student();
student.setId(Integer.parseInt(attributes.getValue(0)));
}
// 把当前标签记录下来
this.currentTag = qName;
}
/**
* 获取标签元素内容
* @param ch:标签元素内容
* @param start:从第几个开始获取
* @param length:字符长度
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
logger.info("开始获取标签内容...");
String tagName = this.currentTag;
if (tagName != "" && tagName != null && tagName.length() > 0) {
//date为解析后得到的数据
String date = new String(ch, start, length);
//给student对象赋值
setStudent(tagName, date);
}
}
/**
* 给student对象赋值
* @param tagName:标签名
* @param date:解析后的数据
*/
public void setStudent(String tagName, String date) {
switch (tagName) {
case "name":
this.student.setName(date);
break;
case "sex":
this.student.setSex(date);
break;
case "age":
this.student.setAge(Integer.parseInt(date));
break;
default:
break;
}
}
}
本篇的核心类是XmlParseHandler,继承了DefaultHandler,重写了里面的核心方法。到这里SAX解析XML文件的基本流程就已经结束了, 感谢大家的阅读和支持!!!
上一篇: jQuery UI 1.7发布
下一篇: SAX解析XML文件