在ios 中解析xml 的方法有很多种
1.苹果原生
NSXMLParser:SAX方式解析,使用简单
2.第三方框架
libxml2:纯c语言,默认包含在ios sdk中,同时支持DOM 和 SAX 方式解析
GDataXML : DOM方式解析,由谷歌开发,基于libxml2
xml 解析建议方式:
大文件选用:NSXMLParser 或者 libxml2
小文件选用:GDataXML
xml解析:
SAX方式解析:
从上往下,一点一点解析,性能比较好,也是苹果推荐使用的。
DOM方式解析
一次性将xml文档以树形结构读入内存,内存消耗比较大。适用于比较小的xml文件解析。在ios 开发中默认是不支持这种方式的解析。但是有一些第三方框架实现了这个方式,
KissXML & GData 都是采用DOM解析。
// // ViewController.m // 04-xml解析 // // Created by jerry on 15/9/28. // Copyright (c) 2015年 jerry. All rights reserved. // #import "ViewController.h" #import "Video.h" @interface ViewController ()<NSXMLParserDelegate> /** * 整个xml的数据容器 */ @property(nonatomic,strong)NSMutableArray *videos; /** * 第三步拼接字符串 */ @property(nonatomic,strong)NSMutableString *elementString; /** * 当前模型 */ @property(nonatomic,strong)Video *currentVideo; /** * 专门用来存储表格所有的数据,也就是表格数据源 */ @property(nonatomic,strong)NSMutableArray *dataList; @end @implementation ViewController @synthesize videos = _videos; - (void)setDataList:(NSMutableArray *)dataList { _dataList = dataList; // 只要重新赋值 就要刷新 [self.tableView reloadData]; // 隐藏刷新控件 [self.refreshControl endRefreshing]; } /** * 懒加载 初始化 自定义属性 */ -(NSMutableArray *)videos { if (_videos == nil) { _videos = [NSMutableArray array]; } return _videos; } /** * 懒加载 初始化 自定义属性 * * @return <#return value description#> */ - (NSMutableString *)elementString { if (_elementString == nil) { _elementString = [NSMutableString string]; } return _elementString; } //- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // [self loadData]; //} -(void)loadView { [super loadView]; [self loadData]; } /** * 加载xml 数据 * 从第2步到第4步,可以拿到video的属性。 */ - (IBAction)loadData { // 1.url NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"]; // 2.请求 // 不采用这个请求的原因就是因为他会有缓存,每次加载会先找缓存数据,这样就会出现“幻觉”数据。 // NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 这样的请求 可以避免缓存数据,以免数据更改了 刷新ui 的时候还是显示原来的数据。 NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:2.0f]; // 3.连接 [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { // xml 解析 // 1.实例化xml 解析器 NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data]; // 2.设置代理 parser.delegate = self; // 3.开始解析 [parser parse]; }]; } #pragma mark - 代理方法 /** * 1.打开文档 准备开始解析 * * @param parser <#parser description#> */ - (void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"打开文档"); // 初始化数组容器,清空容器,便于多次加载数据 [self.videos removeAllObjects]; } /** * 2.开始节点 * 新建一个video对象,设置video的属性, * @param parser <#parser description#> * @param elementName 元素名称 * @param namespaceURI <#namespaceURI description#> * @param qName <#qName description#> * @param attributeDict <#attributeDict description#> */ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { NSLog(@"开始节点---%@---%@",elementName,attributeDict); // 如果开始节点的名称是video 就创建一个对象。 if ([elementName isEqualToString:@"video"]) { self.currentVideo =[[Video alloc]init]; // 设置videoid self.currentVideo.videoId = attributeDict[@"videoId"]; } // 清空字符串内容 因为马上要进行第3步,开始拼接当前节点内容 [self.elementString setString:@""]; } /** * 3.发现节点里面内容 * * @param parser <#parser description#> * @param string <#string description#> */ - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { NSLog(@"发现节点内容---%@",string); // 开始拼接 [self.elementString appendString:string]; } /** * 4.结束节点 * * @param parser <#parser description#> * @param elementName <#elementName description#> * @param namespaceURI <#namespaceURI description#> * @param qName <#qName description#> */ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"结束节点---%@",elementName); if ([elementName isEqualToString:@"video"]) { // 如果结束节点是video 需要把这个对象添加到数组 [self.videos addObject:self.currentVideo]; }else if (![elementName isEqualToString:@"videos"]) { // 利用kvc 进行赋值。可以省略注释掉的代码的麻烦。 [self.currentVideo setValue:self.elementString forKeyPath:elementName]; } // // 如果结束节点,就可以把第二步创建的对象进行赋值,设置name/length属性 // else if ([elementName isEqualToString:@"name"]) { // // 设置name 属性 // self.currentVideo.name = self.elementString; // // }else if ([elementName isEqualToString:@"length"]) // { // // 设置length属性 // // @([self.elementString integerValue]) 现将字符串转成 数字,然后再将数字专程number // self.currentVideo.length = @([self.elementString integerValue]); // // } } /** * 5.结束文档 * * @param parser <#parser description#> */ - (void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"结束文档"); // xml 真正解析结束 可以在主线程更新ui dispatch_async(dispatch_get_main_queue(), ^{ self.dataList =self.videos; }); } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.videos.count; } - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; Video *video = self.dataList[indexPath.row]; cell.textLabel.text = video.name; return cell; } @end