前言
- 本文是解析 XML(用XML语言写的数据) 和 JSON格式的数据
-
在此声明:XML是一种语言,JSON是一种数据格式
一.解析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方法
JSON数据转成OC对象的详情代码2:
- 注意:创建task使用的是dataTaskWithURL方法
OC对象转成JSON数据的详情代码:
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
上述代码截图
二.解析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数据的区别
解析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