解析JSON数据,解析XML


前言
  • 本文是解析 XML(用XML语言写的数据) 和 JSON格式的数据
  • 在此声明:XML是一种语言,JSON是一种数据格式


    30-01.png

一.解析JSON格式的数据(即:反序列化)


利用NSJSONSerialization对JSON格式的数据进行解析
当数据结构为 {key:value,key:value,...}的键值对的结构时,可以解析成NSDictionary.
当数据结构为 ["a","b","c",...]结构时,可以解析成NSArray.

NSJSONSerialization类中的两个方法
  • JSON数据转成OC对象(反序列化)--->解析JSON格式的数据就用这个方法
  • 反序列化目的(通俗理解):转换成OC格式,对于学习OC语法的人来说,能容易看懂
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
  • OC对象转成JSON数据(序列化)
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;


序列化与反序列化:
  • 序列化:在传输之前,将对象转换成有序的字符串或者二进制数据流
  • 反序列化:将已经接收到的字符串或者二进制数据流 转换成对象或者数组,以便程序访问

注意:
  • Json本质上是具有特殊格式的字符串
  • 解析Json的过程就是反序列化的过程
  • 在线代码格式化:http://tool.oschina.net/codeformat/json
  • 区分字典和数组
  • 字典{:,:,}就是key:vaule的形式,既有冒号又有逗号
  • 数组[,,,,]中都是逗号隔开

JSON数据转成OC对象的详情代码1:
  • 注意:创建task使用的是dataTaskWithRequest方法
30-04.png

JSON数据转成OC对象的详情代码2:
  • 注意:创建task使用的是dataTaskWithURL方法
30-05.png

OC对象转成JSON数据的详情代码:
30-03.png

JSON解析综合练习(用NSJSONSerialization创建JSON解析器)
  • 注意区分里面的面向字典开发和面向模型
#import "ViewController.h"
#import "UIImageView+WebCache.h"
#import "ZBTableViewCell.h"
#import "ZBVideo.h"
#import <MediaPlayer/MediaPlayer.h>
#import "MJExtension.h"

#define BaseURL @"http://120.25.226.186:32812"

@interface ViewController ()
/** 数据源*/
@property (nonatomic ,strong) NSArray *videos;
@end

@implementation ViewController

#pragma mark --------------------
#pragma mark Life Cycle
- (void)viewDidLoad
{
    [super viewDidLoad];
   //有了这句代码,模型中的ID本质对应着的是数据库中的id
    //0.告诉框架新值和旧值的对应关系
    [ZBVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
        return @{
                 @"ID":@"id",
                 };
        
    }];
    //1.发送请求
    [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=JSON"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //2.解析数据 (NSJSONSerialization是解析数据的标志)
        NSDictionary *dictM  = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
        NSLog(@"%@",dictM);
        
        //复杂json
        //1)写plist文件到桌面
        [dictM writeToFile:@"/Users/zhangbin/Desktop/video.plist" atomically:YES];
        //2)json在线格式化 http://tool.oschina.net/codeformat/json
        
        //3.设置tableView的数据源(把服务器返回给我们的dictM进行转换,作为tableView的数据源,显示在模拟器上)
        
        /*
         **************************************面向字典开发**************************************
        //a.面向字典开发
        //self.videos = dictM[@"videos"];
         
         **************************************面向模型开发**************************************
        //b.面向模型开发
        NSArray *arrayM = dictM[@"videos"];
        //字典数组---->模型数据
        NSMutableArray *arr = [NSMutableArray array];
        for (NSDictionary *dict  in arrayM) {
            [arr addObject:[ZBVideo videWithDict:dict]];
        }
        self.videos = arr;
         
         */
        //************************************面向模型开发**************************************
        //c.利用MJ的框架,进行面向模型开发(只需要在模型类中声明对应的属性,不需要声明和实现接口方法,并且之前在外界字典转模型需要很多行代码,这里只需一行代码就搞定)
        //dictM[@"videos"]
        self.videos = [ZBVideo mj_objectArrayWithKeyValuesArray:dictM[@"videos"]];
        
        //4.刷新tableView
        dispatch_async(dispatch_get_main_queue(), ^{
             [self.tableView reloadData];//当前类必须继承UITableViewController,并且在故事板中设置关联的类就是当前的控制器。否则这行代码打不出来,会提示错误
        });
       
        
    }] resume];
}

#pragma mark --------------------
#pragma mark UITableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.videos.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"video";
    //1.创建cell
    ZBTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    
    /*
     **************************************面向字典开发**************************************
     面向字典开发,设置数据的代码(取出字典中的key中才能拿到数据,例如dictM[@"length"])
     
    //NSDictionary *dictM = self.videos[indexPath.row];
    //2.2 设置标题
    cell.textLabel.text = dictM[@"name"];
    
    //2.3 设置子标题
    cell.detailTextLabel.text = [NSString stringWithFormat:@"播放时间:%@ 秒",dictM[@"length"]];
    
    //2.4 设置图标
    NSURL *url = [NSURL URLWithString:[BaseURL stringByAppendingPathComponent:dictM[@"image"]]];
    
    [cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20200808_28"]];

     */
    
    
    //**************************************面向模型开发**************************************
    //面向模型开发,设置数据的代码(直接从模型中访问属性即可拿到数据,例如ideoM.length)
    //2.1 获得该cell对应的数据
    ZBVideo *videoM = self.videos[indexPath.row];
    
    //2.2 设置标题
    cell.textLabel.text = videoM.name;
    
    //2.3 设置子标题
    cell.detailTextLabel.text = [NSString stringWithFormat:@"播放时间:%@ 秒",videoM.length];
    
    //2.4 设置图标 image是NSString类型的
    NSURL *url = [NSURL URLWithString:[BaseURL stringByAppendingPathComponent:videoM.image]];
    
    //占位图片,当网上的图片没下载当指定的cell的时候,用占位图片暂时顶替
    [cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20200808_28"]];
    
    NSLog(@"%@",videoM.ID);
    
    //3.返回cell
    return cell;
}

#pragma mark --------------------
#pragma mark UITableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    /* **************************************面向字典开发**************************************
     
    //1.拿到该cell对应的数据
    NSDictionary *dictM  = self.videos[indexPath.row];
    
    //播放该cell对应的视频
    NSString *urlStr = [BaseURL stringByAppendingPathComponent:dictM[@"url"]];
    */
    
    
    //**************************************面向模型开发**************************************
    //1.拿到该cell对应的数据
    ZBVideo *videoM  = self.videos[indexPath.row];
    
    //播放该cell对应的视频
    NSString *urlStr = [BaseURL stringByAppendingPathComponent:videoM.url];
    
    //2.创建视频播放控制器
    MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString:urlStr]];
    
    //3.弹出控制器
    [self presentViewController:vc animated:YES completion:nil];
                        
}
@end

上述代码截图
30-06.png

二.解析XML


解析XML的两种做法
  • NSXMLParser(适合大文件)
  • GDataXMLDocument(不适合大文件)

解析XML的做法一(用NSXMLParser创建XML解析器)

  • 注意:和JSON解析综合练习的区别:
  • 解析数据的代码不一样
  • 让控制器成为NSXMLParser的代理,代理名称为NSXMLParserDelegate
  • 字典转模型在代理方法中执行
#import "ViewController.h"
#import "UIImageView+WebCache.h"
#import "ZBTableViewCell.h"
#import "ZBVideo.h"
#import <MediaPlayer/MediaPlayer.h>
#import "MJExtension.h"

#define BaseURL @"http://120.25.226.186:32812"

@interface ViewController ()<NSXMLParserDelegate>
/** 数据源*/
@property (nonatomic ,strong) NSMutableArray *videos;
@end

@implementation ViewController

#pragma mark --------------------
#pragma mark lazy loading

-(NSMutableArray *)videos
{
    if (_videos == nil) {
        _videos = [NSMutableArray array];
    }
    return _videos;
}
#pragma mark --------------------
#pragma mark Life Cycle
- (void)viewDidLoad
{
    [super viewDidLoad];
   
    //0.告诉框架新值和旧值的对应关系
    [ZBVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
        return @{
                 @"ID":@"id",
                 };
        
    }];
    //1.发送请求
    [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //2.解析数据
        //2.1 创建XML解析器
        NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
        
        //2.2 设置代理
        parser.delegate = self;
        
        //2.3 开始解析,该方法本身是阻塞的
        [parser parse];
        
        //4.刷新tableView
        dispatch_async(dispatch_get_main_queue(), ^{
             [self.tableView reloadData];
        });
       
        
    }] resume];
}

#pragma mark --------------------
#pragma mark UITableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.videos.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"video";
    //1.创建cell
    ZBTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    //2.设置数据

    //2.1 获得该cell对应的数据
  
    ZBVideo *videoM = self.videos[indexPath.row];
    
    //2.2 设置标题
    cell.textLabel.text = videoM.name;
    
    //2.3 设置子标题
    cell.detailTextLabel.text = [NSString stringWithFormat:@"播放时间:%@ 秒",videoM.length];
    
    //2.4 设置图标
    NSURL *url = [NSURL URLWithString:[BaseURL stringByAppendingPathComponent:videoM.image]];
    
    [cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20200808_28"]];
    
    NSLog(@"%@",videoM.ID);
    
    //3.返回cell
    return cell;
}

#pragma mark --------------------
#pragma mark UITableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

    //1.拿到该cell对应的数据
    ZBVideo *videoM  = self.videos[indexPath.row];
    
    //播放该cell对应的视频
    NSString *urlStr = [BaseURL stringByAppendingPathComponent:videoM.url];
    
    //2.创建视频播放控制器
    MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString:urlStr]];
    
    //3.弹出控制器
    [self presentViewController:vc animated:YES completion:nil];
                        
}

