JSON
- 
JSON是一种轻量级的数据格式,一般用于数据交互。 - 服务器返回给客户端的数据,一般都是
JSON格式或者XML格式(文件下载除外)。 - 
JSON的格式很像OC中的字典和数组。 
{"name" : "jack", "age" : 10}
{"names" : ["jack", "rose", "jim"]}
- 
标准JSON格式的
注意点:key必须用双引号。 - 
要想从
JSON中挖掘出具体数据,得对JSON进行解析。 
JSON转换为OC数据类型
- 
JSON – OC转换对照表 
| JSON | OC | 
|---|---|
| 大括号 { } | NSDictionary | 
| 中括号 [ ] | NSArray | 
双引号" "
 | 
NSString | 
| 数字 10、10.8 | NSNumber | 
- 
JSON – OC转换练习
json.png
 - 
JSON解析方案 
- 在
 iOS中,JSON的常见解析方案有4种.
a、第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差) 。
b、苹果原生(自带):NSJSONSerialization(性能最好)。
- 
NSJSONSerialization的常见方法: - 
JSON数据 -->OC对象(字典|数组)[反序列化处理] 
+(id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
//JSONData - >OC中的对象(字典|数组) [反序列化处理]
-(void)jsonToOC
{
    [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=JSON"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //处理服务器返回的数据
        //01 JSONData - > NSString
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
        
        //02 JSONData - >OC中的对象(字典|数组)
        /* 参数说明
         *
         * 第一个参数:要解析的json数据
         * 第二个参数:解析数据时候附加的选项 默认传0
         * NSJSONReadingMutableContainers = (1UL << 0),  得到的对象是可变的
         * NSJSONReadingMutableLeaves = (1UL << 1),      得到的对象中字符串是可变的
         * NSJSONReadingAllowFragments = (1UL << 2)      ! 当返回的对象既不是字典也不是数组的时候(null)
         * 第三个参数:错误信息
         */
        NSDictionary * obj = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
        
        NSLog(@"%@--%@",[obj class],obj);
        
        /*
         [NSNull null]; //空对象
         nil //空
         //NSNull *null = [NSNull null];
         //NSDictionary *dict = @{@"name":@"xiaoma",@"age":[NSNull null]};
         */
    }] resume];
}
- 
OC对象(字典|数组) -->JSON数据[序列化处理] 
+(NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
//OC中的对象(字典|数组) - >JSONData[序列化处理]
-(void)ocToJSON
{
    //注意:并不是所有的OC对象都支持转换为JSON
    
    //NSDictionary *dict = @{@"name":@"xiaoming",@"age":@25};
    //NSArray *array  = @[@"wen",@"xioamage",@"dangdang"];
    NSString *string = @"我恨你!";
    
    /*
     - 最外层的对象必须是 an NSArray or NSDictionary
     - 字典或数组中所有的元素只能是NSString, NSNumber, NSArray, NSDictionary, or NSNull
     - 字典中所有的key都必须是 NSStrings
     - NSNumbers 是标准的并且不能是无穷大
     */
    if (![NSJSONSerialization isValidJSONObject:string]) {
        NSLog(@"该对象不支持转换");
        return;
    }
    
    /* 参数说明
     *
     * 第一个参数:要序列化的OC对象
     * 第二个参数:选项
     */
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:string options:kNilOptions error:nil];
    
    NSLog(@"%@",[[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding]);
}
- 将数据写成
Json格式的文件 
-(void)other
{
    //01 加载数据
    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];
    
    //02 把数据以json的方式来保存
    //写plist文件
    //[array writeToFile:@"/Users/xiaomage/Desktop/123.plist" atomically:YES];
    //写json文件 错误的写法
    //[array writeToFile:@"/Users/xiaomage/Desktop/123.json" atomically:YES];
    //需要先把OC对象转换成jsonData 然后再写文件
    
    //NSJSONWritingPrettyPrinted 排版美化结构
   NSData *jsonData = [NSJSONSerialization dataWithJSONObject:array options:NSJSONWritingPrettyPrinted error:nil];
    
    //03 写文件
    [jsonData writeToFile:@"/Users/nana/Desktop/123.json" atomically:YES];
}
- 
Json文件中的数据转换成OC对象 
-(void)other2
{
    //01 加载数据
    NSData *jsonData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"123.json" ofType:nil]];
    
    //02 jsonData - >OC对象
    NSArray *array = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:nil];
    
    //03 打印输出
    NSLog(@"%@",array);
}
- 解析来自服务器的
JSON 
json01.png
XML
- 什么是
XML? 
a.全称是E
xtensibleMarkupLanguage,译作“可扩展标记语言”。
b.跟JSON一样,也是常用的一种用于交互的数据格式。
c.一般也叫XML文档(XML Document)。
- 
XML举例: 
<videos>
<video name="小黄人 第01部" length="30" />
<video name="小黄人 第02部" length="19" />
<video name="小黄人 第03部" length="33" />
</videos>
- XML语法:
 
- 一个常见的XML文档一般由以下部分组成:
 
1.文档声明
2.元素(Element)
3.属性(Attribute)
- 1.
XML语法 – 文档声明 
1.1、在XML文档的最前面,必须编写一个文档声明,用来声明XML文档的类型
最简单的声明
<?xml version="1.0" ?>
1.2、用encoding属性说明文档的字符编码
<?xml version="1.0" encoding="UTF-8" ?>
- 2.
XML语法 – 元素(Element) 
- 2.1、一个元素包括了开始标签和结束标签
 
a.拥有内容的元素:<video>小黄人</video>
b.没有内容的元素:<video></video>
c.没有内容的元素简写:<video/>- 2.2、一个元素
 可以嵌套若干个子元素(不能出现交叉嵌套)
<videos>
<video>
<name>小黄人 第01部</name>
<length>30</length>
</video>
</videos>- 2.3、规范的
 XML文档最多只有1个根元素,其他元素都是根元素的子孙元素。
XML语法 –元素的注意:
XML中的所有空格和换行,都会当做具体内容处理。
下面两个元素的内容是不一样的:
第1个
<video>小黄人</video>
第2个
<video>
小黄人
</video>
- 3.
XML语法 – 属性(Attribute) 
- 3.1、 一个元素可以拥有多个属性:
 
a.<videoname="小黄人 第01部"length="30" />。
b.video元素拥有name和length两个属性。
c.属性值必须用双引号""或者单引号''括住。
- 3.2、实际上,
 属性表示的信息也可以用子元素来表示,比如
<video>
<name>小黄人 第01部</name>
<length>30</length>
</video>
XML解析
- 要想从XML中提取有用的信息,必须得学会解析XML
 
a、提取
name元素里面的内容。
<name>小黄人 第01部</name>
b、提取video元素中name和length属性的值。
<videoname="小黄人 第01部"length="30" />
- XML的解析方式有2种
 
DOM:一次性将整个XML文档加载进内存,比较适合解析小文件。
SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件。
- iOS中的
XML解析 
- 在iOS中,解析
 XML的手段有很多:
1、苹果原生
NSXMLParser:SAX方式解析,使用简单。
2、第三方框架
libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析。
GDataXML:DOM方式解析,由libxml2。
XML解析方式的选择建议:
大文件:NSXMLParser、libxml2。
小文件:GDataXML、NSXMLParser、libxml2。
-NSXMLParser
- 使用步骤
 
