JSON和XML的复杂解析

一 JSON

1 JSON的基本概念
1 ) JSON是一种轻量级的数据格式,一般用于数据交互
2 ) JSON的格式很像OC中的字典和数组
3 ) 要想从JSON中挖掘具体数据,得对JSON进行解析

二 JSON解析数据

1 JSON转OC对象,解析(反序列化)
2 相关代码 :
#pragma mark - JSON转化为OC
//反序列化
- (void)jsonToOc
{
    //确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=JSON"];

    //创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    //创建会话
    NSURLSession *session = [NSURLSession sharedSession];

    //设置task
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        /*
         NSJSONReadingMutableContainers = (1UL << 0) 得到的字典或者是数组是可变的
         NSJSONReadingMutableLeaves = (1UL << 1),内部的字符串也是可变的
         !!!!NSJSONReadingAllowFragments = (1UL << 2)得到的数据类型最外层既不是字典也不是数组
         kNilOptions 0 默认可以传0 性能最好
         */
        //解析文件
        id obj = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

        //打印出解析的文件
        NSLog(@"%@------%@",obj,[obj class]);

    }];

    //执行task
    [dataTask resume];
}
3 OC对象转JSON,解析(序列化)
注意 : 转的时候需要做出判断,判断OC对象符不符合转JSON的条件
4 相关代码:
#pragma mark - 序列化
- (void)ocToJson
{
    //创建oc格式(字典)
//    NSDictionary *obj = @{@"name":@"xiaoming",
//                          @"age":@"ten"
//                          };

    //创建oc格式(数组)
    NSArray *obj = @[@122,@3222,@22225];

    //创建一个oc字符串
//    NSString *obj = @"abcd";

    //OC---->JSON需要作出判断
    if ([NSJSONSerialization isValidJSONObject:obj]) {

        /*
         oc---->json条件
         - Top level object is an NSArray or NSDictionary
         1)最外层必须是数组或者是字典
         - All objects are NSString, NSNumber, NSArray, NSDictionary, or NSNull
         2)所有的对象必须是NSString, NSNumber, NSArray, NSDictionary, or NSNull
         - All dictionary keys are NSStrings
         3)字典里面所有的key都必须是字符串
         - NSNumbers are not NaN or infinity
         4)NSNumber必须是正规的而且不能死无穷大
         */
        //转JSON
        NSData *data = [NSJSONSerialization dataWithJSONObject:obj options:kNilOptions error:nil];

        //打印出JSON数据
        NSLog(@"%@----%@",obj,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }else{
        NSLog(@"该数据不支持转换为JSON");
    }
}
5 写数据
目的 : 将plist文件转为JSON格式
相关代码 :
#pragma mark - 写数据

- (void)plistToJson
{
    //读取plist文件

    NSArray *arrayM = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];

    //oc--->Json
    NSData *data = [NSJSONSerialization dataWithJSONObject:arrayM options:kNilOptions error:nil];

    //将Json文件写入另外一个文件中
    [data writeToFile:@"/Users/xiaofeng/Desktop/apps2.JSON" atomically:YES];
}

三 复杂的JSON解析

案例的大致功能图:

这里写图片描述

涉及到知识点:
1> JSON解析
2> 利用MJExtension框架实现模型中属性的替换
3> 利用SDWebImage布局cell中的子控件
4> 回到主线程刷新UI
5> 拼接视频下载的完整路径
1 根据提供的相应的接口,下载好的JSON数据
/*
 {"videos":[{"id":1,"image":"resources/images/minion_01.png","length":10,"name":"小黄人 第01部","url":"resources/videos/minion_01.mp4"},{"id":2,"image":"resources/images/minion_02.png","length":12,"name":"小黄人 第02部","url":"resources/videos/minion_02.mp4"},{"id":3,"image":"resources/images/minion_03.png","length":14,"name":"小黄人 第03部","url":"resources/videos/minion_03.mp4"},{"id":4,"image":"resources/images/minion_04.png","length":16,"name":"小黄人 第04部","url":"resources/videos/minion_04.mp4"},{"id":5,"image":"resources/images/minion_05.png","length":18,"name":"小黄人 第05部","url":"resources/videos/minion_05.mp4"},{"id":6,"image":"resources/images/minion_06.png","length":20,"name":"小黄人 第06部","url":"resources/videos/minion_06.mp4"}]
 */
注意: 从下载的JSON数据不难看出文件的类型是由字典组成的,JSON里面找一组字典作为写在模型中的属性模型中的属性代码.
代码 :
//图像
@property (nonatomic, strong) NSString *image;

//片长
@property (nonatomic, assign) NSString *length;

//片名
@property (nonatomic, strong) NSString *name;

//影片来源
@property (nonatomic, strong) NSString *url;

//id
@property (nonatomic, strong) NSString *ID;
2 由于在提供的JSON属性中出现了id类型,有点和系统中的id一样,看起来别扭,其实将id作为属性写入写没什么问题.但是我们为了改善这点,就用MJ的一个框架来转化.
//告诉框架,修改了属性,并且说明修改的值和未修改之前值得对应关系
    [XFVidoeItem mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
        return @{
                 @"ID":@"id",
                 };
    }];
3 发送请求的步骤:
3.1> 确定请求路径
//确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=JSON"];
3.2> 创建可变的请求对象
//创建可变的请求对象
    NSMutableURLRequest *request  = [NSMutableURLRequest requestWithURL:url];
3.3> 设置会话
//设置会话
    NSURLSession *session = [NSURLSession sharedSession];
