OC中JSON解析与XML解析

JSON

  • JSON是一种轻量级的数据格式,一般用于数据交互; 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外)。
  • JSON的格式很像OC中的字典和数组,标准JSON格式key必须是双引号。
  • JSON – OC 转换对照表:
JSON OC
大括号{} NSDictionary
中括号[] NSArray
双引号”“ NSString
数字(整数和小数) NSNumber
  • 注意:并不是所有的OC对象都能转换为JSON,只有满足以下条件才能转为JSON
    • 最外层必须是 NSArray 或者 NSDictionary
    • 所有的元素必须是 NSString, NSNumber, NSArray, NSDictionary, NSNull
    • 字典中所有的key都必须是 NSStrings类型的
    • NSNumbers不能是无穷大
  • JSON解析方案:
    (1)第三方框架:JSONKitSBJsonTouchJSON(性能从左到右,越差);
    (2)苹果原生(自带):NSJSONSerialization(性能最好)。

NSJSONSerialization(JSON序列化)

  • NSJSONSerialization解析JSON数据的常见方法:
//判断一个OC数据对象是否可以转化为JSON数据
+ (BOOL)isValidJSONObject:(id)obj;

//JSON数据解析为OC数据对象
/*
第二个参数(NSJSONReadingOptions)opt是一个枚举:
typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
    //将解析的数组和字典设置为可变对象
    NSJSONReadingMutableContainers = (1UL << 0),
    //将解析数据的子节点创建为可变字符串对象
    NSJSONReadingMutableLeaves = (1UL << 1),
    //允许解析对象的最上层不是字典或者数组
    NSJSONReadingAllowFragments = (1UL << 2)
}
*/
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;

//OC数据对象转换为JSON数据(就是NSData)
/*
其中opt参数的枚举如下,这个参数可以设置,也可以不设置,如果设置,则会输出视觉美观的JSON数据,否则输出紧凑的JSON数据。
typedef NS_OPTIONS(NSUInteger, NSJSONWritingOptions) {
    NSJSONWritingPrettyPrinted = (1UL << 0),
    NSJSONWritingSortedKeys //ios(11.0)以后新加的
}
*/
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
//将JSON数据写入到输出流,返回的是写入流的字节数
+ (NSInteger)writeJSONObject:(id)obj toStream:(NSOutputStream *)stream options:(NSJSONWritingOptions)opt error:(NSError **)error;
//从输入流读取JSON数据
+ (nullable id)JSONObjectWithStream:(NSInputStream *)stream options:(NSJSONReadingOptions)opt error:(NSError **)error;
  • 解析来着服务器的JSON数据过程:
    解析JSON过程

示例

  • JSON数据转换为OC数据对象:
    123.json文件导入项目中,解析JSON数据获得NSArray并在UITableview展示;
    123.json文件里面的内容:
[
  {
    "download" : "10311万",
    "name" : "植物大战僵尸",
    "icon" : "http:\/\/p16.qhimg.com\/dr\/48_48_\/t0125e8d438ae9d2fbb.png"
  },
  {
    "download" : "9982万",
    "name" : "捕鱼达人2",
    "icon" : "http:\/\/p19.qhimg.com\/dr\/48_48_\/t0101e2931181bb540d.png"
  },
  {
    "download" : "8582万",
    "name" : "保卫萝卜",
    "icon" : "http:\/\/p17.qhimg.com\/dr\/48_48_\/t012d281e8ec8e27c06.png"
  },
  {
    "download" : "5910万",
    "name" : "找你妹",
    "icon" : "http:\/\/p18.qhimg.com\/dr\/48_48_\/t0184f949337481f071.png"
  },
  {
    "download" : "5082万",
    "name" : "水果忍者",
    "icon" : "http:\/\/p17.qhimg.com\/dr\/48_48_\/t015f10076f95e27e74.png"
  },
  {
    "download" : "3918万",
    "name" : "鳄鱼小顽皮",
    "icon" : "http:\/\/p16.qhimg.com\/dr\/48_48_\/t01885f5596e1d30172.png"
  },
  {
    "download" : "3681万",
    "name" : "神偷奶爸",
    "icon" : "http:\/\/p19.qhimg.com\/dr\/48_48_\/t0164ad383c622aabef.png"
  },
  {
    "download" : "3645万",
    "name" : "时空猎人",
    "icon" : "http:\/\/p17.qhimg.com\/dr\/48_48_\/t017bc3cfcf3981b197.png"
  },
  {
    "download" : "3552万",
    "name" : "愤怒的小鸟",
    "icon" : "http:\/\/p18.qhimg.com\/dr\/48_48_\/t012fea7312194537c2.png"
  },
  {
    "download" : "3487万",
    "name" : "滑雪大冒险",
    "icon" : "http:\/\/p18.qhimg.com\/dr\/48_48_\/t01e61cbba53fb9eb82.png"
  },
  {
    "download" : "3117万",
    "name" : "爸爸去哪儿",
    "icon" : "http:\/\/p18.qhimg.com\/dr\/48_48_\/t0108c33d3321352682.png"
  },
  {
    "download" : "2386万",
    "name" : "我叫MT ",
    "icon" : "http:\/\/p17.qhimg.com\/dr\/48_48_\/t01077fd80ffb5c8740.png"
  },
  {
    "download" : "2166万",
    "name" : "3D终极狂飙",
    "icon" : "http:\/\/p17.qhimg.com\/dr\/48_48_\/t01f55acd4a3ed024eb.png"
  },
  {
    "download" : "1951万",
    "name" : "杀手2",
    "icon" : "http:\/\/p16.qhimg.com\/dr\/48_48_\/t018f89d6e0922f75a1.png"
  },
  {
    "download" : "1290万",
    "name" : "俄罗斯方块",
    "icon" : "http:\/\/p0.qhimg.com\/dr\/48_48_\/t0183a670f1dbff380f.png"
  },
  {
    "download" : "1249万",
    "name" : "刀塔传奇",
    "icon" : "http:\/\/p16.qhimg.com\/dr\/48_48_\/t01c3f62a27c3de7af5.png"
  }
]

自定义cell:
自定义cell
主要代码:

#import "ViewController.h"
#import "HJCell.h"
@interface ViewController ()<UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tabelView;
@property(nonatomic ,copy) NSArray * dataSource;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.tabelView registerNib:[UINib nibWithNibName:@"HJCell" bundle:nil] forCellReuseIdentifier:@"HJCELL"];
}
-(NSArray *)dataSource{
    if (!_dataSource) {
        //获取应用程序程序包中资源文件路径:
        NSString * path = [[NSBundle mainBundle]pathForResource:@"123.json" ofType:nil];
        //通过路径获得json数据
        NSData * data = [NSData dataWithContentsOfFile:path];
        NSError * error = nil;
        //将json数据转换为OC对象数据
        _dataSource = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
    }
    return _dataSource;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return self.dataSource.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    HJCell * cell = [tableView dequeueReusableCellWithIdentifier:@"HJCELL"];
    NSDictionary * dict = self.dataSource[indexPath.row];
    cell.nameLabel.text = [dict valueForKey:@"name"];
    cell.numLabel.text = [NSString stringWithFormat:@"下载量:%@",[dict valueForKey:@"download"]];
    //通过url获取图片数据
    NSData * imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[dict valueForKey:@"icon"]]];
    cell.imageV.image = [UIImage imageWithData:imageData];
    return cell;
}
@end

结果展示:
结果展示

  • OC数据对象转换为JSON数据:
- (void)jsonWithOCDataObjects{
    if ([NSJSONSerialization isValidJSONObject:self.dataSource]) {//如果oc数据对象对转换为JSON数据
        NSData * data = [NSJSONSerialization dataWithJSONObject:self.dataSource options:NSJSONWritingPrettyPrinted error:nil];
        //将json数据写入到指定指定路径aaa.json文件中
        [data writeToFile:@"/Users/hejun/Desktop/aaa.json" atomically:YES];
    }
}

XML

  • XML:全称是Extensible Markup Language,译作“可扩展标记语言”,跟JSON一样,也是常用的一种用于交互的数据格式。
  • 一个常见的XML文档一般由以下部分组成:
    文档声明
    元素(Element)
    属性(Attribute)

XML文档声明

  • 在XML文档的最前面,必须编写一个文档声明,用来声明XML文档的类型

