解析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


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容