美文网首页ios网络编程
iOS开发之数据解析:Json、XML

iOS开发之数据解析:Json、XML

作者: DB001 | 来源:发表于2020-05-31 01:56 被阅读0次

    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.全称是Extensible MarkupLanguage,译作“可扩展标记语言”
    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.<video name="小黄人 第01部" length="30" />。
      b.video元素拥有namelength两个属性。
      c.属性值必须用 双引号""或者 单引号''括住。
    • 3.2、实际上,属性表示的信息也可以用子元素来表示,比如
      <video>
      <name>小黄人 第01部</name>
      <length>30</length>
      </video>
    XML解析
    • 要想从XML中提取有用的信息,必须得学会解析XML

    a、提取name元素里面的内容。
    <name>小黄人 第01部</name>
    b、提取video元素namelength 属性的值。
    <video name="小黄人 第01部"length="30" />

    • XML的解析方式有2种

    DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
    SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件

    • iOS中的XML解析
    • 在iOS中,解析XML的手段有很多:
      1、苹果原生
      NSXMLParserSAX方式解析,使用简单。
      2、第三方框架
      libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOMSAX方式解析。
      GDataXMLDOM方式解析,由Google开发,基于libxml2
    • XML解析方式的选择建议:
      大文件NSXMLParserlibxml2
      小文件GDataXMLNSXMLParserlibxml2

    -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居多。

    以上内容,为本人结合相关课程的总结解析的相关的知识点,如有错误敬请批正......

    相关文章

      网友评论

        本文标题:iOS开发之数据解析:Json、XML

        本文链接:https://www.haomeiwen.com/subject/yghyghtx.html