01.传入XML数据,创建解析器
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
02.设置代理,监听解析过程
parser.delegate = self;
03.开始解析
[parser parse];
- 
NSXMLParser采取的是SAX方式解析,特点是事件驱动,下面情况都会通知代理。 
1、当扫描到
文档(Document)的开始与结束。
2、当扫描到元素(Element)的开始与结束。
NSXMLParserDelegate
01、当
扫描到文档的开始时调用(开始解析)
- (void)parserDidStartDocument:(NSXMLParser *)parser;
02、当
扫描到文档的结束时调用(解析完毕)
- (void)parserDidEndDocument:(NSXMLParser *)parser;
03、当
扫描到元素的开始时调用(attributeDict存放着元素的属性)
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
04、当
扫描到元素的结束时调用
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
#import "ViewController.h"
#import "UIImageView+WebCache.h"
#import <MediaPlayer/MediaPlayer.h>
#import "XMGVideo.h"
#import "MJExtension.h"
#define KbaseUrlString @"http://120.25.226.186:32812/"
@interface ViewController ()<NSXMLParserDelegate>
@property (nonatomic,strong) NSMutableArray *videos;
@end
@implementation ViewController
-(NSMutableArray *)videos
{
    if (_videos == nil) {
        _videos = [NSMutableArray array];
    }
    return _videos;
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //01 确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"];
    
    //02 创建会话对象
    NSURLSession *session = [NSURLSession sharedSession];
    
    //03 创建TASK 执行Task
    [[session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //在进行字典转模型之前手动的设置替换 ID - id
        [XMGVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
            
            return @{@"ID":@"id"};
        
        }];
        
        //04 解析服务器返回的数据
        //001 创建XML解析器(NSXMLParser-SAX)
        NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
        
        //002 设置代理
        parser.delegate = self;
        
        //003 开始解析 本身是阻塞式的
        [parser parse];
        
        //06 刷新UI
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            
            [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
{
    //01 获得cell
    static NSString *ID = @"video";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    //02 设置cell
    //001 得到该行cell对应的数据
    XMGVideo *videoM = self.videos[indexPath.row];
    //002 设置标题和子标题
    cell.textLabel.text = videoM.name;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"播放时间:%@",videoM.length];
    //003 设置图片
   
    NSString *urlString = [KbaseUrlString stringByAppendingString:videoM.image];
    NSURL *url = [NSURL URLWithString:urlString];
    
    [cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20161125_180"]];
    
    NSLog(@"%@",videoM.ID);
    //03 返回cell
    return cell;
}
#pragma mark -----------------------
#pragma mark UItableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //01 得到对应的数据
    XMGVideo *videoM = self.videos[indexPath.row];
    
    NSString *urlString = [KbaseUrlString stringByAppendingString:videoM.url];
    NSURL *url = [NSURL URLWithString:urlString];
    
    //02 创建视频播放控制器
    MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:url];
    
    //03 弹出播放器
    [self presentViewController:vc animated:YES completion:nil];
}
#pragma mark -----------------------
#pragma mark NSXMLParserDelegate
//01 开始解析XML文档的时候调用
-(void)parserDidStartDocument:(NSXMLParser *)parser
{
    NSLog(@"parserDidStartDocument");
}
//02 开始解析XML文档中某个元素的时候调用 该方法会调用多次
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict
{
    NSLog(@"didStartElement--开始解析的元素名称:%@\n%@",elementName,attributeDict);
    
    //过滤掉根元素
    if ([elementName isEqualToString:@"videos"]) {
        return;
    }
    
    //001 把字典转换为模型
    XMGVideo *video =  [XMGVideo mj_objectWithKeyValues:attributeDict];
    
    //002 把模型添加到全局的可变数组中保存起来
    [self.videos addObject:video];
}
//03 某个元素解析完毕之后会调用该方法
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    NSLog(@"didEndElement");
}
//04 整个XML文档解析完毕
-(void)parserDidEndDocument:(NSXMLParser *)parser
{
    NSLog(@"parserDidEndDocument");
}
@end
GDataXML
- 
GDataXML基于libxml2库,得做以下配置: 
1、导入
libxml2库
xml01.png
2、设置
libxml2的头文件搜索路径(为了能找到libxml2库的所有头文件)
a、在Head Search Path中加入/usr/include/libxml2。
3、设置链接参数(自动链接
libxml2库)
a、在Other Linker Flags中加入-lxml2。
4、由于
GDataXML是非ARC的,因此得设置编译参数
xml02.png
- 
GDataXML使用 
1、
GDataXML中常用的类:
1.1、GDataXMLDocument:代表整个XML文档
1、 把整个XML文档加载进内存
GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:data options:kNilOptions error:nil];
2、
GDataXMLElement
2.1、代表文档中的每个元素。
2.2、使用attributeForName:方法可以获得属性值。
2 先得到根元素,然后获取根元素内部所有名称为video的子元素
GDataXMLElement *rootElement = doc.rootElement;
   NSArray *eles = [rootElement elementsForName:@"video"];
        
        //03 遍历整个子元素数组,然后得到数组中每个元素的内部属性
        for (GDataXMLElement *ele in eles) {
            
            //创建模型
            XMGVideo *video = [[XMGVideo alloc]init];
            
            //得到子元素的属性
            video.name = [ele attributeForName:@"name"].stringValue;
            video.ID =[ele attributeForName:@"id"].stringValue;
            video.length =[ele attributeForName:@"length"].stringValue;
            video.image = [ele attributeForName:@"image"].stringValue;
            video.url = [ele attributeForName:@"url"].stringValue;
            
            //把模型保存到数据源
            [self.videos addObject:video];
        }