最简单的声明:

<?xml version="1.0" ?>

用encoding属性说明文档的字符编码:

<?xml version="1.0" encoding="UTF-8" ?>
  • 规范的XML文档最多只有1个根元素,其他元素都是根元素的子孙元素

XML元素(Element)

  • 一个元素包括了开始标签和结束标签
    拥有元素内容:<model>模型</model>
    没有元素内容:<model></model>
    没有元素内容的简写:<model/>
  • 一个元素可以嵌套若干个子元素(不能出现交叉嵌套)
<models>
    <model>
        <name>模型1</name>
        <length>30</length>
    </model>
</models>
  • 注意:
    1. 规范的XML文档最多只有1个根元素,其他元素都是根元素的子孙元素;
    2. XML中的所有空格和换行,都会当做具体内容处理。

下面两个元素的内容是不一样的:

<video>小黄人</video>
<video>
    小黄人
</video>

XML属性(Attribute)

  • 一个元素可以拥有多个属性

    <people name="大鹏" height="180cm" weight='70kg'/>//people元素有name,height,weight三个属性

    注意:属性值必须用 双引号”” 或者 单引号” 括住。

  • 属性表示的信息也可以用子元素来表示,如:
<people>
    <name>大鹏</name>
    <height>180cm</height>
    <weight>70kg</weight>
</people>

XML的解析

  • 要想从XML中提取有用的信息,必须得学会解析XML。
  • XML解析的两种方式:
    1. SAX:从根元素开始,按顺序一个元素一个元素的往下解析,可用于解析大、小文件;
    2. DOM:一次性将整个XML文档加载到内存中,适合较小的文件。
  • 解析XML的工具:
    苹果原生:NSXMLParser:使用SAX方式解析,使用简单;
    第三方框架: libxml2:纯C语言的,默认包含在iOS SDK中,同时支持DOM和SAX的方式解析;
    GDataXML:采用DOM方式解析,该框架由Goole开发,是基于xml2的。
NSXMLParser解析XML文档
  • NSXMLParser采取的是SAX方式解析,特点是事件驱动,下面情况都会通知代理
    当扫描到文档(Document)的开始与结束
    当扫描到元素(Element)的开始与结
  • 常见的API方法
//通过URL创建XML解析器。
- (nullable instancetype)initWithContentsOfURL:(NSURL *)url;
//通过JSON数据创建XML解析器。
- (instancetype)initWithData:(NSData *)data; 
//创建一个分析器,它逐步从指定的流中提取数据并解析它。
- (instancetype)initWithStream:(NSInputStream *)stream;

//NSXMLParserDelegate打理方法
//开始解析XML文档
- (void)parserDidStartDocument:(NSXMLParser *)parser;
//XML文档解析完成
- (void)parserDidEndDocument:(NSXMLParser *)parser;
//开始解析某个元素
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(NSDictionary<NSString *, NSString *> *)attributeDict;
//某个元素解析完毕调用
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName;
//解析出错调用,并停止解析
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError;
//解析校验失败发送错误信息给代理,解析器停止解析
- (void)parser:(NSXMLParser *)parser validationErrorOccurred:(NSError *)validationError;
  • 示例:
    网络请求加载数据,并且展示到列表:
    XML数据样式:
<videos>
    <video id="1" name="小黄人 第01部" length="10" image="resources/images/minion_01.png" url="resources/videos/minion_01.mp4"/>
    <video id="2" name="小黄人 第02部" length="12" image="resources/images/minion_02.png" url="resources/videos/minion_02.mp4"/>
    <video id="3" name="小黄人 第03部" length="14" image="resources/images/minion_03.png" url="resources/videos/minion_03.mp4"/>
    <video id="4" name="小黄人 第04部" length="16" image="resources/images/minion_04.png" url="resources/videos/minion_04.mp4"/>
    <video id="5" name="小黄人 第05部" length="18" image="resources/images/minion_05.png" url="resources/videos/minion_05.mp4"/>
    <video id="6" name="小黄人 第06部" length="20" image="resources/images/minion_06.png" url="resources/videos/minion_06.mp4"/>
    <video id="7" name="小黄人 第07部" length="22" image="resources/images/minion_07.png" url="resources/videos/minion_07.mp4"/>
    <video id="8" name="小黄人 第08部" length="24" image="resources/images/minion_08.png" url="resources/videos/minion_08.mp4"/>
    <video id="9" name="小黄人 第09部" length="26" image="resources/images/minion_09.png" url="resources/videos/minion_09.mp4"/>
    <video id="10" name="小黄人 第10部" length="28" image="resources/images/minion_10.png" url="resources/videos/minion_10.mp4"/>
    <video id="11" name="小黄人 第11部" length="30" image="resources/images/minion_11.png" url="resources/videos/minion_11.mp4"/>
    <video id="12" name="小黄人 第12部" length="32" image="resources/images/minion_12.png" url="resources/videos/minion_12.mp4"/>
    <video id="13" name="小黄人 第13部" length="34" image="resources/images/minion_13.png" url="resources/videos/minion_13.mp4"/>
    <video id="14" name="小黄人 第14部" length="36" image="resources/images/minion_14.png" url="resources/videos/minion_14.mp4"/>
    <video id="15" name="小黄人 第15部" length="38" image="resources/images/minion_15.png" url="resources/videos/minion_15.mp4"/>
    <video id="16" name="小黄人 第16部" length="40" image="resources/images/minion_16.png" url="resources/videos/minion_16.mp4"/>
</videos>

设置UITableView和自定义cell,并设置UITableView的代理和数据源,cell绑定子空间的tag,方便通过tag获取子视图:
自定义cell
给自定义cell绑定子控件tag
给自定义cell绑定子控件tag2

  • 主要相关代码
#import "ViewController.h"
#import <MediaPlayer/MediaPlayer.h>
#define URLSTR @"http://120.25.226.186:32812"

@interface ViewController ()<NSXMLParserDelegate,UITableViewDelegate,UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property(nonatomic ,strong) NSMutableArray * dataSource;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //通过xml的URL创建xml解析器
    NSXMLParser * parser = [[NSXMLParser alloc]initWithContentsOfURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"]];
    //设置代理
    parser.delegate = self;
    //开始解析,开始调用代理方法
    [parser parse];
}
-(NSMutableArray *)dataSource{
    if (!_dataSource) {
        _dataSource = [NSMutableArray array];
    }
    return _dataSource;
}
#pragma mark NSXMLParserDelegate
//开始解析XML文档时调用
-(void)parserDidStartDocument:(NSXMLParser *)parser{
    NSLog(@"%s",__func__);
}
//开始解析某个元素时调用,
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
    NSLog(@"%@",attributeDict);
    NSLog(@"%s",__func__);
    if ([elementName isEqualToString:@"video"]) {//解析到video元素就添加到数据源中
        [self.dataSource addObject:attributeDict];
    }
}
//某个元素解析完毕调用
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    NSLog(@"%s",__func__);
}
//XML文档解析完毕调用
-(void)parserDidEndDocument:(NSXMLParser *)parser{
    NSLog(@"%s",__func__);
    NSLog(@"%@",self.dataSource);
    [self.tableView reloadData];
}
#pragma mark UITableViewDataSourceAndUITableViewDelegate
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return self.dataSource.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"VIDEOCELL"];
    NSDictionary * dict = self.dataSource[indexPath.row];
    //通过tag获取子类控件
    UILabel * label = [cell.contentView viewWithTag:111];
    label.text = [dict valueForKey:@"name"];
    NSString * path = [URLSTR stringByAppendingPathComponent:[dict valueForKey:@"image"]];
    NSLog(@"path:%@",path);
    NSData * imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:path]];
    UIImage * image = [UIImage imageWithData:imageData];
    UIImageView * imageV = [cell.contentView viewWithTag:222];
    imageV.image = image;
    return cell;
}
//选中cell播放视频
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    NSDictionary * dict = self.dataSource[indexPath.row];
    //拼接视频路径
    NSString * videoPath = [URLSTR stringByAppendingPathComponent:[dict valueForKey:@"url"]];
    NSLog(@"videoPath:%@",videoPath);
    //创建视频播放器
    MPMoviePlayerViewController * playerVC = [[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString:videoPath]];
    //模态的方式弹出
    [self presentViewController:playerVC animated:YES completion:nil];
}
@end

