XML一共有两种解析方式,SAX和DOM,本篇记录一下我在SAX数据解析时的操作。SAX解析器是对数据进行逐条的解析,这样的好处是可以查看每条的解析内容,不必等待全部解析完成,也可以发现数据中的错误。缺点就是读取速度比较慢。
citys.xml截图取一段示意:
首先创建一个NSObject:SAXxml.h SAXxml.m
在.m.中自定义一个方法startParser,并在.h中声明
-(void)startParser{
//citys:xml文件名,xml:文件类型
NSString *path=[[NSBundle mainBundle] pathForResource:@"citys" ofType:@"xml"];
//获取PATH路径中的数据data
NSData *data=[NSData dataWithContentsOfFile:path];
//将数据传入解析类
NSXMLParser *parser=[[NSXMLParser alloc] initWithData:data];
//将数据转为字符串类型NSUTF8StringEncoding枚举
NSString *astring=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//在.h中加入解析类NSXMLParser的协议
parser.delegate=self;
[parser parse];
//有alloc就要release,为了内存平衡
[astring release];
[parser release];
}
//没什么用处,就是下面调用的时候名字方便了
static NSString *Kcities=@"cities";
static NSString *Kcity=@"city";
static NSString *Kname=@"name";
static NSString *Klatitude_e6=@"latitude_e6";
static NSString *Klongitude_e6=@"longitude_e6";
//用协议里的开始解析方法elementName为city中属性的名字
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
//如果节点(尖括号为节点)中的名字与Kcity相同
if ([elementName isEqualToString:Kcity]) {
//创建model用于存放每个城市中的属性,如名字,经度,纬度
SaxModel *model=[[SaxModel alloc] init];
//并将model加入到大数组中,数组在初始化创建,数组存储的就是一个个城市
[_bigArr addObject:model];
[model release];
}if ([elementName isEqualToString:Kname]) {
SaxModel *model=[_bigArr lastObject];
NSString *name=[attributeDict objectForKey:@"data"];
model.name=name;
}if ([elementName isEqualToString:Klatitude_e6]) {
SaxModel *model=[_bigArr lastObject];
NSString *kla=[attributeDict objectForKey:@"data"];
model.latitude_e6=kla;
}if ([elementName isEqualToString:Klongitude_e6]) {
SaxModel *model=[_bigArr lastObject];
NSString *klo=[attributeDict objectForKey:@"data"];
model.longitude_e6=klo;
}
}
//协议中的结束解析方法
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//当走到最后一个节点的时候也就是name=Kcities,将大数组里存储的各个城市通过一个自定义的协议传到root页的数组中(为了在tableView中显示)
if ([elementName isEqualToString:Kcities]) {
[self.delegate sendMessageToSax:_bigArr];
}
}
SAXxml.h
//声明这个自定义的协议
@protocol SaxXmlDelegate;
@interface SaxXml : NSObject<NSXMLParserDelegate>
{//创建可变数组的成员变量用于存放city的属性也就是model
NSMutableArray *_bigArr;
}
//声明刚才自定义的方法
-(void)startParser;
//设置协议的属性
@property(nonatomic,retain)id<SaxXmlDelegate>delegate;
@end
//自定义一个协议
@protocol SaxXmlDelegate <NSObject>
//自定义一个非必须实现的方法
@optional
-(void)sendMessageToSax:(NSArray *)str;
@end
为了将每个city中的数据存储在一起调用,我们选择model继承与NSObject
SaxModel.h
//创建属性
@property(nonatomic,retain)NSString *name;
@property(nonatomic,retain)NSString *latitude_e6;
@property(nonatomic,retain)NSString *longitude_e6;
@property(nonatomic,retain)NSString *city;
SaxModel.m
//释放,成员变量都需要释放
-(void)dealloc{
[_name release];
[_latitude_e6 release];
[_longitude_e6 release];
[_city release];
[super dealloc];
}
现在我们回到rootViewController
我们的需求是将XML的数据解析出并显示在tableView上
rootViewController.h
首先需要引SAXxml.h的头文件
@interface RootViewController : UIViewController
//加入自定义的协议,以及tableView的两个协议
<SaxXmlDelegate,UITableViewDataSource,UITableViewDelegate>
{
//定义一个可变数组用于存储_bigArr传过来的数据,定义一个tableView
NSMutableArray *_arr;
UITableView *_aTable;
}
在rootViewController.m
中引入头文件,为了也能用model需要导入SaxModel.h,引用NewCell.h(下面会创建,这是一个自定义的cell),再就引用SaxXml.h为了传值
//一定要release
-(void)dealloc{
[_aTable release];
[_arr release];
[super dealloc];
}
//这个方法是创建文件就会有的,一般初始化什么的时候写在里面,此处是为了初始化数组
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
_arr=[[NSMutableArray alloc] init];
}
return self;
}
在viewDidLoad中创建tableView
//其中的高度减掉的44是导航的高度,这个因人而异
_aTable=[[UITableView alloc] initWithFrame:CGRectMake(10, 10, 320,self.view.frame.size.height-44) style:UITableViewStylePlain];
[self.view addSubview:_aTable];
_aTable.delegate=self;
_aTable.dataSource=self;
//设置行高
_aTable.rowHeight=150;
[_aTable release];
//调用开始解析的方法
[self saxParser];
//根据tableView协议调用的必须实现的方法
//根据数组中的数据算出一共多少个cell
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [_arr count];
}
//创建cell,并传值
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//重用池名字
static NSString * cellIdentify =@"cellIdentify";
//NewCell是自定义的cell的格式,下面我会写到
NewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentify];
//如果不为空,创建一个重用池
if (cell ==Nil)
{
cell=[[[NewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentify] autorelease];
}
//获取每行
SaxModel *model=[_arr objectAtIndex:indexPath.row];
//传值
cell.name.text=model.name;
cell.la.text=model.latitude_e6;
cell.lo.text=model.longitude_e6;
return cell;
}
使用自定义协议中自定义的方法将SaxXml中的_bigArr,传值到rootViewController的_arr中
-(void)sendMessageToSax:(NSArray *)str{
[_arr addObjectsFromArray:str];
}
创建开始解析的方法
-(void)saxParser{
SaxXml *a=[[SaxXml alloc] init];
a.delegate=self;
[a startParser];
}
自定义一个cell
继承于UITableViewCell
NewCell.h
//定义每个城市的属性
@property(nonatomic,retain) UILabel *name;
@property(nonatomic,retain) UILabel *la;
@property(nonatomic,retain)UILabel *lo;
NewCell.m
-(void)dealloc{
[_name release];
[_la release];
[_lo release];
[super dealloc];
}
定义每个cell中每个Label的坐标大小
self.name=[[UILabel alloc] initWithFrame:CGRectZero];
[self.contentView addSubview:_name];
[_name release];
self.la=[[UILabel alloc] initWithFrame:CGRectZero];
[self.contentView addSubview:_la];
[_la release];
self.lo=[[UILabel alloc] initWithFrame:CGRectZero];
[self.contentView addSubview:_lo];
[_lo release];
先将坐标创建为0,0,0,0
用一个固定方法设置具体大小
-(void)layoutSubviews{
[_name setFrame:CGRectMake(10, 10, 100, 30)];
[_lo setFrame:CGRectMake(10, 40, 100, 30)];
[_la setFrame:CGRectMake(10, 70, 100, 30)];
}
解析后运行在TableView上的样子