一、定义规则

  1. XML数据结构定义


    请记住上面的定义,后面我会用“标签开始”、“文本”、“标签结束”表示SAX正在处理哪部分XML数据

  2. 事件模型

    为什么这里我要谈到这个,因为SAX处理XML数据是采用事件的形式来处理,下面我们来简单的做个介绍。

    当我们处理XML数据中遇到一个开始标签后SAX会告诉你“我遇到了一个开始标签,这个标签是XXXX”,等你作出反应后,它会继续往下
    这时它遇到了一段文本,SAX告诉你“我遇到了一段文本,是XXXX”,然后继续等你作出反应,接着下去就遇到了结束标签,SAX仍然会
    告诉你“我到了一个结束标签是XXX”。SAX就是以这样的方式将整个XML数据全部处理完。

二、为何使用

  1. 节约内存

    这里我要声明我的目标设备是手机,而不是电脑等等。而手机的内存是很小的,同时也十分珍贵。或许你会说现在手机都是1GB、
    2GB内存,根本不用着想。但是我们既然开发应用,当然是希望使用的人越多越好,而大多数手机设备是没有那么多内存的,所以我们
    需要尽量使我们开发的应用能够适合于很多的设备。

  2. 效率高

    手机不仅仅有着内存少的缺点,而且本身的CPU处理能力也是相对较慢的。所以我们要让代码的速度更快更快,否则用户就会感觉
    使用你的应用总是卡顿半天,从而会选择其他更优秀的应用。而SAX在执行效率方面也是很客观的,当然这个前提是你的代码够简洁,而
    不是把所有逻辑处理任务都放进处理XML数据的方法里面。

三、安卓如何使用

  1. DefaultHandler类

    这是安卓中内置的用于SAX处理XML的类,但是大多情况下我们都需要继承该类重写部分方法,才能达到处理XML数据的功能。

  2. startDocument方法

    这是第一个需要重写的方法,每处理一个XML文档都会响应一次。所以这个方法里可以写需要初始化的代码。

  3. startElement方法

    这是处理每个节点所触发的方法,通过这个方法你可以直接当前处理的节点的名称以及属性。

  4. characters方法

    当处理一个节点之间的文本时候触发该方法,但是该方法并不会告诉你当前文本的所属标签,而仅仅是告诉你文本内容。

  5. endElement方法

    遇到一个节点的结束标签时,将会出发这个方法,并且会传递结束标签的名称。

  6. endDocument方法

    如果当前的XML文档处理完毕后,将会触发该方法,在此方法内你可以将最终的结果保存并且销毁不需要使用的变量。

四、执行流程举例

  1. 下面我将以下的XML文件为例,说明SAX具体如何处理XML文件。(部分文本因为是中文所以经过了URL编码)

 <notic>
<id>1</id>
<title>%3cs%3edsds%3c%2fs%3e</title>
4 <content>%e5%86%85%e5%ae%b91</content>
<author>1</author>
</notic>

2. 下面是具体的响应过程

方法名称 localName(标签名称) ch[](文本名称)
 startDocument  -- --
 startElement notic --
 startElement id --
 characters -- 1
 endElement id --
 startElement title --
 characters -- %3cs%3edsds%2c%2fs%3e
 endElement title --
 startElement content --
 characters -- %e5%86%85%e5%ae%b91
 endElement content --
 startElement author --
 characters -- 1
 endElement author --
 endElement notic --
 endDocument -- --
 

3.通过上面的分析我们可以清楚的看到,它是如何处理XML文档的,下面是列举的一个顺序图:

 <!-- startDocument -->
<notic> -> startElement(localName = 'notic')
<id> -> startElement(localName = 'id')
1 -> characters(ch[] = '1')
</id> -> endElement(localName = 'id')
<title> -> startElement(localName = 'title')
%3c... -> characters(ch[] = '略')
</title> -> endElement(localName = 'title')
<content> -> startElement(localName = 'content')
%e5... -> characters(ch[] = '略')
</content> -> endElement(localName = 'content')
<author> -> startElement(localName = 'author')
1 -> characters(ch[] = '1')
</author> -> endElement(localName = 'author')
</notic> -> endElement(localName = 'notic')
<!-- endDocument -->

