一、SAX的概念
在Android平台解析XML主要使用SAX标准。
SAX全称Simple API for XML,既是指一种接口,也是指一个软件包。作为接口,SAX是事件驱动型/XML解析的一个标准接口。
逐行扫描文档,而dom是要先把所有文档先载入进来。缺点:操作不方便,添加删除内容麻烦。
二、SAX基本原理
SAX的工作原理简单的说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知时间处理函数,由时间处理函数做相应动作,然后继续同样的扫描,直至文档结束。
SAX实现都会产生以下类型的事件:
1) 在文档的开始和结束时触发文档处理事件。
2) 在文档内每一个XML元素接受解析的前后触发元素事件。
3) 任何元数据通常都由单独的事件交付。
4) 在处理文档的DTD或Schema是产生DTD或Schema事件。
5) 产生错误时间用来通知主机应用程序解析错误。
SAX解析模型
SAX解析文档过程
<doc> <para>Hello,XML!</para> </doc>
在解析文档的过程中会产生如下一系列事件:
1)创建事件处理程序。
2)创建SAX解析器。
3)将事件处理程序分配给解析器。
4)对文档进行解析,将每个事件发送给处理程序。
三、SAX常用接口
ContentHandler接口是Java类包中的一个特殊的SAX接口,位于org.xml.sax包中。该接口封装了一些对事件处理的方法,当XML解析器开始解析XML输入文档的时候,他会遇到某些特殊的事件,比如文档的开始和结束、元素的开始和结束、以及元素中的字符数据等事件。当遇到这些事件是,XML解析器会调用ContentHandler接口中相应的方法来相应该事件。
ContentHandler接口的方法有以下几种:
void startDocument()
void endDocument()
void startElement(String uri,String localName,String qName,Attributes atts)
void endElement(String uri,String localName,String qName)
void characters(char[] ch,int start,ing length)
四、SAX解析
例子程序很简单,在Tomcat上放入一个xml文件,调用程序下载下来,并解析。
目录结构如下:
test.xml
<?xml version="1.0" encoding="UTF-8"?> <teachers> <teacher id="1"> <name>bauble</name> <sex>男</sex> <subject>数学</subject> </teacher> <teacher id="2"> <name>allorry</name> <sex>男</sex> <subject>英语</subject> </teacher> <teacher id="3"> <name>lily</name> <sex>女</sex> <subject>语文</subject> </teacher> </teachers>
XMLActivity.java
package com.android.activity;
import java.io.StringReader;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.android.utils.HttpDownloader;
public class XMLActivity extends Activity {
private Button parseButton ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
parseButton = (Button)findViewById(R.id.parseButton);
parseButton.setOnClickListener(new ParseButtonListener());
}
class ParseButtonListener implements OnClickListener{
public void onClick(View v) {
HttpDownloader hd = new HttpDownloader();
String resultStr = hd.download("http://1.56.227.150:8080/download/test.xml");
System.out.println(resultStr);
try{
//创建一个SAXParserFactory解析器工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader reader = factory.newSAXParser().getXMLReader();
//为XMLReader设置内容处理器,逐行扫描文件,遇到标签等会触发相应的函数在MyContentHandler中
reader.setContentHandler(new MyContentHandler());
//开始解析文件
reader.parse(new InputSource(new StringReader(resultStr)));
}
catch(Exception e){
e.printStackTrace();
}
}
}
}
MyContentHandler.java
package com.android.activity;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyContentHandler extends DefaultHandler {
String name,sex, subject;
String tagName;
public void startDocument() throws SAXException {
System.out.println("-----------begin-----------");
}
public void endDocument() throws SAXException {
System.out.println("-------------end-----------");
}
/**
* namespaceURI当前正在解析的标签的命名空间,localName没有前缀的值,qName有前缀的值,如c:out
* attributes表示属性,可有多个
*/
public void startElement(String namespaceURI, String localName,
String qName, Attributes attr) throws SAXException {
tagName = localName;
if (localName.equals("teacher")) {
//获取标签的全部属性
for (int i = 0; i < attr.getLength(); i++) {
System.out.println(attr.getLocalName(i) + "=" + attr.getValue(i));
}
}
}
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
//在teacher标签解析完之后,会打印出所有得到的数据
tagName = "";
if (localName.equals("teacher")) {
this.print();
}
}
/**
* 该方法用于得到标签中的内容
* ch:标签中的内容存储到一个char型数组中,start:读取到的数组是从ch中的哪一位开始,length:有多长
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
if (tagName.equals("name")){
name = new String(ch, start, length);
}else if (tagName.equals("sex")){
sex = new String(ch, start, length);
}else if (tagName.equals("subject")){
subject = new String(ch, start, length);
}
}
private void print() {
System.out.print("name: ");
System.out.println(name);
System.out.print("sex: ");
System.out.println(sex);
System.out.print("subject: ");
System.out.println(subject);
System.out.println();
}
}
FileUtils.java
package com.android.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.os.Environment;
public class FileUtils {
private String SDPATH;
public String getSDPATH() {
return SDPATH;
}
public FileUtils() {
//得到当前外部存储设备的目录,得到的目录名/SDCARD
SDPATH = Environment.getExternalStorageDirectory() + "/";
}
/**
* 在SD卡上创建文件
* @throws IOException
*/
public File creatSDFile(String fileName) throws IOException {
File file = new File(SDPATH + fileName);
file.createNewFile();
return file;
}
/**
* 在SD卡上创建目录
* @param dirName
*/
public File creatSDDir(String dirName) {
File dir = new File(SDPATH + dirName);
dir.mkdir();
return dir;
}
/**
* 判断SD卡上的文件夹是否存在
*/
public boolean isFileExist(String fileName){
File file = new File(SDPATH + fileName);
return file.exists();
}
/**
* 将一个InputStream里面的数据写入到SD卡中
*/
public File writeToSDFromInput(String path,String fileName,InputStream input){
File file = null;
OutputStream output = null;
try{
creatSDDir(path);
file = creatSDFile(path + fileName);
output = new FileOutputStream(file);
byte buffer [] = new byte[4 * 1024];
while((input.read(buffer)) != -1){
output.write(buffer);
}
output.flush();
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
output.close();
}
catch(Exception e){
e.printStackTrace();
}
}
return file;
}
}
HttpDownloader.java
package com.android.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpDownloader {
private URL url = null;
/**
* 根据URL下载文件,前提是这个文件当中的内容是文本,函数的返回值就是文件当中的内容
* 1.创建一个URL对象
* 2.通过URL对象,创建一个HttpURLConnection对象
* 3.得到InputStram
* 4.从InputStream当中读取数据
* @param url
* @return
*/
public String download(String fileURL){
StringBuffer stringBuffer = new StringBuffer();
String line = null;
BufferedReader buffer = null;
try{
//创建一个URL对象
url = new URL(fileURL);
//创建一个HTTP连接
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
//使用IO流读取数据
buffer = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
while((line = buffer.readLine()) != null){
stringBuffer.append(line);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
buffer.close();
}catch(Exception e){
e.printStackTrace();
}
}
return stringBuffer.toString();
}
/**
* 可以下载任意文件,返回-1代表下载出错,返回0代表下载成功,返回1代表文件已存在
* 参数为源URL地址、目标路径、文件名
*/
public int downloadFile(String fileURL,String path,String fileName){
InputStream inputStream = null;
try {
FileUtils fileUtils = new FileUtils();
if (fileUtils.isFileExist(path + fileName)) {
return 1;
} else {
url = new URL(fileURL);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
inputStream = urlConnection.getInputStream();
File resultFile = fileUtils.writeToSDFromInput(path,fileName, inputStream);
if (resultFile == null) {
return -1;
}
}
} catch (Exception e) {
e.printStackTrace();
return -1;
} finally {
try {
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return 0;
}
}
运行结果:
程序界面: