一、定义规则
-
XML数据结构定义
请记住上面的定义,后面我会用“标签开始”、“文本”、“标签结束”表示SAX正在处理哪部分XML数据
-
事件模型
为什么这里我要谈到这个,因为SAX处理XML数据是采用事件的形式来处理,下面我们来简单的做个介绍。
当我们处理XML数据中遇到一个开始标签后SAX会告诉你“我遇到了一个开始标签,这个标签是XXXX”,等你作出反应后,它会继续往下
这时它遇到了一段文本,SAX告诉你“我遇到了一段文本,是XXXX”,然后继续等你作出反应,接着下去就遇到了结束标签,SAX仍然会
告诉你“我到了一个结束标签是XXX”。SAX就是以这样的方式将整个XML数据全部处理完。
二、为何使用
-
节约内存
这里我要声明我的目标设备是手机,而不是电脑等等。而手机的内存是很小的,同时也十分珍贵。或许你会说现在手机都是1GB、
2GB内存,根本不用着想。但是我们既然开发应用,当然是希望使用的人越多越好,而大多数手机设备是没有那么多内存的,所以我们
需要尽量使我们开发的应用能够适合于很多的设备。
-
效率高
手机不仅仅有着内存少的缺点,而且本身的CPU处理能力也是相对较慢的。所以我们要让代码的速度更快更快,否则用户就会感觉
使用你的应用总是卡顿半天,从而会选择其他更优秀的应用。而SAX在执行效率方面也是很客观的,当然这个前提是你的代码够简洁,而
不是把所有逻辑处理任务都放进处理XML数据的方法里面。
三、安卓如何使用
-
DefaultHandler类
这是安卓中内置的用于SAX处理XML的类,但是大多情况下我们都需要继承该类重写部分方法,才能达到处理XML数据的功能。
-
startDocument方法
这是第一个需要重写的方法,每处理一个XML文档都会响应一次。所以这个方法里可以写需要初始化的代码。
-
startElement方法
这是处理每个节点所触发的方法,通过这个方法你可以直接当前处理的节点的名称以及属性。
-
characters方法
当处理一个节点之间的文本时候触发该方法,但是该方法并不会告诉你当前文本的所属标签,而仅仅是告诉你文本内容。
-
endElement方法
遇到一个节点的结束标签时,将会出发这个方法,并且会传递结束标签的名称。
-
endDocument方法
如果当前的XML文档处理完毕后,将会触发该方法,在此方法内你可以将最终的结果保存并且销毁不需要使用的变量。
四、执行流程举例
-
下面我将以下的XML文件为例,说明SAX具体如何处理XML文件。(部分文本因为是中文所以经过了URL编码)
1 <notic> 2 <id>1</id> 3 <title>%3cs%3edsds%3c%2fs%3e</title> 4 <content>%e5%86%85%e5%ae%b91</content> 5 <author>1</author> 6 </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文档的,下面是列举的一个顺序图:
1 <!-- startDocument --> 2 <notic> -> startElement(localName = 'notic') 3 <id> -> startElement(localName = 'id') 4 1 -> characters(ch[] = '1') 5 </id> -> endElement(localName = 'id') 6 <title> -> startElement(localName = 'title') 7 %3c... -> characters(ch[] = '略') 8 </title> -> endElement(localName = 'title') 9 <content> -> startElement(localName = 'content') 10 %e5... -> characters(ch[] = '略') 11 </content> -> endElement(localName = 'content') 12 <author> -> startElement(localName = 'author') 13 1 -> characters(ch[] = '1') 14 </author> -> endElement(localName = 'author') 15 </notic> -> endElement(localName = 'notic') 16 <!-- endDocument -->
五、实例
下面我们采用一个实例来学习如何使用SAX解析XML
-
下面是我们需要解析的XML文档
1 <result> 2 <notic> 3 <id>1</id> 4 <title>%3cs%3edsds%3c%2fs%3e</title> 5 <content>%e5%86%85%e5%ae%b91</content> 6 <author>1</author> 7 <time>2013-11-01 12-00-00</time> 8 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 9 <warn>False</warn> 10 </notic> 11 <notic> 12 <id>2</id> 13 <title>%e6%b5%8b%e8%af%952</title> 14 <content>%e5%86%85%e5%ae%b92</content> 15 <author>2</author> 16 <time>2013-11-02 12-00-00</time> 17 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 18 <warn>True</warn> 19 </notic> 20 <notic> 21 <id>3</id> 22 <title>%e6%b5%8b%e8%af%953</title> 23 <content>%e5%86%85%e5%ae%b93</content> 24 <author>3</author> 25 <time>2013-11-03 12-00-00</time> 26 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 27 <warn>False</warn> 28 </notic> 29 <notic> 30 <id>4</id> 31 <title>%e6%b5%8b%e8%af%954</title> 32 <content>%e5%86%85%e5%ae%b94</content> 33 <author>4</author> 34 <time>2013-11-04 12-00-00</time> 35 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 36 <warn>False</warn> 37 </notic> 38 <notic> 39 <id>5</id> 40 <title>%e6%b5%8b%e8%af%955</title> 41 <content>%e5%86%85%e5%ae%b95</content> 42 <author>5</author> 43 <time>2013-11-05 12-00-00</time> 44 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 45 <warn>False</warn> 46 </notic> 47 <notic> 48 <id>6</id> 49 <title>%e6%b5%8b%e8%af%956</title> 50 <content>%e5%86%85%e5%ae%b96</content> 51 <author>6</author> 52 <time>2013-11-06 12-00-00</time> 53 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 54 <warn>True</warn> 55 </notic> 56 <notic> 57 <id>7</id> 58 <title>%e6%b5%8b%e8%af%956</title> 59 <content>%e5%86%85%e5%ae%b96</content> 60 <author>6</author> 61 <time>2013-11-06 12-00-00</time> 62 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 63 <warn>True</warn> 64 </notic> 65 <notic> 66 <id>8</id> 67 <title>%e6%b5%8b%e8%af%956</title> 68 <content>%e5%86%85%e5%ae%b96</content> 69 <author>6</author> 70 <time>2013-11-06 12-00-00</time> 71 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 72 <warn>True</warn> 73 </notic> 74 <notic> 75 <id>9</id> 76 <title>%e6%b5%8b%e8%af%956</title> 77 <content>%e5%86%85%e5%ae%b96</content> 78 <author>6</author> 79 <time>2013-11-06 12-00-00</time> 80 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 81 <warn>True</warn> 82 </notic> 83 <notic> 84 <id>10</id> 85 <title>%e6%b5%8b%e8%af%956</title> 86 <content>%e5%86%85%e5%ae%b96</content> 87 <author>6</author> 88 <time>2013-11-06 12-00-00</time> 89 <section>%e4%bf%a1%e6%81%af%e5%a4%84</section> 90 <warn>True</warn> 91 </notic> 92 </result>
-
开始继承DefaultHandler类
1 public class SAXForHandler extends DefaultHandler { 2 //用于保存当前处理的节点名称 3 private String preTag; 4 //用于保存当前处理的节点数据 5 private Map<String,String> curMap; 6 //用于保存最终的结果 7 private ArrayList<Map<String,String>> result; 8 9 //重写startDocument 10 public void startDocument() 11 { 12 //初始化 13 result = new ArrayList<Map<String,String>>(); 14 } 15 16 public void startElement(String uri,String localName,String qName,Attributes attributes) 17 { 18 //判断当前节点是notic时表示是一项数据,创建一个新的项 19 if("notic".equals(localName)) 20 { 21 curMap = new HashMap<String,String>(); 22 } 23 //用于保存当前处理的节点名称,用于后面判断用 24 preTag = localName; 25 } 26 27 public void characters(char[] ch,int start,int length) 28 { 29 //从char[]数据转换成String 30 String data = new String(ch,start,length); 31 if("id".equals(preTag)) 32 { 33 //表示当前的文本值是id标签的 34 curMap.put("id",data); 35 }else if("title".equals(preTag)) 36 { 37 //表示当前的文本值是title标签的 38 curMap.put("title",data); 39 }else if("content".equals(preTag)) 40 { 41 //表示当前的文本值是content标签的 42 curMap.put("content",data); 43 } 44 else if("time".equals(preTag)) 45 { 46 //表示当前的文本值是time标签的 47 curMap.put("time",data); 48 }else if("section".equals(preTag)) 49 { 50 //表示当前的文本值是section标签的 51 curMap.put("section",data); 52 }else if("warn",equals(preTag)) 53 { 54 //表示当前的文本值是warn标签的 55 curMap.put("warn",data); 56 } 57 } 58 59 public void endElement(String uri,String localName,String qName) 60 { 61 if("notic".equals(localName)) 62 { 63 //表示一条数据处理完毕 64 result.add(curMap); 65 curMap = null; 66 } 67 //每次处理完一个节点都要将preTag重置 68 preTag = null; 69 } 70 71 public void endDocument() 72 { 73 //XML处理结束,因为没有使用到必须释放的资源所以这里为空 74 } 75 }
-
如何使用该SAXForHandler
1 //in为InputStream表示读取的XML文件流 2 SAXParserFactory spf = SAXParserFactory.newInstance(); 3 SAXParser sp = spf.newSAXParser(); 4 SAXForHandler sfh = new SAXForHandler(); 5 sp.parser(in,sfh); 6 //如果要想获得处理后的结果 7 //可以公开一个方法,用来将result通过return的方法传递给调用者.
六、以下是本人开发的一个工具类,可以方便的通过代码调整SAXForHandler来处理不同的XML
1 package com.ninesoft.newprower.xml; 2 3 import java.io.UnsupportedEncodingException; 4 import java.net.URLDecoder; 5 import java.util.ArrayList; 6 import java.util.HashMap; 7 import java.util.Map; 8 9 import org.xml.sax.Attributes; 10 import org.xml.sax.SAXException; 11 import org.xml.sax.helpers.DefaultHandler; 12 13 public class SaxForXmlHandler extends DefaultHandler { 14 private String[] _needTag; 15 private ArrayList<Map<String,String>> _notics; 16 private Map<String,String> current; 17 private String preTag; 18 private String _nodeTag; 19 20 //构造函数 21 public SaxForXmlHandler(String tag) 22 { 23 this._nodeTag = tag; 24 } 25 public SaxForXmlHandler(String[] need) 26 { 27 this._needTag = need; 28 } 29 public SaxForXmlHandler(String tag,String[] need) 30 { 31 this._nodeTag = tag; 32 this._needTag = need; 33 } 34 35 //获取设置每个节点数据的标签名称 36 public void setNodeTag(String tag) 37 { 38 this._nodeTag = tag; 39 } 40 public String getNodeTag() 41 { 42 return this._nodeTag; 43 } 44 45 //获取设置包含数据的标签名称数组 46 public void setNeedTag(String[] need) 47 { 48 this._needTag = need; 49 } 50 public String[] getNeedTag() 51 { 52 return this._needTag; 53 } 54 55 //获得最终处理后的数据 56 public ArrayList<Map<String,String>> getResult() 57 { 58 return this._notics; 59 } 60 61 //文档开始 62 @Override 63 public void startDocument() throws SAXException { 64 this._notics = new ArrayList<Map<String,String>>(); 65 this.preTag = null; 66 this.current = null; 67 if(this._nodeTag == null){ 68 throw new IllegalArgumentException("节点标签名称未赋值"); 69 }else if(this._needTag == null){ 70 throw new IllegalArgumentException("数据标签数据未赋值"); 71 } 72 super.startDocument(); 73 } 74 75 //节点开头 76 @Override 77 public void startElement(String uri, String localName, String qName, 78 Attributes attributes) throws SAXException { 79 if(_nodeTag.equals(localName)){ 80 //实例化一个Map对象 81 current = new HashMap<String,String>(); 82 } 83 //将当前处理的标签名称保存至preTag中 84 preTag = localName; 85 } 86 87 //节点中的文本 88 @Override 89 public void characters(char[] ch, int start, int length) 90 throws SAXException { 91 //提取标签中的文本 92 String data = new String(ch,start,length); 93 String dedata = ""; 94 for(String item : this._needTag) 95 { 96 if(item.equals(preTag)) 97 { 98 try { 99 //将数据进行URL解码 100 dedata = URLDecoder.decode(data,"UTF-8"); 101 } catch (UnsupportedEncodingException e) { 102 dedata = data; 103 }finally{ 104 //将当前的数据放入map对象中 105 current.put(item, dedata); 106 } 107 return; 108 } 109 } 110 } 111 112 //节点结束 113 @Override 114 public void endElement(String uri, String localName, String qName) 115 throws SAXException { 116 if(this._nodeTag.equals(localName)) 117 { 118 //将当前map对象放入ArrayList对象中 119 this._notics.add(current); 120 current = null; 121 } 122 //将当前标签设置为null 123 preTag = null; 124 } 125 126 //文档结束 127 @Override 128 public void endDocument() throws SAXException { 129 current = null; 130 preTag = null; 131 super.endDocument(); 132 } 133 }
在满足必要的经济的条件下,研究更佳高深的技术.满足自己的野心