一、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解析模型
<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; } }
运行结果:
程序界面: