SAX解析XML
最近用到了XML数据 ,今天分享一下我对SAX的理解
- 原理
- 实例
- 自定义Handler 继承DefaultHandler
- Handler执行顺序各方法参数讲解
- SaxParse的创建
- 设置解析内容 开始解析
原理
sax 是基于事件驱动。那么什么是事件驱动呢(请自行百度)简单点说 就是触发一个事件 去执行某些操作;
sax在解析XML时 是边读取边解析,不会将整个文档加载到内存中。而是读到一个元素解析一个元素,和上下的元素是关联不上的,占用内存较小。这也是非常适合Android这种内存较小的嵌入式设备内存的原因;
sax在读取文档的时候激活一系列的事件并执行一些操作。
在开始读取文档的时候触发 startDocument() ;
读取到一个元素触发 startElement();
读取文本 触发characters(); ps:即使是读取到换行符也会触发
元素读取完毕 触发 endElement();
读取完整个文档触发 endDocument();
上述事件 基本就把xml文档读取完毕了,这些方法在DefaultHandle中已经封装好了,我们做的就是重写这些方法就可以了
贴代码
student XML文件
<?xml version="1.0" encoding="utf-8"?>
<Students>
<Student id="0">
<name>张三</name>
<clazz>13班</clazz>
<age>17</age>
</Student>
</Students>
创建 StudentHandler 继承自 DefaultHandler
package com.skymxc.demo.parsexml;
import android.text.TextUtils;
import android.util.Log;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
/**
* Created by sky-mxc
*/
public class StudentHandler extends DefaultHandler {
private List<Student> students;
private Student student;
private String tag; //记录读取到的元素的名字
@Override
public void startDocument() throws SAXException {
Log.e("Tag","=======startDocument()========");
students = new ArrayList<>();
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
Log.e("Tag","=======endDocument()========");
}
/**
*
* @param uri 明明空间的uri
* @param localName 不带前缀的元素名字
* @param qName 带有前缀的元素名
* @param attributes 属性
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
Log.e("Tag","==========startElement()==========="+localName);
Log.e("Tag","===startElement():uri======"+uri);
Log.e("Tag","===startElement():localName======"+localName);
Log.e("Tag","===startElement():qName======"+qName);
switch (localName){
case "Student": //student元素
student = new Student();
int id = Integer.parseInt(attributes.getValue("id")); //获取到属性id的值
student.setId(id);
break;
default:
tag=localName;//除了 student元素 其他元素都要读取文本 characters()无法获取元素名字
break;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
Log.e("Tag","==========endElement()==========="+localName);
switch (localName){
case "Student":
students.add(student);
break;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
Log.e("Tag","==========characters()===========");
Log.e("Tag","======start:"+start);
Log.e("Tag","======length:"+length);
//将字符转为字符串
String text = new String(ch,start,length).trim();
Log.e("Tag","====当前元素:"+tag+"===文本值:"+text);
//排除无效字符 会读取到一些换行符
if (TextUtils.isEmpty(text)) return;
if (student == null) return;
switch (tag){
case "name":
student.setName(text);
break;
case "age":
int age = Integer.parseInt(text);
student.setAge(age);
break;
case "clazz":
student.setClazz(text);
break;
}
}
public List<Student> getStudents() {
return students;
}
}
Handler中的执行过程解析 读取过程如下,可以看出 就算根节点没有文本也触发了characters() 因为会读取换行符 所以慎重处理
E/Tag: =======startDocument()========
E/Tag: ==========startElement()===========Students
E/Tag: ==========characters()===========
E/Tag: ==========characters()===========
E/Tag: ==========startElement()===========Student
E/Tag: ==========characters()===========
E/Tag: ==========characters()===========
E/Tag: ==========startElement()===========name
E/Tag: ==========characters()===========
E/Tag: ==========endElement()===========name
E/Tag: ==========characters()===========
E/Tag: ==========characters()===========
E/Tag: ==========startElement()===========clazz
E/Tag: ==========characters()===========
E/Tag: ==========endElement()===========clazz
E/Tag: ==========characters()===========
E/Tag: ==========characters()===========
E/Tag: ==========startElement()===========age
E/Tag: ==========characters()===========
E/Tag: ==========endElement()===========age
E/Tag: ==========characters()===========
E/Tag: ==========characters()===========
E/Tag: ==========endElement()===========Student
E/Tag: ==========characters()===========
E/Tag: ==========endElement()===========Students
E/Tag: =======endDocument()========
startElement() 参数如下 xml 文件中并没有定义 命名空间 和任何前缀
uri :为空
qName :也是元素的名字并没有带有前缀
localName: 当前元素的名字
E/Tag: ===startElement():uri======
E/Tag: ===startElement():localName======Student
E/Tag: ===startElement():qName======Student
E/Tag: ==========characters()===========
characters()参数如下
start :开始下标
length :长度
E/Tag: ==========characters()===========
E/Tag: ======start:0
E/Tag: ======length:3
E/Tag: ====当前元素:clazz===文本值:13班
创建SAXParse 设置解析内容
SAXParserFactory factory = SAXParserFactory.newInstance();
StudentHandler handler = new StudentHandler();
try {
SAXParser parser = factory.newSAXParser();
parser.parse(getAssets().open("students.xml"),handler);
Log.e("Tag","===Size:"+handler.getStudents().size());
for (Student stu :handler.getStudents()){
Log.e("Tag","==Name:"+stu.getName()+"===Age:"+stu.getAge()+"====Clazz:"+stu.getClazz()+"==id:"+stu.getId());
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
读取结果
E/Tag: ==Name:张三===Age:17====Clazz:13班==id:0
对于SAX的理解就这些了
为什么只有深夜 才有感觉呢,唉…..发愁github地址 :https://github.com/sky-mxc/AndroidDemo/tree/master/parsexml