读写XML文档,目前流行的两种模式:SAX和DOM。
1.SAX是一种基于事件驱动的解析模式。解析XML的时候,程序从上到下读取XML文档,如果遇到开始标签、结束标签、属性等,就会触发相应的事件。
优点:解析速度快,iOS重点推荐使用SAX模式解析
缺点:只能读取XML文档,不能写入XML文档
2.DOM模式是将XML文档作为一颗树状结构进行分析,提供获取节点的内容,以及相关属性,或是新增、删除和修改节点的内容。XML解析器在加载XML文件以后,DOM将XML文件的元素视为一个树状结构的节点,一次性读入到内存中。
优点:能够修改XML文档
缺点:如果文档比较大,解析速度就会变慢
NSXML是iOS SDK自带的,也是苹果默认的解析框架,采用SAX模式解析,它是SAX解析模式的代表。本文主要介绍采用NSXML解析XML文件。
采用NSXML解析XML文件
NSXML框架中的核心是NSXMLParser和它的代理NSXMLParserDelegate,NSXMLParserDelegate中的常用方法有:
// 在文档开始的时候触发- (void)parserDidStartDocument:(NSXMLParser*)parser;// 在文档出错的时候触发,该方法一般在调试阶段使用,实际发布时意义不大- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError;// 遇到一个开始标签时触发,其中namespaceURI部分是命名空间,qualifiedName是限定名,attributes是字典类型的属性集合- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qName attributes:(NSDictionary*)attributeDict;// 遇到字符串时触发- (void)parser:(NSXMLParser*)parser foundCharacters:(NSString*)string;// 遇到结束标签时触发- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qName;// 遇到文档结束时触发- (void)parserDidEndDocument:(NSXMLParser*)parser;
代码演示解析XML文件
Notes.xml文件如下:
2015-10-20早上7点钟起床到实验室xiaolou2015-10-21学习iOS开发xiaolou2015-10-22学习iOS开发之解析XML文件xiaolou2015-10-23采用NSXML解析XML文件xiaolou2015-10-24解析速度快,iOS重点推荐使用SAX模式解析xiaolou2015-10-25该投简历了,希望能找个好工作xiaolou
新建一个类NotesXMLParser,继承自NSObject,遵守委托协议NSXMLParserDelegate,并拥有相关属性与方法。
NotesXMLParser.h文件:
#import@interfaceNotesXMLParser:NSObject// 解析出的数据内部是字典类型@property(strong,nonatomic)NSMutableArray*notes;// 当前标签的名字@property(strong,nonatomic)NSString*currentTagName;// 开始解析- (void)start;@end
注:定义currentTagName属性的目的是:在触发开始标签方法和结束标签方法 期间临时存储正在解析的元素名,在方法(parser:foundCharacters:)触发时,能够知道目前解析器处于哪个元素之中
NotesXMLParser.m文件中实现start方法:
- (void)start {NSString*path = [[NSBundlemainBundle] pathForResource:@"Notes"ofType:@"xml"];NSURL*url = [NSURLfileURLWithPath:path];// 开始解析XMLNSXMLParser*parser = [[NSXMLParseralloc] initWithContentsOfURL:url]; parser.delegate=self; [parser parse];NSLog(@"解析完成。。。");}
注:NSXMLParser是解析类,它有3个构造方法
1)- (instancetype)initWithContentsOfURL:(NSURL)url;
2)- (instancetype)initWithData:(NSData)data;
3) - (instancetype)initWithStream:(NSInputStream *)stream;
实现NSXMLParserDelegate代理方法:
// 文档开始的时候触发- (void)parserDidStartDocument:(NSXMLParser*)parser {// 此方法只在解析开始时触发一次,因此可在这个方法中初始化解析过程中用到的一些成员变量_notes = [NSMutableArraynew];}// 文档出错的时候触发- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError {NSLog(@"%@", parseError);}// 遇到一个开始标签的时候触发- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qName attributes:(NSDictionary*)attributeDict {// elementName是正在解析的元素的名字_currentTagName = elementName;// 如果元素名字为Note,取出它的属性idif([_currentTagName isEqualToString:@"Note"]) {// 属性在attributeDict参数中传递过来,它是一个字典类型,其中的键的名字就是属性的名字,值是属性的值NSString*_id= [attributeDict objectForKey:@"id"];NSMutableDictionary*dict = [NSMutableDictionarynew]; [dict setObject:_idforKey:@"id"]; [_notes addObject:dict]; }}// 遇到字符串时候触发,该方法是解析元素文本内容主要场所- (void)parser:(NSXMLParser*)parser foundCharacters:(NSString*)string {// 剔除回车和空格// stringByTrimmingCharactersInSet:方法是剔除字符方法// [NSCharacterSet whitespaceAndNewlineCharacterSet]指定字符集为换行符和回车符string = [string stringByTrimmingCharactersInSet:[NSCharacterSetwhitespaceAndNewlineCharacterSet]];if([string isEqualToString:@""]) {return; }NSMutableDictionary*dict = [_notes lastObject];if([_currentTagName isEqualToString:@"CDate"] && dict) { [dict setObject:string forKey:@"CDate"]; }if([_currentTagName isEqualToString:@"Content"] && dict) { [dict setObject:string forKey:@"Content"]; }if([_currentTagName isEqualToString:@"UserID"] && dict) { [dict setObject:string forKey:@"UserID"]; }}// 遇到结束标签时触发,在该方法中主要是清理刚刚解析完成的元素产生的影响,以便于不影响接下来的解析- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qName {// 清理刚才解析的元素的名字,以便于记录接下来解析的元素的名字self.currentTagName=nil;}// 遇到文档结束时触发- (void)parserDidEndDocument:(NSXMLParser*)parser {// 使用通知机制将数据通过广播通知投送回表示层[[NSNotificationCenterdefaultCenter] postNotificationName:@"reloadViewNotification"object:self.notesuserInfo:nil];// 解析完成,清理成员变量self.notes=nil;}
ViewController.m文件:
#import"ViewController.h"#import"NotesXMLParser.h"@interfaceViewController() {UITableView*_tableView;}//保存数据列表@property(nonatomic,strong)NSMutableArray* listData;@end@implementationViewController- (void)viewDidLoad { [superviewDidLoad]; _tableView = [[UITableViewalloc] initWithFrame:self.view.boundsstyle:UITableViewStylePlain]; _tableView.dataSource=self; [self.viewaddSubview:_tableView];// 注册一个通知,这样ViewController才能在解析完成后接收到投送回来的通知// 一旦投送成功就会触发reloadView:方法,在该方法中取出数据,并重新加载表示图[[NSNotificationCenterdefaultCenter] addObserver:selfselector:@selector(reloadView:) name:@"reloadViewNotification"object:nil]; NotesXMLParser *parser = [NotesXMLParser new];// 开始解析[parser start];}- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {return1;}- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {returnself.listData.count;}- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {staticNSString*ID =@"cell";UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:ID];if(!cell) { cell = [[UITableViewCellalloc] initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:ID]; }NSMutableDictionary* dict =self.listData[indexPath.row]; cell.textLabel.text= [dict objectForKey:@"Content"]; cell.detailTextLabel.text= [dict objectForKey:@"CDate"];returncell;}#pragma mark - 处理通知- (void)reloadView:(NSNotification*)notification {// 在该方法中取出数据,并重新加载表示图NSMutableArray*resList = [notification object];self.listData= resList; [_tableView reloadData];}@end
转载请保留原文地址:http://www.jianshu.com/p/871830fc9945