3.4> 创建task任务–>解析JSON文件—->用mj创建模型并且存入数组中—->回到主线程刷新UI
//创建task任务
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        //解析Json文件
        //由于知道了Json文件的类型,所以直接用字典来接收
        NSDictionary *dictM = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
        //遍历根数据里面的字数据
        self.videos = [XFVidoeItem mj_objectArrayWithKeyValuesArray:dictM[@"videos"]];
        //回到主线程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{

            [self.tableView reloadData]; 
        });     
    }];
3.5> 开始执行任务
//开始执行
    [dataTask resume];
4 自定义cell—>重写系统布局子控件的方法
- (void)layoutSubviews {
    [super layoutSubviews];

    self.imageView.frame = CGRectMake(5,5,80,40);
    float limgW =  self.imageView.image.size.width;
    if(limgW > 0) {
        self.textLabel.frame = CGRectMake(90,self.textLabel.frame.origin.y,self.textLabel.frame.size.width,self.textLabel.frame.size.height);
        self.detailTextLabel.frame = CGRectMake(90,self.detailTextLabel.frame.origin.y,self.detailTextLabel.frame.size.width,self.detailTextLabel.frame.size.height);
    }
}
5 tableView的数据源方法(只标上重点部分)
#pragma mark - 每行cell的内容

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //注册
    static NSString *ID = @"cell";

    //创建cell
    XFVidoeCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    //设置数据(取出行)
    XFVidoeItem *vidoeItem = self.videos[indexPath.row];

    //设置标题一
    cell.textLabel.text = vidoeItem.name;
    //设置播放时间
    cell.detailTextLabel.text = [NSString stringWithFormat:@"播放时间:%@秒",vidoeItem.length];

    //设置影片(拼接路径)BaseURL定义的宏,代表了文件的接口
    NSURL *url = [NSURL URLWithString:[BaseURL stringByAppendingPathComponent:vidoeItem.image]];

    //设置占位图
    [cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"/Users/xiaofeng/Desktop/Snip20160320_2.png"]];

    //返回设置好的cell
    return cell;
}
6 注意由于提供的视频的下载只有响应体部分,还有接口部分省略了,那么由于是下载视频是模型中的url,所以需要我们自己拼接.
7 用户点击某行cell,播放出相应的视频
#pragma mark - 点击某行cell播放视频
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //拿到某行cell
    XFVidoeItem *vidoeItem = self.videos[indexPath.row];

    //播放该cell
    NSString *urlStr = [BaseURL stringByAppendingPathComponent:vidoeItem.url];

    //创建视频播放器
    MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:urlStr]];

    //modol出控制器
    [self presentViewController:vc animated:YES completion:nil];
}

四 复杂的XML解析数据方法一

1 大部分方法和普通的JSON解析数据是一样的,只需要将JSON部分的代码改为XML解析的代码就可以,主要修改创建task任务的部分代码.
   //告诉框架,修改了属性,并且说明修改的值和未修改之前值得对应关系
    [XFVidoeItem mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
        return @{
                 @"ID":@"id",
                 };
    }];


    //确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"];
    //创建请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    //设置会话
    NSURLSession *session = [NSURLSession sharedSession];
    //创建task
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        //创建XML解析器
        NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

        //设置代理
        parser.delegate = self;

        //开始解析,这个方法本身是阻塞的,需要解析完XML才会刷新tableView,所以不会出现先刷新在加载的可能性
        [parser parse];

        //回到主线程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{

            [self.tableView reloadData];

        });

    }];

    //开始执行
    [dataTask resume];
}
2 与JSON解析不同的部分是在XML解析数据是在代理方法中完成解析的,下面是数据解析的代码部分
//开始解析某个元素
- (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;
    }

    //创建一个模型
    XFVidoeItem *item = [[XFVidoeItem alloc] init];
    //字典转模型
    [item mj_setKeyValues:attributeDict];

    [self.videos addObject:item];
}
注意部分: 会不会出现当XML还没有解析完毕,就开始刷新tableView呢?不会,因为调用代理的那个方法本身是阻塞的,需要在XML都解析完毕,才会刷新.

五 复杂的XML解析数据方法二—>用GDataXML框架解析(基本没人用)

1 导入头文件GDataXMLNode.h
2 在创建task任务的方法中写入下面代码就可以完成用框架对XML的解析
    //加载整个XML文件
        GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:kNilOptions error:nil];

        //拿到根元素,得到根元素内部所有为video的属性
        NSArray *eles = [doc.rootElement elementsForName:@"video"];

        //遍历所有的子元素
        for (GDataXMLElement *ele in eles) {
            //创建一个模型,给模型中的属性赋值
            XFVidoeItem *item = [[XFVidoeItem alloc] init];

            //给属性赋值
            item.name = [ele attributeForName:@"name"].stringValue;
            item.image = [ele attributeForName:@"image"].stringValue;
            item.ID = [ele attributeForName:@"id"].stringValue;
            item.length = [ele attributeForName:@"length"].stringValue;
            item.url = [ele attributeForName:@"url"].stringValue;

            //将赋值好的模型加入到装模型的可变数组中
            [self.videos addObject:item];
        }
3 配置Xcode,因为如果就写上上面的代码部分,运行起来是会报错的,所以需要配置xcode,在开发的时候一般都是用苹果提供的类来解析XML,下面是xcode配置信息.只要将图片上的地方配置好了,也是能达到解析XML的目的.
图一:

这里写图片描述

图二:

这里写图片描述

图三:

这里写图片描述

4 需要填写的信息来源地:
图一:

这里写图片描述

图二:

这里写图片描述

六 结尾

1 以上就是JSON和XML解析的部分解释和代码,或许不完全.这里要重申一次,一般在开发当中,从服务器返回的数据一般都是JSON数据,所以还是需要重点掌握以下.但是XML解析也是需要知道的,这里面有什么不足的地方,希望大家给我留言,谢谢!!!!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值