示例代码:
#import "ViewController.h"
#import "UIImageView+WebCache.h"
#import <MediaPlayer/MediaPlayer.h>
#import "XMGVideo.h"
#import "MJExtension.h"
#import "GDataXMLNode.h"
#define KbaseUrlString @"http://120.25.226.186:32812/"
@interface ViewController ()
@property (nonatomic,strong) NSMutableArray *videos;
@end
@implementation ViewController
-(NSMutableArray *)videos
{
    if (_videos == nil) {
        _videos = [NSMutableArray array];
    }
    return _videos;
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //01 确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"];
    
    //02 创建会话对象
    NSURLSession *session = [NSURLSession sharedSession];
    
    //03 创建TASK 执行Task
    [[session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //在进行字典转模型之前手动的设置替换 ID - id
        [XMGVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
            return @{@"ID":@"id"};
        }];
        
        //04 解析服务器返回的数据 XML
        
        //001 把整个XML文档加载进内存
        GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:data options:kNilOptions error:nil];
        
        //002 先得到根元素,然后获取根元素内部所有名称为video的子元素
        GDataXMLElement *rootElement = doc.rootElement;
        
        NSArray *eles = [rootElement elementsForName:@"video"];
        
        //03 遍历整个子元素数组,然后得到数组中每个元素的内部属性
        for (GDataXMLElement *ele in eles) {
            
            //创建模型
            XMGVideo *video = [[XMGVideo alloc]init];
            
            //得到子元素的属性
            video.name = [ele attributeForName:@"name"].stringValue;
            video.ID =[ele attributeForName:@"id"].stringValue;
            video.length =[ele attributeForName:@"length"].stringValue;
            video.image = [ele attributeForName:@"image"].stringValue;
            video.url = [ele attributeForName:@"url"].stringValue;
            
            //把模型保存到数据源
            [self.videos addObject:video];
        }
        
        //06 回到主线程刷新UI
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [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
{
    //01 获得cell
    static NSString *ID = @"video";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    //02 设置cell
    //001 得到该行cell对应的数据
    XMGVideo *videoM = self.videos[indexPath.row];
    //002 设置标题和子标题
    cell.textLabel.text = videoM.name;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"播放时间:%@",videoM.length];
    //003 设置图片
   
    NSString *urlString = [KbaseUrlString stringByAppendingString:videoM.image];
    NSURL *url = [NSURL URLWithString:urlString];
    
    [cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20161125_180"]];
    
    NSLog(@"%@",videoM.ID);
    //03 返回cell
    return cell;
}
#pragma mark -----------------------
#pragma mark UItableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //01 得到对应的数据
    XMGVideo *videoM = self.videos[indexPath.row];
    
    NSString *urlString = [KbaseUrlString stringByAppendingString:videoM.url];
    NSURL *url = [NSURL URLWithString:urlString];
    
    //02 创建视频播放控制器
    MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:url];
    
    //03 弹出播放器
    [self presentViewController:vc animated:YES completion:nil];
}
@end
JSON和XML比较
同一份数据,既可以用JSON来表示,也可以用XML来表示。
解析.png
相比之下,
JSON的体积小于XML,所以服务器返回给移动端的数据格式以JSON居多。
以上内容,为本人结合相关课程的总结解析的相关的知识点,如有错误敬请批正......

xml01.png
xml02.png
解析.png










网友评论