• IOS-JSON & XML解析


    XML & JSON 简介

    •JSON
    –作为一种轻量级的数据交换格式,正在逐步取代XML,成为网络数据的通用格式
    –基于JavaScript的一个子集
    –易读性略差,编码手写难度大,数据量小
    –JSON格式取代了XML给网络传输带来了很大的便利,但是却没有了XML的一目了然,尤其是JSON数据很长的时候,我们会陷入繁琐复杂的数据节点查找中
    •JSON是轻量级的数据交换格式,正逐步取代XML,成为通用网络数据格式
    •使用类方法JSONObjectWithData:options:error:可以将接收到的JSON数据反序列化为NSArray或NSDictionary等对象
    •XML
    –可扩展标记语言
    –用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言
    –易读性高,编码手写难度小,数据量大
     
    JSON格式说明
    •对象: {} 括起来的内容
    –数据结构为 {key:value,key:value,...}的键值对的结构
    –可以反序列化为OC中的NSDictionary
    •数组: []括起来的内容
    –数据结构为 ["java","javascript","vb",...]
    –可以反序列化为OC中的NSArray
    Ø序列化:在传输之前,将对象转换成有序的字符串或者二进制数据流
    Ø反序列化:将接收到的字符串或者二进制数据流转换成对象或者数组,以便程序访问
     
    NSXMLParser解析方法
    •NSXMLParser是SAX方法解析
    –SAX(Simple API for XML)
    •只能读,不能修改,只能顺序访问,适合解析大型XML,解析速度快
    •常应用于处理大量数据的XML,实现异构系统的数据访问,实现跨平台
    •从文档的开始通过每一节点移动,定位一个特定的节点
    –DOM(Document Object Model)
    •不仅能读,还能修改,而且能够实现随机访问,缺点是解析速度慢,适合解析小型文档
    •一般应用与小型的配置XML,方便操作
    •为载入到内存的文档节点建立类型描述,呈现可横向移动、潜在巨大的树型结构
    •在内存中生成节点树操作代价昂贵
     
    NSXMLParser解析过程
    •1. 创建NSXMLParser实例,并传入从服务器接收的XML数据
    •2. 定义解析器代理
    •3. 解析器解析
    •4. 通过解析代理方法完成XML数据的解析
     
    NSXMLParser解析代理方法

    // 1. 开始解析XML文档

    - (void)parserDidStartDocument:

    // 2. 开始解析某个元素,会遍历整个XML,识别元素节点名称

    - (void)parser:didStartElement:namespaceURI:qualifiedName:attributes:

    // 3. 文本节点,得到文本节点里存储的信息数据,对于大数据可能会接收多次!为了节约内存开销

    - (void)parser:foundCharacters:

    // 4. 结束某个节点,存储从parser:foundCharacters:方法中获取到的信息

    - (void)parser:didEndElement:namespaceURI:qualifiedName:

    注意:在解析过程中,2、3、4三个方法会不停的重复执行,直到遍历完成为止

    // 5. 解析XML文档结束

    - (void)parserDidEndDocument:

    // 6. 解析出错

    - (void)parser:parseErrorOccurred:

    实例代码

    #import "DemoViewController.h"
    #import "UIImageView+WebCache.h"

    #import "Video.h"
    #import "VideoCell.h"

    #define kBaseURL    @"http://192.168.3.251/~apple"

    @interface DemoViewController () <NSXMLParserDelegate>
    {
        NSMutableArray      *_dataList;
        UIImage             *_placeHolderImage;
        
        // 以下是XML解析需要的成员变量
        NSMutableString     *_elementString;    // 拼接的字符串
        Video               *_currentVideo;     // 当前解析的视频模型对象
    }

    @end

    @implementation DemoViewController

    /**
     数据处理过程
     
     1> 从服务器上加载不同类型的数据JSON/XML
     2> 将接收到的数据转换成对象数组
     3> 在表格中显示数组内容
     
     XML解析的六个步骤
     
     1. 开始解析文档,在这里做初始化工作
     2.3.4会循环执行,一直到XML文档解析完毕
     2. 解析一个节点
     3. 查找节点内容,可能会多次
     4. 节点完成
     5. 解析完成,做收尾工作
     6. 解析出错,清理中间数据
     */
    - (void)viewDidLoad
    {
        [super viewDidLoad];

        // 设置标题
        self.title = (_loadType == kLoadDataJSON) ? @"JSON" : @"XML";
        
        _placeHolderImage = [UIImage imageNamed:@"user_default"];
        
        if (_loadType == kLoadDataJSON) {
            [self loadJSON];
        } else {
            [self loadXML];
        }
    }

    #pragma mark - 表格的数据源方法
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return _dataList.count;
    }

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *ID = @"MyCell";
        VideoCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
        
        // 设置单元格
        Video *video = _dataList[indexPath.row];
        
        cell.videoTitleLabel.text = video.name;
        cell.teacherLabel.text = video.teacher;
        cell.lengthLabel.text = video.lengthStr;
        
        // 设置图像
        // 完整的URL
        NSString *imageURLStr = [NSString stringWithFormat:@"%@%@", kBaseURL, video.imageURL];
        NSURL *url = [NSURL URLWithString:imageURLStr];
        [cell.icon setImageWithURL:url placeholderImage:_placeHolderImage];
        
        return cell;
    }

    #pragma mark - 数据加载方法
    - (void)loadJSON
    {
        // 1. 从服务器获取数据 GET
        // 1) url
        NSURL *url = [NSURL URLWithString:@"http://192.168.3.251/~apple/itcast/videos.php?format=json"];
        // 2) request
        NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:2.0f];
        
        // 3) 连接同步,可以让用户先有内容可看
        NSError *error;
        // NSData存放的是二进制的数据
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
        
        // 判断返回结果
        if (data != nil) {
            // 正常返回数据
    //        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    //        NSLog(@"%@", result);
            
            // 反序列化
            NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
            
            NSLog(@"%@", array);
            // 技巧,从网络上接收到JSON,为了方便阅读,可以将其反序列化之后,保存至文件
            [array writeToFile:@"/Users/apple/Desktop/123.plist" atomically:YES];
            
            // 将数据转换成模型,并保存至表格需要的数组中
            NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:array.count];
            
            for (NSDictionary *dict in array) {
                Video *video = [[Video alloc] init];
                
                [video setValuesForKeysWithDictionary:dict];
                
                [arrayM addObject:video];
            }
            
            _dataList = arrayM;
        } else if (error == nil) {
            NSLog(@"返回空数据");
        } else {
            NSLog(@"%@", error.localizedDescription);
        }
    }

    #pragma mark 解析XML
    - (void)loadXML
    {
        // 1. 从服务器获取数据 GET
        // 1) url
        NSURL *url = [NSURL URLWithString:@"http://192.168.3.251/~apple/itcast/videos.php?format=xml"];
        // 2) request
        NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:2.0f];
        
        // 3) 连接同步,可以让用户先有内容可看
        NSError *error;
        // NSData存放的是二进制的数据
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
        
        // 2. XML解析
        // 1) 解析器
        NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
        // 2) 设置代理
        parser.delegate = self;
        
        // 3)开始解析
        [parser parse];
    }

    #pragma mark - XML解析方法
    // 1. 开始解析文档,在这里做初始化工作
    - (void)parserDidStartDocument:(NSXMLParser *)parser
    {
        NSLog(@"开始解析文档");
        // 数组还没有被初始化,初始化数组
        _dataList = [NSMutableArray array];
        
        _elementString = [NSMutableString string];
    }

    // 2.3.4会循环执行,一直到XML文档解析完毕
    // 2. 解析一个节点
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
    {
        NSLog(@"节点开始 %@ %@", elementName, attributeDict);
        
        if ([elementName isEqualToString:@"video"]) {
            // 新建一个视频模型对象
            _currentVideo = [[Video alloc] init];
            
            // 取视频ID
            _currentVideo.videoId = [attributeDict[@"videoId"] integerValue];
        }
        
        // 清空拼接字符串
        [_elementString setString:@""];
    }

    // 3. 查找节点内容,可能会多次
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
    {
        NSLog(@"开始查找内容 %@", string);
        // 拼接字符串
        [_elementString appendString:string];
    }

    // 4. 节点完成
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
    {
        NSLog(@"节点完成 %@ %p", elementName, _elementString);
        
        NSString *result = [NSString stringWithString:_elementString];
        
        if ([elementName isEqualToString:@"video"]) {
            // 对象的属性填充完毕,添加到数组
            [_dataList addObject:_currentVideo];
        } else if ([elementName isEqualToString:@"length"]) {
            _currentVideo.length = [result integerValue];
        } else if (![elementName isEqualToString:@"videos"]) {
            // 利用KVC给字符串类型的属性赋值
            [_currentVideo setValue:result forKey:elementName];
        }
        
    //    else if ([elementName isEqualToString:@"name"]) {
    //        _currentVideo.name = result;
    //    } else if ([elementName isEqualToString:@"length"]) {
    //        _currentVideo.length = [result integerValue];
    //    } else if ([elementName isEqualToString:@"videoURL"]) {
    //        _currentVideo.videoURL = result;
    //    } else if ([elementName isEqualToString:@"imageURL"]) {
    //        _currentVideo.imageURL = result;
    //    } else if ([elementName isEqualToString:@"desc"]) {
    //        _currentVideo.desc = result;
    //    } else if ([elementName isEqualToString:@"teacher"]) {
    //        _currentVideo.teacher = result;
    //    }
    }

    // 5. 解析完成,做收尾工作
    - (void)parserDidEndDocument:(NSXMLParser *)parser
    {
        NSLog(@"解析完成");
        
        NSLog(@"%@", _dataList);
    }

    // 6. 解析出错,清理中间数据
    - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
    {
        NSLog(@"%@", parseError.localizedDescription);
        
        // 一旦解析发生错误,需要把解析过程中生成的记录全部清除,以免造成不必要的麻烦
        [_dataList removeAllObjects];
    }

    @end

  • 相关阅读:
    IMail不能发送邮件的解决方法
    asp.net防止刷新重新提交触发后台事件的方法
    你的网站被“白名单”了吗?
    网站权限引起的504错误的问题
    asp.net Web Service请求因 HTTP 状态 400 失败: Bad Request的原因
    对现有数据库的表做分区的方法
    测试 Cookie在不同浏览器内容长度限制的测试
    Thinkphp框架中使用memcache缓存的方法
    替换手机号中间数字为*号或隐藏IP最后位
    linux mysql 操作命令
  • 原文地址:https://www.cnblogs.com/mcj-coding/p/3558572.html
Copyright © 2020-2023  润新知