博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS高级编程之JSON,XML数据解析
阅读量:4703 次
发布时间:2019-06-10

本文共 10913 字,大约阅读时间需要 36 分钟。

解析的基本概念

所谓“解析”:从事先规定好的格式串中提取数据

解析的前提:提前约定好格式、数据提供方按照格式提供数据、数据获取方按照格式获取数据

iOS开发常见的解析:XML解析、JSON解析

 

一、JSON数据结构

 

JSON数据结构基本概念

Javascript Object Notation ,轻量级的数据交换格式,采用完全独立于语言的文本格式,被称为理想的数据交换语言,易于人阅读和便携,同时也易于及其解析何程,由于JSON解析便捷、快速,并且相同数据用JSON编辑所占的内存更小,所以在iOS中我们我们使用JSON解析更加普遍。

 

JSON文档有两种结构:对象 、数据

对象:以“{“开始,以”}”结束,是“名称/值”对儿的集合。名称和值中间用“:”隔开。多个“名称/值”对之间用“,”隔开。类似OC中的字典。

数组:以“["开始,以“]”结束,中间是数据。数据以“,”分割。

JSON中的数据类型:字符串、数值、BOOL、对象、数组。 

 例如:

 

 

JSON – OC 转换对照表

 

 JSON数据结构的功能

1、数据交换

2、内容管理

3、配置文件

 

 

JSON解析方案

 

在iOS中,JSON的常见解析方案有4种 

第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差)  JSONKit从2012年开始就没有更新了
苹果原生(自带):NSJSONSerialization(性能最好)

JSONObjectWithData常见的语法

从JSON数据到OC对象

+ (nullable id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;

 

从OC对象到JSON数据

+ (nullable NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;

 

下面是NSJSONSerialization解析过程:

如何进行XML解析

有以下两种方法:

1、SAX解析

SAX:Simple API for XML .基于事件驱动的解析方式,逐行解析数据。(采用协议回调机制)

SAX解析XML,是基于事件通知的模式,一边读取XML文档一边处理,不必等整个文档加载完之后才采取操作,SAX解析器会检测整个XML树形结构,你的代码会控制它在哪里停止,使用哪些数据之类的事情。就是说,SAX可控制性强,占用内存小,适用于提取部分数据。当在读取解析过程中遇到需要处理的对象,会发出通知对其进行处理,如果XML格式在某一处出现错误,前面的数据会被提取出来,错误后面数据的就显示不出来。

 

NSXMLParse类是iOS自带的XML解析类。采用SAX方式解析数据

解析过程由NSXMLParserDelegate协议方法回调

解析过程:开始标签->取值->结束标签->取值

代码的实现过程是,首先我们建立一个XML文档,并引入文件,如下: 

首先创建模型

.h中

#import 
@interface Video : NSObject@property (nonatomic, copy) NSNumber *videoId;@property (nonatomic, copy) NSString *name;@property (nonatomic, copy) NSNumber *length;//值不改变@property (nonatomic, copy) NSString *videoURL;@property (nonatomic, copy) NSString *imageURL;@property (nonatomic, copy) NSString *desc;@property (nonatomic, copy) NSString *teacher;@property (nonatomic, readonly) NSString *time;- (instancetype)initWithDict:(NSDictionary *)dict;+ (instancetype)videoWithDict:(NSDictionary *)dict;@end

 

.m中

#import "Video.h"@implementation Video- (instancetype)initWithDict:(NSDictionary *)dict {    self = [super init];    if (self) {        [self setValuesForKeysWithDictionary:dict];    }    return self;}+ (instancetype)videoWithDict:(NSDictionary *)dict {    return [[self alloc] initWithDict:dict];}- (NSString *)time {    int len = self.length.intValue;        return [NSString stringWithFormat:@"%02d:%02d:%02d", len / 3600, (len % 3600) / 60, (len % 60)];}- (NSString *)description {    return [NSString stringWithFormat:@"<%@ : %p> { videoId : %@, name : %@, length : %@, videoURL : %@, imageURL : %@, desc : %@, teacher : %@}", [self class], self, self.videoId, self.name, self.length, self.videoURL, self.imageURL, self.desc, self.teacher];}@end

在viewController.m中

#import "ViewController.h"#import "Video.h"@interface ViewController () 
@property (nonatomic, strong) NSMutableArray *videos;//当前创建的video对象@property (nonatomic, strong) Video *currentVideo;//存储当前节点的内容@property (nonatomic, copy) NSMutableString *mString;@end@implementation ViewController//懒加载- (NSMutableArray *)videos { if (_videos == nil) { _videos = [NSMutableArray arrayWithCapacity:10]; } return _videos;}- (NSMutableString *)mString { if (_mString == nil) { _mString = [NSMutableString string]; } return _mString;}- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self loadXML];}//异步请求xml- (void)loadXML { //异步请求服务器的xml文件 NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { if (connectionError) { NSLog(@"连接错误 %@",connectionError); return; } // NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == 200 || httpResponse.statusCode == 304) { //解析数据 NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; //设置代理 parser.delegate = self; //开始执行代理的方法,代理的方法中开始解析的 [parser parse]; }else{ NSLog(@"服务器内部错误"); } }];}//代理方法执行 和 设置代理属性在同一个线程//代理的方法//1 开始解析文档- (void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"1 开始解析文档 %@",[NSThread currentThread]);}//2 找开始节点- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary
*)attributeDict { //elementName 节点的名称 //attributeDict 标签的属性 NSLog(@"2 找开始节点 %@--%@",elementName,attributeDict); //如果是video标签,创建video对象 if ([elementName isEqualToString:@"video"]) { self.currentVideo = [[Video alloc] init]; self.currentVideo.videoId = @([attributeDict[@"videoId"] intValue]); //添加到数组中 [self.videos addObject:self.currentVideo]; } }//3 找节点之间的内容- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // NSLog(@"3 找节点之间的内容 %@",string); //拼接字符串 [self.mString appendString:string]; }//4 找结束节点- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { //elementName 节点名称 NSLog(@"4 找结束节点 %@",elementName); //判断标签是否是对应的属性 if ([elementName isEqualToString:@"name"]) { self.currentVideo.name = self.mString; }else if([elementName isEqualToString:@"length"]) { self.currentVideo.length = @(self.mString.intValue); }else if([elementName isEqualToString:@"videoURL"]) { self.currentVideo.videoURL = self.mString; }else if([elementName isEqualToString:@"imageURL"]) { self.currentVideo.imageURL = self.mString; }else if([elementName isEqualToString:@"desc"]) { self.currentVideo.desc = self.mString; }else if([elementName isEqualToString:@"teacher"]) { self.currentVideo.teacher = self.mString; } //清空可变字符串 [self.mString setString:@""];}//5 结束解析文档- (void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"5 结束解析文档"); NSLog(@"%@",self.videos);}//6 解析出错- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"出错");}@end

用KVC的方式

//4 找结束节点- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {    //elementName 节点名称    NSLog(@"4 找结束节点 %@",elementName);        //判断标签是否是对应的属性    if (![elementName isEqualToString:@"video"] && ![elementName isEqualToString:@"videos"]) {        //self.currentVideo.length =        //kvc 赋值的过程就是地址指向的过程,不会做类型转换!!!其实是set方法!!!        [self.currentVideo setValue:self.mString forKey:elementName];            }        //清空可变字符串    [self.mString setString:@""];}

2、DOM工具解析

DOM:Document Object Model (文档对象模型)。解析时需要将XML文件整体读入,并且将XML结构化成树状,使用时再通过树状结构读取相关数据,查找特定节点,然后对节点进行读或写。他的主要优势是实现简单,读写平衡;缺点是比较占内存,因为他要把整个xml文档都读入内存,文件越大,这种缺点就越明显。当文件内容出现错误时,在输入框内会标记出错误的位置

GDataXMLNode是Google提供的开元XML解析类,对libxml2.dylib进行了Objective-C的封装,因此在使用GDataXML之前,你需要先导入libxml2

iOS中包含一个C语言的动态链接库libxml2.dylib,解析速度比NSXMLParser快

 

模型

#import 
@interface Video : NSObject@property (nonatomic, copy) NSNumber *videoId;@property (nonatomic, copy) NSString *name;@property (nonatomic, copy) NSNumber *length;@property (nonatomic, copy) NSString *videoURL;@property (nonatomic, copy) NSString *imageURL;@property (nonatomic, copy) NSString *desc;@property (nonatomic, copy) NSString *teacher;@property (nonatomic, readonly) NSString *time;- (instancetype)initWithDict:(NSDictionary *)dict;+ (instancetype)videoWithDict:(NSDictionary *)dict;@end
#import "Video.h"@implementation Video- (instancetype)initWithDict:(NSDictionary *)dict {    self = [super init];    if (self) {        [self setValuesForKeysWithDictionary:dict];    }    return self;}+ (instancetype)videoWithDict:(NSDictionary *)dict {    return [[self alloc] initWithDict:dict];}- (NSString *)time {    int len = self.length.intValue;        return [NSString stringWithFormat:@"%02d:%02d:%02d", len / 3600, (len % 3600) / 60, (len % 60)];}- (NSString *)description {    return [NSString stringWithFormat:@"<%@ : %p> { videoId : %@, name : %@, length : %@, videoURL : %@, imageURL : %@, desc : %@, teacher : %@}", [self class], self, self.videoId, self.name, self.length, self.videoURL, self.imageURL, self.desc, self.teacher];}

在控制器.M文件中

导入模型头文件  

导入第三方框架的头文件

#import "ViewController.h"#import "GDataXMLNode.h"#import "Video.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    [self loadXML];}- (void)loadXML {    NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"];    NSURLRequest *request = [NSURLRequest requestWithURL:url];    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {        if (connectionError) {            NSLog(@"连接错误 %@",connectionError);            return;        }                //        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;        if (httpResponse.statusCode == 200 || httpResponse.statusCode == 304) {            //解析数据            //DOM 文档对象模型            //1  加载xml文档            GDataXMLDocument *document = [[GDataXMLDocument alloc] initWithData:data error:NULL];                        //获取xml文档的根元素(标签)            GDataXMLElement *rootElement = document.rootElement;            //            NSLog(@"%@",rootElement);                        NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:10];            //2 遍历所有的video节点            //video            for (GDataXMLElement *element in rootElement.children) {                //创建对象                Video *v = [[Video alloc] init];                [mArray addObject:v];                                //给对象的属性赋值                //3 遍历video的子标签,目的是拿到子标签,开始标签和结束标签之间的字符串                for (GDataXMLElement *subElement in element.children) {                    //给属性赋值                    [v setValue:subElement.stringValue forKey:subElement.name];                }                //4 遍历video的所有属性                //                NSLog(@"%@",element.attributes);                for (GDataXMLNode *attr in element.attributes) {                    [v setValue:attr.stringValue forKey:attr.name];                }                                            }            NSLog(@"%@",mArray);                                }else{            NSLog(@"服务器内部错误");        }    }];

 

转载于:https://www.cnblogs.com/huangfang1314/p/5606789.html

你可能感兴趣的文章
翻转字符串和左旋转字符串
查看>>
wampserver配置多站点
查看>>
找不到请求的 .Net Framework Data Provider。可能没有安装
查看>>
实验室管理系统(SQL+VS)
查看>>
C# protogen 处理protobuf生成cs文件
查看>>
oracle_SQL 实验查询及删除重复记录 依据条件 (row)
查看>>
SSM框架搭建
查看>>
[UE4]蓝图比C++慢10倍,是吗?
查看>>
使用IdleTest进行TDD单元测试驱动开发演练(1)
查看>>
零基础入门深度学习(2) - 线性单元和梯度下降
查看>>
微软职位内部推荐-Senior SDE
查看>>
守护进程
查看>>
初入linux系统
查看>>
机器学习预测机动车摇号:神秘的第七位
查看>>
linux 下启动tomcat 提示-bash: ./startup.sh: Permission denied 原来...
查看>>
洛谷P1041 传染病控制
查看>>
Android:interpolator用法
查看>>
集合和函数
查看>>
thinkPHP5 验证码
查看>>
『摄影欣赏』25幅记录欢乐瞬间的精美照片【组图】
查看>>