五、实例

 下面我们采用一个实例来学习如何使用SAX解析XML

  1. 下面是我们需要解析的XML文档

     <result>
    <notic>
    <id>1</id>
    <title>%3cs%3edsds%3c%2fs%3e</title>
    <content>%e5%86%85%e5%ae%b91</content>
    <author>1</author>
    <time>2013-11-01 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>False</warn>
    </notic>
    <notic>
    <id>2</id>
    <title>%e6%b5%8b%e8%af%952</title>
    <content>%e5%86%85%e5%ae%b92</content>
    <author>2</author>
    <time>2013-11-02 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>True</warn>
    </notic>
    <notic>
    <id>3</id>
    <title>%e6%b5%8b%e8%af%953</title>
    <content>%e5%86%85%e5%ae%b93</content>
    <author>3</author>
    <time>2013-11-03 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>False</warn>
    </notic>
    <notic>
    <id>4</id>
    <title>%e6%b5%8b%e8%af%954</title>
    <content>%e5%86%85%e5%ae%b94</content>
    <author>4</author>
    <time>2013-11-04 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>False</warn>
    </notic>
    <notic>
    <id>5</id>
    <title>%e6%b5%8b%e8%af%955</title>
    <content>%e5%86%85%e5%ae%b95</content>
    <author>5</author>
    <time>2013-11-05 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>False</warn>
    </notic>
    <notic>
    <id>6</id>
    <title>%e6%b5%8b%e8%af%956</title>
    <content>%e5%86%85%e5%ae%b96</content>
    <author>6</author>
    <time>2013-11-06 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>True</warn>
    </notic>
    <notic>
    <id>7</id>
    <title>%e6%b5%8b%e8%af%956</title>
    <content>%e5%86%85%e5%ae%b96</content>
    <author>6</author>
    <time>2013-11-06 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>True</warn>
    </notic>
    <notic>
    <id>8</id>
    <title>%e6%b5%8b%e8%af%956</title>
    <content>%e5%86%85%e5%ae%b96</content>
    <author>6</author>
    <time>2013-11-06 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>True</warn>
    </notic>
    <notic>
    <id>9</id>
    <title>%e6%b5%8b%e8%af%956</title>
    <content>%e5%86%85%e5%ae%b96</content>
    <author>6</author>
    <time>2013-11-06 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>True</warn>
    </notic>
    <notic>
    <id>10</id>
    <title>%e6%b5%8b%e8%af%956</title>
    <content>%e5%86%85%e5%ae%b96</content>
    <author>6</author>
    <time>2013-11-06 12-00-00</time>
    <section>%e4%bf%a1%e6%81%af%e5%a4%84</section>
    <warn>True</warn>
    </notic>
    </result>
  2. 开始继承DefaultHandler类

     public class SAXForHandler extends DefaultHandler {
    //用于保存当前处理的节点名称
    private String preTag;
    //用于保存当前处理的节点数据
    private Map<String,String> curMap;
    //用于保存最终的结果
    private ArrayList<Map<String,String>> result; //重写startDocument
    public void startDocument()
    {
    //初始化
    result = new ArrayList<Map<String,String>>();
    } public void startElement(String uri,String localName,String qName,Attributes attributes)
    {
    //判断当前节点是notic时表示是一项数据,创建一个新的项
    if("notic".equals(localName))
    {
    curMap = new HashMap<String,String>();
    }
    //用于保存当前处理的节点名称,用于后面判断用
    preTag = localName;
    } public void characters(char[] ch,int start,int length)
    {
    //从char[]数据转换成String
    String data = new String(ch,start,length);
    if("id".equals(preTag))
    {
    //表示当前的文本值是id标签的
    curMap.put("id",data);
    }else if("title".equals(preTag))
    {
    //表示当前的文本值是title标签的
    curMap.put("title",data);
    }else if("content".equals(preTag))
    {
    //表示当前的文本值是content标签的
    curMap.put("content",data);
    }
    else if("time".equals(preTag))
    {
    //表示当前的文本值是time标签的
    curMap.put("time",data);
    }else if("section".equals(preTag))
    {
    //表示当前的文本值是section标签的
    curMap.put("section",data);
    }else if("warn",equals(preTag))
    {
    //表示当前的文本值是warn标签的
    curMap.put("warn",data);
    }
    } public void endElement(String uri,String localName,String qName)
    {
    if("notic".equals(localName))
    {
    //表示一条数据处理完毕
    result.add(curMap);
    curMap = null;
    }
    //每次处理完一个节点都要将preTag重置
    preTag = null;
    } public void endDocument()
    {
    //XML处理结束,因为没有使用到必须释放的资源所以这里为空
    }
    }
  3. 如何使用该SAXForHandler

     //in为InputStream表示读取的XML文件流
    SAXParserFactory spf = SAXParserFactory.newInstance();
    SAXParser sp = spf.newSAXParser();
    SAXForHandler sfh = new SAXForHandler();
    sp.parser(in,sfh);
    //如果要想获得处理后的结果
    //可以公开一个方法,用来将result通过return的方法传递给调用者.