#pragma mark --------------------
#pragma mark NSXMLParserDelegate
//1.开始解析XML文档
-(void)parserDidStartDocument:(NSXMLParser *)parser
{
    NSLog(@"%s",__func__);
}

//2.开始解析某个元素   attributeDict:存放着元素的属性
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict
{
     NSLog(@"%s--开始解析元素%@---\n%@",__func__,elementName,attributeDict);
    
    if ([elementName isEqualToString:@"videos"]) {
        //过滤根元素
        return;
    }
    ZBVideo *videoM = [[ZBVideo alloc]init];
    [videoM mj_setKeyValues:attributeDict];
    [self.videos addObject:videoM];//先调用videos的懒加载方法。再将模型装进大的数组中

}

//3.某个元素解析完毕
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
     NSLog(@"%s--结束%@元素的解析",__func__,elementName);
}

//4.整个XML文档都已经解析完毕
-(void)parserDidEndDocument:(NSXMLParser *)parser
{
    NSLog(@"%s",__func__);
}
@end


利用NSXMLParser解析XML和利用NSJSONSerialization解析JSON数据的区别
30-07.png
30-08.png
30-09.png

解析XML的做法二(用GDataXMLDocument创建XML解析器)
  • 注意:和NSXMLParser的区别:
    • 解析数据的代码不一样
    • 不需要设置代理
#import "ViewController.h"
#import "UIImageView+WebCache.h"
#import "ZBTableViewCell.h"
#import "ZBVideo.h"
#import <MediaPlayer/MediaPlayer.h>
#import "MJExtension.h"
#import "GDataXMLNode.h"

#define BaseURL @"http://120.25.226.186:32812"

@interface ViewController ()<NSXMLParserDelegate>
/** 数据源*/
@property (nonatomic ,strong) NSMutableArray *videos;
@end

@implementation ViewController

#pragma mark --------------------
#pragma mark lazy loading

-(NSMutableArray *)videos
{
    if (_videos == nil) {
        _videos = [NSMutableArray array];
    }
    return _videos;
}
#pragma mark --------------------
#pragma mark Life Cycle
- (void)viewDidLoad
{
    [super viewDidLoad];
   
    //有了这句代码,模型中的ID本质对应着的是数据库中的id
    
    //0.告诉框架新值和旧值的对应关系
    [ZBVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
        return @{
                 @"ID":@"id",
                 };
        
    }];
    //1.发送请求
    [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //2.解析数据
                //2.1 加载整个XML文档
        GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:data options:kNilOptions error:nil];
        
        //2.2 拿到根元素,得到根元素内部所有名称为video的属性
       NSArray *eles =  [doc.rootElement elementsForName:@"video"];
        
        //2.3 遍历所有的子元素,得到元素内部的属性数据
        for (GDataXMLElement *ele in eles) {
            ZBVideo *videoM = [[ZBVideo alloc]init];
            
            videoM.name = [ele attributeForName:@"name"].stringValue;
            videoM.image = [ele attributeForName:@"image"].stringValue;
            videoM.ID = [ele attributeForName:@"id"].stringValue;
            videoM.length = [ele attributeForName:@"length"].stringValue;
            videoM.url = [ele attributeForName:@"url"].stringValue;
            [self.videos addObject:videoM];
        }
        
        //4.刷新tableView
        dispatch_async(dispatch_get_main_queue(), ^{
             [self.tableView reloadData];
        });
       
        
    }] resume];
}

#pragma mark --------------------
#pragma mark UITableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.videos.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"video";
    //1.创建cell
    ZBTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    //2.设置数据

    //2.1 获得该cell对应的数据
  
    ZBVideo *videoM = self.videos[indexPath.row];
    
    //2.2 设置标题
    cell.textLabel.text = videoM.name;
    
    //2.3 设置子标题
    cell.detailTextLabel.text = [NSString stringWithFormat:@"播放时间:%@ 秒",videoM.length];
    
    //2.4 设置图标
    NSURL *url = [NSURL URLWithString:[BaseURL stringByAppendingPathComponent:videoM.image]];
    
    [cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20200808_28"]];
    
   
    NSLog(@"%@",videoM.ID);
    
    //3.返回cell
    return cell;
}

#pragma mark --------------------
#pragma mark UITableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //1.拿到该cell对应的数据
    ZBVideo *videoM  = self.videos[indexPath.row];
    
    //播放该cell对应的视频
    NSString *urlStr = [BaseURL stringByAppendingPathComponent:videoM.url];
    
    //2.创建视频播放控制器
    MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString:urlStr]];
    
    //3.弹出控制器
    [self presentViewController:vc animated:YES completion:nil];
                        
}

@end


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容