ios网络编程

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

2020-05-31  本文已影响0人  DB001

JSON

{"name" : "jack", "age" : 10}
{"names" : ["jack", "rose", "jim"]}

JSON 转换为 OC数据类型

JSON OC
大括号 { } NSDictionary
中括号 [ ] NSArray
双引号" " NSString
数字 10、10.8 NSNumber
  • iOS中,JSON的常见解析方案有4种.
    a、第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差) 。
    b、苹果原生(自带):NSJSONSerialization性能最好)。

+(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];
}

+(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]);
}


-(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];
}

-(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);
}
json01.png

XML

a.全称是Extensible MarkupLanguage,译作“可扩展标记语言”
b.跟JSON一样,也是常用的一种用于交互的数据格式
c.一般也叫XML文档(XML Document)。

<videos>
<video name="小黄人 第01部" length="30" />
<video name="小黄人 第02部" length="19" />
<video name="小黄人 第03部" length="33" />
</videos>

  • 一个常见的XML文档一般由以下部分组成:
    1.文档声明
    2.元素(Element)
    3.属性(Attribute)

1.1、在XML文档的最前面,必须编写一个文档声明,用来声明XML文档的类型
最简单的声明
<?xml version="1.0" ?>
1.2、用encoding属性说明文档的字符编码
<?xml version="1.0" encoding="UTF-8" ?>

  • 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.1、 一个元素可以拥有多个属性:
    a.<video name="小黄人 第01部" length="30" />。
    b.video元素拥有namelength两个属性。
    c.属性值必须用 双引号""或者 单引号''括住。
  • 3.2、实际上,属性表示的信息也可以用子元素来表示,比如
    <video>
    <name>小黄人 第01部</name>
    <length>30</length>
    </video>
XML解析

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

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

  • 在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];

1、当扫描到文档Document)的开始与结束。
2、当扫描到元素Element)的开始与结束。

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

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

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

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

上一篇下一篇

猜你喜欢

热点阅读