ASIHTTPRequest和libxml结合,实现边请求边解析
<user name="t3" phone="15877103548"/>
<user name="t1" phone="13399459990"/>
</List>
<List Name="好友">
<user name="f2" phone="13828831140"/>
<user name="f3" phone="15886103548"/>
<user name="f1" phone="13019459990"/>
</List>
</root>
也就是说,这是一个通讯录类似的东西。通讯录把电话号码按性质分成不同的组,就像Windows mobile智能手机上的的通讯录,把电话号码按“家庭”、“好友”、“同事”等进行划分。
我们新建一个?BaseXmlParser的子类 TelNoXmlParser ,让这个 TelNoXmlParser 去实现 3 个回调方法:
#import?<Foundation/Foundation.h>
#import?<libxml/tree.h>
#import?"BaseXmlParser.h"
@interface?TelNoXmlParser : BaseXmlParser {
BOOL?loginSuccess?;
NSMutableArray?*?groups?,*?members?;
NSMutableDictionary?*?_group?;
NSDictionary?*?_user?;
}
@end
#import?"TelNoXmlParser.h"
?
?
@implementation?TelNoXmlParser
?
-(?id?)init{
if?(?self?=[?super?init?]) {
//?一个?groups?数组,代表了所有?List
groups?=[[?NSMutableArray?alloc?]?init?];
[?_root?setObject?:?groups?forKey?:?@"items"?];
loginSuccess?=?YES?;
}
return?self?;
}
-(?void?)dealloc{
[?_group?release?],?_group?=?nil?;
[?super?dealloc?];
}
//--------------------------//
#pragma mark -- libxml handler?,主要是?3?个回调方法?--
//--------------------------//
//?解析元素开始标记时触发?,?在这里取元素的属性值以及设置标志变量
- (?void?)startElementLocalName:(?const?xmlChar?*)localname
???prefix:(?const?xmlChar?*)prefix
??URI:(?const?xmlChar?*)URI
nb_namespaces:(?int?)nb_namespaces
???namespaces:(?const?xmlChar?**)namespaces
nb_attributes:(?int?)nb_attributes
??nb_defaulted:(?int?)nb_defaultedslo
???attributes:(?const?xmlChar?**)attributes
{?//?我们关心?8?个元素标签,所以设置了?8?个标志位
????// login_status
????if?(?strncmp?((?char?*)localname,?"login_status"?,?sizeof?(?"login_status"?)) ==?0?) {
??????????loginSuccess?=?NO?;
????????return?;
????}
if?(?loginSuccess?) {
// List
if?(?strncmp?((?char?*)localname,?"List"?,?sizeof?(?"List"?)) ==?0?) {
NSDictionary?* atts=[?self?getAtributes?:attributes?withSize?:nb_attributes];?//?获取?List?的所有属性
_group?=[[?NSMutableDictionary?alloc?]?init?];
members?=[[?NSMutableArray?alloc?]?init?];
[?_group?setObject?:?members?forKey?:?@"members"?];
[?_group?setObject?:[[?NSString?alloc?]?initWithString?:(?NSString?*)[atts?objectForKey?:?@"Name"?]]forKey?:?@"groupname"?];
[?groups?addObject?:?_group?];?//?把?group?加入数组
return?;
}
// user
if?(?strncmp?((?char?*)localname,?"user"?,?sizeof?(?"user"?)) ==?0?) {
NSDictionary?* atts=[?self?getAtributes?:attributes?withSize?:nb_attributes];?//?获取?List?的所有属性
_user?=[[?NSDictionary?alloc?]?initWithDictionary?:atts];
[?members?addObject?:?_user?];
return?;
}
}
}
//?解析元素结束标记时触发
- (?void?)endElementLocalName:(?const?xmlChar?*)localname
??prefix:(?const?xmlChar?*)prefix URI:(?const?xmlChar?*)URI
{
if?(?strncmp?((?char?*)localname,?"root"?,?sizeof?(?"root"?)) ==?0?){?//root?结束时置??login_status?标志
if?(?loginSuccess?) {
[?_root?setObject?:?@"true"?forKey?:?@"login_status"?];
}?else?{
[?_root?setObject?:?@"false"?forKey?:?@"login_status"?];
}
}
if?(?loginSuccess?) {
//?我们还关心?<List>?的结束标记
if?(?strncmp?((?char?*)localname,?"List"?,?sizeof?(?"List"?)) ==?0?) {
[?_group?release?],?_group?=?nil?;?//?回收?_group?对象,以便重复利用
}?else?if?(?strncmp?((?char?*)localname,?"user"?,?sizeof?(?"user"?)) ==?0?){
[?_user?release?],?_user?=?nil?;?//?回收?_user?对象,以便重复利用
}
}
}
//?解析元素体时触发
- (?void?)charactersFound:(?const?xmlChar?*)ch
len:(?int?)len
{??????
//?没有元素体需要关心
}
@end
接下来我们看如何在?ViewController 中使用。
?
四、在?UI 中测试在?ViewController 中放入一个按钮和一个 WebView,当点击按钮时,请求http服务器,获取通讯录XML 数据,并解析为 Dictionary 对象。把解析结果显示在 WebView 中。
这是按钮的?touch up inside 事件代码:
-(?IBAction?)go{
if?(?_queue?==?nil?){
_queue?= [[?NSOperationQueue?alloc?]?init?];
}
[?button?setEnabled?:?NO?];
[?progress?setProgress?:?0?];
[?webView?loadHTMLString?:?@""?baseURL?:[?NSURL?URLWithString?:?URL?]];
//?构造?xmlparser
TelNoXmlParser?* parser=[[?TelNoXmlParser?alloc?]?init?];
//?把?self?注册为?delegate?,这样?self?必需实现?syncRequestParseStatusNofity:?方法?,?以接收statusChanged?方法
SyncRequestParseOperation?* operation=[[?SyncRequestParseOperation?alloc ]
??initWithURLString?:?URL
??xmlParser?:parser
??delegate?:?self?];
//?把?progress?设置为?progressDelegate?,这样会显示进度
[operation?setProgressDelegate?:?progress?];
[parser?release?];?// opertaion?已?retain?,可以?release
[?_queue?addOperation?:operation];?//?开始处理
[operation?release?];?//?队列已?retain?,可以?release?;
}
这是异步消息到达时的处理代码,当数据接收完时,我们把解析结果在WebView 中显示:
//?实现?statusChanged?通知方法
-(?void?)syncRequestParseStatusNofity:(?id?)sender{
SyncRequestParseOperation?* operation=(?SyncRequestParseOperation?*)sender;
int?status=[operation?status?];
NSLog?(?@"status:%d"?,status);
if?(status==?kRequestStatusFinished?){?//?如数据接收完成
[?button?setEnabled?:?YES?];
NSDictionary?* d=[operation?data?];
[?webView?loadHTMLString?:[d?description?]?baseURL?:[?NSURL?URLWithString?:?URL?]];
}
}
这是程序运行时?WebView 显示效果:

?
注意,当xml 文档比较大时,WebView 的内容是从上到下逐渐刷新的。
这是控制台输出,可以看到服务器响应的数据是被分成很多次下载的:
