首页 > 代码库 > ios网络学习------8 xml格式数据的请求处理 用代码块封装

ios网络学习------8 xml格式数据的请求处理 用代码块封装

#pragma mark 加载xml
- (void)loadXML
{
    //获取网络数据。
    NSLog(@"load xml");
    //从web服务器加载数据
    NSString *str = @"http://www.baidu.com?format=xml";  //这里是乱写的
    //1简历NSURL
    NSURL *url = [NSURL URLWithString:str];
    //2建立NSURLRequest
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:2.0f];
    //3建立NSURLConnect的同步方法加载数据
    NSURLResponse *response = nil;
    NSError *error = nil;
    
    
    //同步加载数据
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    MyXMLParser *myParser = [[MyXMLParser alloc]init];
    
    //懒加载实例化数据
    if (self.dataList == nil) {
        self.dataList = [NSMutableArray array];
    }else{
        [self.dataList removeAllObjects];
    }
    
    //解析数据
    [myParser xmlParserWithData:data StartName:@"video"
    startElement:^( NSDictionary *dict) {
        //1 实例化currentvideo
        self.currentVideo = [[Video alloc]init];
        //2 设置videoid
        self.currentVideo.videoId = [dict[@"videoId"]integerValue];
    } endElement:^(NSString *elementName, NSString *result) {
        if ([elementName isEqualToString:@"name"]) {
            self.currentVideo.name = result;
        }else if ([elementName isEqualToString:@"length"]){
            self.currentVideo.length = [result integerValue];
        }else if ([elementName isEqualToString:@"videoURL"]){
            self.currentVideo.videoId = [result integerValue];
        }else if ([elementName isEqualToString:@"imageURL"]){
            self.currentVideo.imageURL = result;
        }else if ([elementName isEqualToString:@"desc"]){
            self.currentVideo.desc = result;
        }else if ([elementName isEqualToString:@"teacher"]){
            self.currentVideo.teacher = result;
        }else if ([elementName isEqualToString:@"video"]){
            [self.dataList addObject:self.currentVideo];
        }
    } finishedParser:^{
        self.currentVideo = nil;
        [self.tableView reloadData];   //刷新表格数据
    } errorParser:^{
        NSLog(@"解析出现错误");
        //清空临时数据
        self.currentVideo = nil;
        //清空数组
        [self.dataList removeAllObjects];
    }];
}
<pre name="code" class="objc">#import <Foundation/Foundation.h>

//代理方法中需要与调用者交互的方法:
 // 2 交互元素: elementname  attributeDict
 // 4 交互的元素: elementname 中转的字符串
  //5 仅通知即可
  //6 仅通知即可

//定义块代码:
typedef void(^startElementBlock)(NSDictionary *dict);
typedef void(^endElementBlock)(NSString *elementName, NSString *result);
typedef void(^xmlParserNotificationBlock)();

@interface MyXMLParser : NSObject
//定义解析方法
/*
 data  xml数据
 startname 开始的节点名称
 startElement 开始节点方法
 endElement  结束节点方法
 finishedparser 文档解析结束。
 errorParse  文档解析出错。
*/
-(void)xmlParserWithData:(NSData *)data
                 StartName:(NSString *)startName
                 startElement:(startElementBlock)startElement
                 endElement:(endElementBlock)endElement
                 finishedParser:(xmlParserNotificationBlock)finishedParser
                 errorParser:(xmlParserNotificationBlock)errorParser;
@end


<pre name="code" class="objc">#import "MyXMLParser.h"

@interface MyXMLParser() <NSXMLParserDelegate>
{
    //记录块代码的成员变量
    startElementBlock _startElementBlock;
    endElementBlock _endElementBlock;
    xmlParserNotificationBlock _finishedBlock;
    xmlParserNotificationBlock _errorBlock;
}

//开始节点名称,列如:video  如果检测到此名称, 需要实例化对象
@property (strong, nonatomic)NSString *startElementName;
//中转字符串
@property (strong, nonatomic) NSMutableString *elementString;
@end


@implementation MyXMLParser

//在这个方法里面实现xml的解析。
/*
 data  xml数据
 startname 开始的节点名称
 startElement 开始节点方法
 endElement  结束节点方法
 finishedparser 文档解析结束。
 errorParse  文档解析出错。
 */
- (void)xmlParserWithData:(NSData *)data
                    StartName:(NSString *)startName
                    startElement:(startElementBlock)startElement
                    endElement:(endElementBlock)endElement
                    finishedParser:(xmlParserNotificationBlock)finishedParser
                    errorParser:(xmlParserNotificationBlock)errorParser
{
    self.startElementName = startName;
    //记录块代码
    _startElementBlock = startElement;
    _endElementBlock = endElement;
    _finishedBlock = finishedParser;
    _errorBlock = errorParser;
    
    //定义解析器并且开始解析
    NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
    [parser setDelegate:self]; //设置代理
    //开始解析
    [parser parse]; //这个方法会调用下面的几个方法来实现。
}


#pragma mark - XML解析器代理方法
//所谓需要与外界交互,表示需要与调用发打交道,通知调用放执行某些操作。
//1开始解析文档,初始化数据,也不需要与外部交互。
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
    //实例化中装字符串
    if (self.elementString == nil) {
        self.elementString = [NSMutableString string];
    }
}

//2开始解析元素(元素的头部video, 需要实例化对象, attributedict需要设置属性)
//需要与外部交互
//交互的元素: elementName  attributeDict
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:self.startElementName]) {
        //开始部分代码
        _startElementBlock(attributeDict);
    }
    //开始循环执行第三个方法前,清空中转字符串
    [self.elementString setString:@""];
}

//3发现元素字符串(拼接字符串,不需要和外部交互)
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [self.elementString appendString:string];
}

//4结束元素解析,根据elementname和第三步的拼接内容,确定对象属性,需要与外部交互
//交互的元素: elementname  中转的字符串
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    NSString *result = [NSString stringWithString:self.elementString];
    _endElementBlock(elementName, result);
}

//5解析文档结束,通常需要调用放刷新数据。
//交互的元素: 仅通知即可
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
    [self.elementString setString:@""];
    _finishedBlock();
}
//解析出错,通知调用方解析出错(需要与外界交互)。
//交互的元素: 仅通知即可。
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
    NSLog(@"解析出错");
    [self.elementString setString:@""];
    //带一个nserror回去会更好。
    _errorBlock();
}
@end