iOS 中的 xml 解析

在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
原文地址:https://www.cnblogs.com/pengpengzhang/p/4843594.html