六、以下是本人开发的一个工具类,可以方便的通过代码调整SAXForHandler来处理不同的XML

 package com.ninesoft.newprower.xml;

 import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map; import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; public class SaxForXmlHandler extends DefaultHandler {
private String[] _needTag;
private ArrayList<Map<String,String>> _notics;
private Map<String,String> current;
private String preTag;
private String _nodeTag; //构造函数
public SaxForXmlHandler(String tag)
{
this._nodeTag = tag;
}
public SaxForXmlHandler(String[] need)
{
this._needTag = need;
}
public SaxForXmlHandler(String tag,String[] need)
{
this._nodeTag = tag;
this._needTag = need;
} //获取设置每个节点数据的标签名称
public void setNodeTag(String tag)
{
this._nodeTag = tag;
}
public String getNodeTag()
{
return this._nodeTag;
} //获取设置包含数据的标签名称数组
public void setNeedTag(String[] need)
{
this._needTag = need;
}
public String[] getNeedTag()
{
return this._needTag;
} //获得最终处理后的数据
public ArrayList<Map<String,String>> getResult()
{
return this._notics;
} //文档开始
@Override
public void startDocument() throws SAXException {
this._notics = new ArrayList<Map<String,String>>();
this.preTag = null;
this.current = null;
if(this._nodeTag == null){
throw new IllegalArgumentException("节点标签名称未赋值");
}else if(this._needTag == null){
throw new IllegalArgumentException("数据标签数据未赋值");
}
super.startDocument();
} //节点开头
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(_nodeTag.equals(localName)){
//实例化一个Map对象
current = new HashMap<String,String>();
}
//将当前处理的标签名称保存至preTag中
preTag = localName;
} //节点中的文本
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//提取标签中的文本
String data = new String(ch,start,length);
String dedata = "";
for(String item : this._needTag)
{
if(item.equals(preTag))
{
try {
//将数据进行URL解码
dedata = URLDecoder.decode(data,"UTF-8");
} catch (UnsupportedEncodingException e) {
dedata = data;
}finally{
//将当前的数据放入map对象中
current.put(item, dedata);
}
return;
}
}
} //节点结束
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if(this._nodeTag.equals(localName))
{
//将当前map对象放入ArrayList对象中
this._notics.add(current);
current = null;
}
//将当前标签设置为null
preTag = null;
} //文档结束
@Override
public void endDocument() throws SAXException {
current = null;
preTag = null;
super.endDocument();
}
}

