我们知道,ios XML解析一共有两种方法,一种是SAX解析,另一种是DOM解析。两者之间的区别就是 SAX是打印式解析,也就是我们常说的逐行解析。DOM是复印式解析,也就是我们常说的整篇解析。如果在解析过程中遇到错误,SAX解析会停止到出现错误的前一行,而DOM解析不会解析出任何的数据。但是因为SAX解析的缺点是逐行解析,所以相对于DOM解析来说速度比较慢。
下面我们通过一个例子具体来看一下两种解析方式:
首先,我们来具体实现SAX方法:
1.先建立一个方法,通过此方法找到所要解析的文件路径,建立NSXMLParser对象,通过parser对象来设置代理,并调用parse方法来进行解析
- (void)startParser{
NSString *path = [[NSBundle mainBundle]pathForResource:@"citys" ofType:@"xml"];
NSData *filedata = [NSData dataWithContentsOfFile:path];
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:filedata];
[parser setDelegate:self];
[parser parse]; //调用方法进行解析
}
再在.h文件中声明NSXMLParser协议:
<NSXMLParserDelegate>
2.SAX解析中,解析数据时会走两种方法,分别是:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
和
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
这里的参数大家可以自行打印nslog进行测试,这里不便多说。
在我们这个需要解析的文件中,所需要的数据都是每一个元素的属性,所以我们不用didEndElement这个方法,只用到第一个方法,通过方法的最后一个对象attributeDict来找到我们需要的属性来进行调用。在这之前,我们需要定义一个NSMutableArray类型的数组并初始化和释放。建立完成后,开始进行第一个方法的实现:
static NSString *kCity = @"city";
static NSString *kCityname = @"name";
static NSString *klat = @"latitude_e6";
static NSString *klon = @"longitude_e6";//声明常量串
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
if ([elementName isEqualToString:kCity]) {
SaxModel *model = [[DomModel alloc]init];//这里需要自定义model类
[_tablearray addObject:model]; //将model添加到刚才定义的可变数组中
[model release];
}if ([elementName isEqualToString:kCityname]) {
SaxModel *model = [_tablearray lastObject];
NSString *str = [attributeDict objectForKey:@"data"]; //将属性中的城市名取出
model.cityname = str; //将取出的属性赋值给model中对应的成员
}if ([elementName isEqualToString:klat]) {
SaxModel *model = [_tablearray lastObject];
NSString *str = [attributeDict objectForKey:@"data"];
model.Jcity = str;
}if ([elementName isEqualToString:klon]) {
SaxModel *model = [_tablearray lastObject];
NSString *str = [attributeDict objectForKey:@"data"];
model.Wcity = str;
}
}
此时,数据已经全部解析完毕保存在model中,我们将每一个model存储在可变数组—tablearray中,方便调用。我们就可以在一个视图控制器建立tableview,通过tableview的cell来检验我们解析的数据是否正确。
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _tablearray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellinentify = @"cell";
DIYCell *cell = [tableView dequeueReusableCellWithIdentifier:cellinentify];
if (!cell) {
cell = [[[DIYCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellinentify] autorelease];
}
SaxModel *model = [_tablearray objectAtIndex:indexPath.row];
[cell.cityname setText:model.cityname];
[cell.Jcitylabel setText:model.Jcity];
[cell.Wcitylabel setText:model.Wcity];
return cell;
}
这里的cell是我自定义的,.h文件如下:
#import <UIKit/UIKit.h>
@interface DIYCell : UITableViewCell
@property (retain,nonatomic) UILabel *cityname; //城市名
@property (retain,nonatomic) UILabel *Jcitylabel;//城市经度
@property (retain,nonatomic) UILabel *Wcitylabel;//城市纬度
@end
cell的.m 文件:
#import "DIYCell.h"
@implementation DIYCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
_cityname = [[UILabel alloc]initWithFrame:CGRectZero];
_Jcitylabel = [[UILabel alloc]initWithFrame:CGRectZero];
_Wcitylabel = [[UILabel alloc]initWithFrame:CGRectZero];
[self.contentView addSubview:_cityname];
[self.contentView addSubview:_Jcitylabel];
[self.contentView addSubview:_Wcitylabel];
}
return self;
}
- (void)layoutSubviews{
[_cityname setFrame:CGRectMake(5, 5, 60, 30)];
[_Jcitylabel setFrame:CGRectMake(70, 5, 80, 30)];
[_Wcitylabel setFrame:CGRectMake(155, 5, 100, 30)];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
最后输出结果:
2.我们再来具体实现DOM 方法:
1.在解析之前,我们需要先使用两个文件:
如果有需要的可以留言。DOM解析文件。
下面讲解一下适配这两个文件:
在build Settings查找Header Search Paths,双击,并点击添加:
然后输入:/usr/include/libxml2,点击回车。
再查找other Linker Flags,点击添加-lxml2 配置完成。
然后进行解析:(建议与数据图配合理解,比较容易,注意层级关系)
- (void)DomParserAttribute{
//与Sax解析一样,先找到需要解析的文件路径,再解析
NSString *path = [[NSBundle mainBundle]pathForResource:@"citys" ofType:@"xml"];
NSData *filedata = [NSData dataWithContentsOfFile:path];
NSError *error = Nil;
GDataXMLDocument *document = [[GDataXMLDocument alloc]initWithData:filedata options:GDataXMLDocumentKind error:&error];
if (error) {
NSLog(@"error = %@",error);
}
GDataXMLElement *root = [document rootElement];//找到根节点
NSArray *arr = [root children];//这里注意,根节点的子节点是以数组形式存在
GDataXMLElement *cityselement = [arr lastObject];
NSArray *cityarray = [cityselement children];
for (GDataXMLElement *element in cityarray) {
DomModel *model = [[DomModel alloc]init];
[_tablearray addObject:model];//同样与Sax解析一样,将model放入数组中
NSArray *desription = [element children];
for (GDataXMLElement *value in desription) {
model = [_tablearray lastObject];
if ([value.name isEqualToString:@"name"]) {
GDataXMLNode *node = [value attributeForName:@"data"];//取出每一个元素的属性值
model.cityname = [node stringValue];
}
if ([value.name isEqualToString:@"latitude_e6"]) {
GDataXMLNode *node = [value attributeForName:@"data"];
model.Jcity = [node stringValue];
}
if ([value.name isEqualToString:@"longitude_e6"]) {
GDataXMLNode *node = [value attributeForName:@"data"];
model.Wcity = [node stringValue];
}
}
}
}
这里,我们已经将数据全部取出,同Sax解析一样,我们建立tableview进行显示,这里的操作重复,就不一一展示。效果图如下:
到这里,XML的两种解析方式已经全部完毕,主要注意的就是层级关系,以及他们的特性,可以根据自己对数据的需求来选择解析方式。以达到自己想要的效果。
以上内容均属原创,如果有什么不明白的,或者我写的有什么不足,欢迎留言,谢谢。