本帖最后由 JenMinZhang 于 2012-11-6 13:47 编辑
1. SAX解析XML简单介绍 :SAX是 Simple API for XML(XML 简单应用程序接口),是一个公共的基于事件的XML文档解析标准。它以事件作为解析XML 文件的模式, 将 XML 文件转化成一系列的事件,由不同的事件处理器来决定如何处理。
SAX是一个解析速度快并且占用内存少的xml解析器,非常适合android等移动设备,SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读取到的字符是否合法xml语法中的某部分,如果符合就会触发事件。
解析流程:
2.使用SAX解析网络XML:
(1)准备工作:
寻找要解析的XML文件网络路径,可以使用网络路径为:
http://www.w3school.com.cn/example/xmle/plant_catalog.xml
(2)XML文件对应Model:
(3)助手类代码:
a.引入包 :
b.助手类代码:
(4)权限配置 ,AndroidManifest.xml 配置权限代码:
(5)解析测试:
3.应注意问题:
1)如果要解析网络XML文件,就需要在在AndroidManifest.xml 配置权限,代码为:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
如果不加权限代码会出现:
XML文法正常解析,使用LogCat可以再告警(W)中看到 Permission denied (没有权限;拒绝访问
)异常信息
2)如果XML文件放置在本地服务器(自己的PC机,XMl运行在其他环节中,如 JAVA ,PHP),在访问是需要设置静态IP地址,访问是使用静态IP地址访问:
如: http://192.85.1.235/mms/index.php?controller=default
如果直接使用 http://localhost/mms/index.php?controller=default 就会报:Connection refused(连接拒绝)
3)如果使用助手类解析XML,在根据XML标签生成对应Model(实体)时,应注意,Model实体名称必须和目标根目录名称忽略大小后保持一致生成实体所定义的属性名称必须和XML目标标签下的属性标签名称保持一致:
<?xml version="1.0" encoding="UTF-8" ?>
<CATALOG>
<PLANT>
<COMMON>Bloodroot</COMMON>
<BOTANICAL>Sanguinaria canadensis</BOTANICAL>
<ZONE>4</ZONE>
<LIGHT>Mostly Shady</LIGHT>
<PRICE>$2.44</PRICE>
<AVAILABILITY>031599</AVAILABILITY>
</PLANT>
</CATALOG>
对应Model实体类名称应该为: Plant ,不然的话解析过程中不会报异常,只是解析结果为空,因为解析方法通过传递参数Model对象实例找到对应的Model类名称,并使用它调getClass().getDeclaredFields()获取实体中定义的属性(XML目标标签下的属性标签,如 name ,price ,description);
如果实体所定义的属性名称必须和XML目标标签下的属性标签名称保持不一样,就无法把XML标签内容赋值给对应实体的属性,对应实体属性解析结果为null ;
1. SAX解析XML简单介绍 :SAX是 Simple API for XML(XML 简单应用程序接口),是一个公共的基于事件的XML文档解析标准。它以事件作为解析XML 文件的模式, 将 XML 文件转化成一系列的事件,由不同的事件处理器来决定如何处理。
SAX是一个解析速度快并且占用内存少的xml解析器,非常适合android等移动设备,SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读取到的字符是否合法xml语法中的某部分,如果符合就会触发事件。
解析流程:

2.使用SAX解析网络XML:
(1)准备工作:
寻找要解析的XML文件网络路径,可以使用网络路径为:
http://www.w3school.com.cn/example/xmle/plant_catalog.xml
(2)XML文件对应Model:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
import
java.io.Serializable;
public
class
Plant
implements
Serializable {
/**
*
*/
private
static
final
long
serialVersionUID = 1L;
private
String common=
""
;
private
String botanical=
""
;
private
String zone=
""
;
private
String price=
""
;
private
String availability=
""
;
public
String getCommon() {
return
common;
}
public
void
setCommon(String common) {
this
.common = common;
}
public
String getBotanical() {
return
botanical;
}
public
void
setBotanical(String botanical) {
this
.botanical = botanical;
}
public
String getZone() {
return
zone;
}
public
void
setZone(String zone) {
this
.zone = zone;
}
public
String getPrice() {
return
price;
}
public
void
setPrice(String price) {
this
.price = price;
}
public
String getAvailability() {
return
availability;
}
public
void
setAvailability(String availability) {
this
.availability = availability;
}
}
|
(3)助手类代码:
a.引入包 :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
import
java.io.InputStream;
import
java.lang.reflect.Field;
import
java.lang.reflect.Method;
import
java.net.HttpURLConnection;
import
java.net.URL;
import
java.sql.Date;
import
java.text.SimpleDateFormat;
import
java.util.ArrayList;
import
java.util.List;
import
javax.xml.parsers.SAXParser;
import
javax.xml.parsers.SAXParserFactory;
import
org.xml.sax.Attributes;
import
org.xml.sax.SAXException;
import
org.xml.sax.helpers.DefaultHandler;
|
b.助手类代码:
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
/**
* 助手类 传递一个网络XML地址和一个对象实体类实例对象即可解析XML内容
*
* @author JenMinZhang
*/
public
class
SAXParserContentHandler
extends
DefaultHandler {
private
Object javaBean =
null
;
private
String tag;
// 标签名称
List<Object> list =
null
;
/**
* 用 SAX 解析xml文件
*
* @param strUrl
* 网络xml地址
* @param javaBean
* 实体类对象
* @return List 返回实体类的一个list集合
* @throws Exception
*/
public
List<Object> parseReadXml(String strUrl, Object javaBean)
throws
Exception {
this
.javaBean = javaBean;
// 要从网络上获取xml,要定义一个URL类对象
URL url =
new
URL(strUrl);
// 打开连接,。会返回HttpsURLConnection 对象
HttpURLConnection httpsURLConnection = (HttpURLConnection) url
.openConnection();
// 现在是使用HTTP协议请求服务器的数据
// 所以要设置请求方式
httpsURLConnection.setRequestMethod(
"GET"
);
// 设置 超时时间 为5秒
httpsURLConnection.setConnectTimeout(
5
*
1000
);
// 通过输入流获取网络xml内容
// 取得输入流
InputStream inputStream = httpsURLConnection.getInputStream();
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
// 取得SAXParser 实例
SAXParser parser = parserFactory.newSAXParser();
parser.parse(inputStream,
this
);
return
list;
}
@Override
public
void
characters(
char
[] ch,
int
start,
int
length)
throws
SAXException {
if
(
null
!= tag && !
""
.equals(tag)) {
if
(javaBean !=
null
) {
String data =
new
String(ch, start, length);
Field[] fields = javaBean.getClass().getDeclaredFields();
for
(
int
i =
0
; i < fields.length; i++) {
if
(tag.equalsIgnoreCase(fields[i].getName())) {
setAttribute(javaBean, fields[i].getName(), data,
new
Class[] { fields[i].getType() });
}
}
}
}
}
@Override
public
void
endDocument()
throws
SAXException {
}
@Override
public
void
endElement(String uri, String localName, String qName)
throws
SAXException {
if
(
null
!= localName && !
""
.equals(localName)) {
String bean = updateSmall(javaBean.getClass().getSimpleName());
if
(bean.equalsIgnoreCase(localName) && bean !=
null
) {
list.add(javaBean);
}
}
tag =
null
;
}
@Override
public
void
startDocument()
throws
SAXException {
// TODO Auto-generated method stub
list =
new
ArrayList<Object>();
}
@Override
public
void
startElement(String uri, String localName, String qName,
Attributes attributes)
throws
SAXException {
tag = qName;
// 取得实体类简单名称,把首字母变为小 写
String bean = updateSmall(javaBean.getClass().getSimpleName());
// 取得实体类的 全限 名称
String clazz = javaBean.getClass().getName();
if
(bean.equalsIgnoreCase(qName)) {
try
{
javaBean = Class.forName(clazz).newInstance();
}
catch
(Exception e) {
e.printStackTrace();
}
Field[] fields = javaBean.getClass().getDeclaredFields();
for
(
int
i =
0
; i < attributes.getLength(); i++) {
for
(
int
j =
0
; j < fields.length; j++) {
if
(attributes.getQName(i).equalsIgnoreCase(fields[j].getName())) {
setAttribute(javaBean, attributes.getQName(i),
attributes.getValue(i),
new
Class[] { fields[j].getType() });
}
}
}
}
}
/**
* @param object
* 类
* @param setName
* 方法名
* @param setValue方法设置
* @param obj
* 属性类型
* @throws Exception
*/
public
void
setAttribute(Object object, String setName,
String setValue, Class[] obj) {
Method method;
try
{
method = object.getClass().getMethod(
"set"
+ updateStr(setName), obj[
0
]);
if
(obj[
0
].equals(Integer.
class
) || obj[
0
].equals(
int
.
class
)) {
method.invoke(object,
new
Integer(setValue));
}
if
(obj[
0
].equals(Float.
class
) || obj[
0
].equals(
float
.
class
)) {
method.invoke(object,
new
Float(setValue));
}
if
(obj[
0
].equals(Short.
class
) || obj[
0
].equals(
short
.
class
)) {
method.invoke(object,
new
Short(setValue));
}
if
(obj[
0
].equals(Byte.
class
) || obj[
0
].equals(
byte
.
class
)) {
method.invoke(object,
new
Byte(setValue));
}
if
(obj[
0
].equals(Double.
class
) || obj[
0
].equals(
double
.
class
)) {
method.invoke(object,
new
Double(setValue));
}
if
(obj[
0
].equals(Date.
class
)) {
method.invoke(object,
new
Date(
new
Long(setValue)));
}
if
(obj[
0
].equals(java.util.Date.
class
)) {
method.invoke(object,
new
java.util.Date(setValue));
}
if
(obj[
0
].equals(Long.
class
) || obj[
0
].equals(
long
.
class
)) {
method.invoke(object,
new
Long(setValue));
}
if
(obj[
0
].equals(Boolean.
class
)
|| obj[
0
].equals(
boolean
.
class
)) {
method.invoke(object,
new
Boolean(setValue));
}
if
(obj[
0
].equals(String.
class
)) {
method.invoke(object, setValue);
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
/**
* 把字符串的首字母改为大写
*
* @param str
* @return String
*/
public
String updateStr(String str) {
char
c = (
char
) (str.charAt(
0
) -
32
);
String s = str.substring(
1
, str.length());
return
c + s;
}
/**
* 把字符串的首字母改为小写
*
* @param str
* @return String
*/
public
String updateSmall(String str) {
char
c = (
char
) (str.charAt(
0
) +
32
);
String s = str.substring(
1
, str.length());
return
c + s;
}
}
|
(4)权限配置 ,AndroidManifest.xml 配置权限代码:
1
2
|
<uses-permission android:name=
"android.permission.INTERNET"
/>
<uses-permission android:name=
"android.permission.ACCESS_WIFI_STATE"
/>
|
(5)解析测试:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SAXParserContentHandler contentHandler =
new
SAXParserContentHandler();
List<Object> list;
Plant plant =
new
Plant();
try
{
SimpleDateFormat formatter =
new
SimpleDateFormat (
"yyyy-MM-dd HH:mm:ss S "
);
Date curDate =
new
Date(System.currentTimeMillis());
//获取当前时间
String str = formatter.format(curDate);
System.out.println(
" 开始时间为 :"
+str );
list = contentHandler.parseReadXml(
"http://www.w3school.com.cn/example/xmle/plant_catalog.xml"
,plant);
System.out.println( list.size()+
" AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
);
for
(Object object : list) {
Plant pants=(Plant )object;
System.out.println(
"普通种类:"
+pants.getCommon());
System.out.println(
" 植物名称:"
+pants.getBotanical() );
System.out.println(
"地区:"
+pants.getZone() );
System.out.println(
"可用性:"
+pants.getAvailability());
Log.d(
"Pull Helper"
,
"Pull Helpe:"
+pants.getBotanical()+
"可用性:"
+pants.getAvailability());
}
Date curend =
new
Date(System.currentTimeMillis());
//获取当前时间
String strend = formatter.format(curend);
System.out.println(
" 结束时间为 :"
+strend );
}
catch
(Exception e) {
// System.out.println(" %%%%%%%%%%%%%%&&&&&&&&&&&&&&&&&&&&&&& "+e.getMessage());
e.printStackTrace();
}
}
|
3.应注意问题:
1)如果要解析网络XML文件,就需要在在AndroidManifest.xml 配置权限,代码为:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
如果不加权限代码会出现:
XML文法正常解析,使用LogCat可以再告警(W)中看到 Permission denied (没有权限;拒绝访问
)异常信息
2)如果XML文件放置在本地服务器(自己的PC机,XMl运行在其他环节中,如 JAVA ,PHP),在访问是需要设置静态IP地址,访问是使用静态IP地址访问:
如: http://192.85.1.235/mms/index.php?controller=default
如果直接使用 http://localhost/mms/index.php?controller=default 就会报:Connection refused(连接拒绝)
3)如果使用助手类解析XML,在根据XML标签生成对应Model(实体)时,应注意,Model实体名称必须和目标根目录名称忽略大小后保持一致生成实体所定义的属性名称必须和XML目标标签下的属性标签名称保持一致:
<?xml version="1.0" encoding="UTF-8" ?>
<CATALOG>
<PLANT>
<COMMON>Bloodroot</COMMON>
<BOTANICAL>Sanguinaria canadensis</BOTANICAL>
<ZONE>4</ZONE>
<LIGHT>Mostly Shady</LIGHT>
<PRICE>$2.44</PRICE>
<AVAILABILITY>031599</AVAILABILITY>
</PLANT>
</CATALOG>
对应Model实体类名称应该为: Plant ,不然的话解析过程中不会报异常,只是解析结果为空,因为解析方法通过传递参数Model对象实例找到对应的Model类名称,并使用它调getClass().getDeclaredFields()获取实体中定义的属性(XML目标标签下的属性标签,如 name ,price ,description);
如果实体所定义的属性名称必须和XML目标标签下的属性标签名称保持不一样,就无法把XML标签内容赋值给对应实体的属性,对应实体属性解析结果为null ;