Android开发之使用DefaultHandler处理XML数据的更多相关文章

  1. android开发中的5种存储数据方式

    数据存储在开发中是使用最频繁的,根据不同的情况选择不同的存储数据方式对于提高开发效率很有帮助.下面笔者在主要介绍Android平台中实现数据存储的5种方式. 1.使用SharedPreferences ...

  2. Android开发学习---使用XmlPullParser解析xml文件

    Android中解析XML的方式主要有三种:sax,dom和pull关于其内容可参考:http://blog.csdn.net/liuhe688/article/details/6415593 本文将 ...

  3. 【Android Developers Training】 81. 解析XML数据

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. android开发(26) 和其他应用交换数据方式一,使用intent指定自定义action调用其他程序里的activity,并获得其返回的结果

    我们在开发中会遇到和其他应用的交互情形,下面是一个简单的方式.整个的使用类似“使用intent调用系统自带的拍照应用并获得结果”. 先看页面:     我们看看实现步骤. 第一个应用 DEMO1: 1 ...

  5. Android开发(二十四)——数据存储SharePreference、SQLite、File、ContentProvider

    Android提供以下四种存储方式: SharePreference SQLite File ContentProvider Android系统中数据基本都是私有的,一般存放在“data/data/程 ...

  6. Android开发笔记:SQLite导入导出数据

    SQLite是Android中最方便使用的数据库了,现在看下如何快速的在SQLite中导入导出数据. 首先由于是.NET项目转Android,原有数据库使用的是SQLSERVER,由于项目相同部分结构 ...

  7. android开发中难免遇到listview刷新数据出现异常

    异常:java.lang.IllegalStateException: The content of the adapter has changed but ListView did not rece ...

  8. android开发中 解决服务器端解析MySql数据时中文显示乱码的情况

    首先,还是确认自己MySql账户和密码 1.示例  账户:root   密码:123456   有三个字段   分别是_id  .username(插入有中文数据).password 1)首先我们知道 ...

  9. 【Bugly 技术干货】Android开发必备知识:为什么说Kotlin值得一试

    1.Hello, Kotlin Bugly 技术干货系列内容主要涉及移动开发方向,是由 Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 1. ...

随机推荐

  1. [Linux] ubuntu各目录含义

    /boot/: 启动文件,所有与系统启动有关的文件都保存在这里 /boot/grub/:grub引导器相关的配置文件都在这里 /dev/:此目录中保存了所有设备文件,例如,使用的分区:/dev/hda ...

  2. Javascript 对象(object)合并

    对象的合并 需求:设有对象 o1 ,o2,需要得到对象 o3 var o1 = { a:'a' }, o2 = { b:'b' }; // 则 var o3 = { a:'a', b:'b' } 方法 ...

  3. 深入理解多线程(二)—— Java的对象模型

    上一篇文章中简单介绍过synchronized关键字的方式,其中,同步代码块使用monitorenter和monitorexit两个指令实现,同步方法使用ACC_SYNCHRONIZED标记符实现.后 ...

  4. [转]PHP之APC缓存详细介绍(学习整理)

    From : http://www.2cto.com/kf/201210/160140.html 1.APC缓存简介APC,全称是Alternative PHP Cache,官方翻译叫”可选PHP缓存 ...

  5. codevs 2190 有理逼近

    2190 有理逼近  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 黄金 Gold   题目描述 Description 对于一个素数P,我们可以用一系列有理分数(分子.分母都是 ...

  6. storm的一些相关文章

    文章可以看这些: https://www.cnblogs.com/zhaojiankai/p/7257617.html https://blog.csdn.net/wangshuminjava/art ...

  7. 25个可遇不可求的jQuery插件

    随着jQuery插件在网站建设过程中的使用率不断的增加,所以有必要跟进时代步伐开发出一些新的插件/代码片段,以此来巩固并提高前端用户体验,将用户体验提升到一个新的高度. 接下来所推荐的这些插件中有滑块 ...

  8. MFC/Windows API 使用过的函数(持续更新)

    /*******************使用默认画笔对象**************************** // //绘制矩形 pDC->MoveTo(50, 50); //返回值是一个指 ...

  9. SciPy 安装不上?

    参考:链接:https://www.zhihu.com/question/30188492/answer/150928275来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处 ...

  10. 协程(Coroutine)并不是真正的多线程

    自:http://www.zhihu.com/question/23895384 说到Coroutine,我们必须提到两个更远的东西.在操作系统(os)级别,有进程(process)和线程(threa ...