结果展示:
结果展示

扫描二维码关注公众号,回复: 2463213 查看本文章
GDataXML解析XML文档
  • 配置
    GDataXML基于libxml2库,得做以下配置
    导入libxml2库,导入方式有2种:
    1.选中项目TARGET: General->Linked Frameworks and Libraries 点加号添加
    导入libxml2库方式1
    2.选中项目TARGET:Build Phases ->Link Binary With Libraries 点加号添加
    导入libxml2库方式2
    该动态库内部没有头文件,所以还需要设置libxml2的头文件搜索路径(为了能找到libxml2库的所有头文件)在TARGET->Bulid Setting -> Head Search Paths 中加入/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/usr/include/libxml2,但是有一个问题,如果这样做的话每升级一次版本就要修改一次。正确做法因该是Header Search Paths 该为 ${SDKROOT}/usr/include/libxml2
    头文件搜索路径设置
    导入GDataXMLNode文件是2008年的,是MRC管理内存的,所以还需要告诉编译器,所以要进行非ARC处理。TARGET -> Bulid Phases -> Compile Sources 双击GDataXMLNode.m文件,添加-fno-objc-arc代码。
    转化为ARC
    设置链接参数(自动链接libxml2库),在TARGET->Bulid Setting ->Linking->Other Linker Flags中加入-lxml2
    自动链接libxml2库设置
  • 主要API方法
//GDataXMLDocument是XML文档类
@interface GDataXMLDocument : NSObject
//创建XML文档方法
- (id)initWithXMLString:(NSString *)str options:(unsigned int)mask error:(NSError **)error;
- (id)initWithData:(NSData *)data options:(unsigned int)mask error:(NSError **)error;
- (id)initWithRootElement:(GDataXMLElement *)element;
//获取XML文档根元素
- (GDataXMLElement *)rootElement;

//GDataXMLElement是元素类
@interface GDataXMLElement : GDataXMLNode
//创建XML元素方法
- (id)initWithXMLString:(NSString *)str error:(NSError **)error;
//获取元素里面为name的子元素或者为name的属性
- (NSArray *)elementsForName:(NSString *)name;
//通过元素属性名称name获得属性值
- (GDataXMLNode *)attributeForName:(NSString *)name;
//将元素值转换为字符串类型
- (NSString *)stringValue;
  • 示例关键代码
#import "ViewController.h"
#import "GDataXMLNode.h"
#import <MediaPlayer/MediaPlayer.h>
#define URLSTR @"http://120.25.226.186:32812"
@interface ViewController ()
@property(nonatomic ,strong) NSMutableArray * dataSource;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    NSURL * url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"];
    NSURLRequest * request = [NSURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //通过data回去xml文档
        GDataXMLDocument * document = [[GDataXMLDocument alloc]initWithData:data options:kNilOptions error:nil];
        //拿到根元素,得到根元素内部所有名称为video的子孙元素
        NSArray * elementArray = [document.rootElement elementsForName:@"video"];
        //便利元素数组获取元素属性值 并将元素属性保存到字典中,一个元素对应一个字典
        for (GDataXMLElement * element in elementArray) {
            NSMutableDictionary * dict = [NSMutableDictionary dictionary];
            //通过属性名称获取属性字符串值
            [dict setValue:[element attributeForName:@"name"].stringValue forKey:@"name"];
            [dict setValue:[element attributeForName:@"length"].stringValue forKey:@"length"];
            [dict setValue:[element attributeForName:@"image"].stringValue forKey:@"image"];
            [dict setValue:[element attributeForName:@"id"].stringValue forKey:@"id"];
            [dict setValue:[element attributeForName:@"url"].stringValue forKey:@"url"];
            [self.dataSource addObject:dict];
        }
        NSLog(@"%@",self.dataSource);
    }];
}
-(NSMutableArray *)dataSource{
    if (!_dataSource) {
        _dataSource = [NSMutableArray array];
    }
    return _dataSource;
}

打印结果(为展示完):
这里写图片描述

猜你喜欢

转载自blog.csdn.net/bolted_snail/article/details/80237166