所谓"解析":从事先规定好的格式中提取数据
解析一共有两种格式:JSON和XML
一、JSON
全称JavaScript Object Notation,轻量级的数据交换格式。
1.数据格式:
字典:{key:value}
数组:[value1,value2]
JSON中的数据类型:字符串,数值,BOOL,对象,数组
2.示例:
字典格式1:{@"name":@"Carson"}
数组格式2:["value1","value2"]
混合格式3:[ {@"name":"Carson"},{@"sex":"Male"}]
3.解析方法
使用系统推荐的方法,NSJSONSerialization
它有两个方法,
JSON反序列化方法,也叫JSON解析,从服务器端获得二进制 数据,转为OC对象就是反序列化。
JSONObjectWithData: option: error:
id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSDictionary *dict= [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSArray *array= [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSString *string= [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
服务器传过来的二进制数据,可以转为oc对象,它可以是id类型,可以是字典,数组、以及字符串。
JSON序列化,把OC对象转为二进制数据,上传给服务器。
dataWithJSONObejct:option:error:
NSDictionary *dic1 = @{@"name":@"cj",@"age":@"27"};
NSDictionary *dic2 = @{@"name":@"cj2527",@"age":@"27"};
NSArray *array = @[dic1,dic2];
//检测能否被序列化
if (![NSJSONSerialization isValidJSONObject:array]) {
NSLog(@"格式不正确!");
return;
}
request.HTTPBody = [NSJSONSerialization dataWithJSONObject:array options:0 error:NULL];
使用第三方框架
MJExtension
下载地址和详细说明
https://github.com/CoderMJLee/MJExtension#Getting_Started
二、XML
全称Extensible Markup language,可拓展标记语言
它的解析方式有两种:
SAX(Simple API for XML):事件驱动机制。从根元素开始,按顺序一个个元素往下解析,它只在XML文档中查找特定条件的内容,并且只提取需要的东西,占用内存少,也比较灵活,所以适合解析大文件。
DOM(Document Object Model):文档对象模型。一次性将整个XML文档加载进内存,放在一个树型结构中,需要的时候查找特定节点。实现简单,读写平衡,但是比较占内存,适合解析小文件。
xml格式有两种结构:
结构一:
<?xml version="1.0" encoding="utf-8"?> <!--此行包含XML的版本信息和编码格式-->
<Students className = "cj">
<Student name = "张三" age = "18"/>
<Student name = "李四" age = "18"/>
</Students>
这种结构的解析比较容易,参考以下链接文章。
http://www.jianshu.com/p/2eb1c93d75bb
结构二:
<?xml version="1.0" encoding="utf-8"?> <!--此行包含XML的版本信息和编码格式-->
<students><!--这是开始标签,也就是根节点-->
<student attribute = "学生A" ><!--student为根节点的子节点,name节点的父节点, attribute是它的属性-->
<name>张三</name><!--张三 为name节点的值-->
<sex>男</sex>
<age>23</age>
</student>
<student attribute = "学生B">
<name>李四</name>
<sex>男</sex>
<age>22</age>
</student>
</students><!--节点的结束标签都是以/加标签名称组成 -->
这种结构使用系统原生的NSXMLParse解析,相对复杂,参考http://www.jianshu.com/p/c82eaaf8b47a
//1.实例化一个xml解析,通过代理实现XML的解析
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
//2.设置代理
parser.delegate = self;
//3.开始解析
[parser parse];
遵守代理协议,实现代理的5个方法
parserDidStartDocument//打开文档
parser:didStartElement //开始节点
parser:foundCharacters //发现节点内容
parser:didEndElement //结束节点
parserDidEndDocument //结束文档
具体实现如下:
//1.打开文档,准备解析,一般在这里边用来将保存数据的数组暂时清空
-(void)parserDidStartDocument:(nonnull NSXMLParser *)parser{
// 初始化数据容器,清空数据,便于多次调用
[self.videos removeAllObjects];
}
//2.开始节点,一般在这里主要进行数据模型的初始化和读取节点的属性值
-(void)parser:(nonnull NSXMLParser *)parser didStartElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(nonnull NSDictionary<NSString *,NSString *> *)attributeDict{
// 创建对象
if ([elementName isEqualToString:@"video"]) {
self.currentVideo =[[Video alloc]init];
//设置videoID
self.currentVideo.videoId = [NSNumber numberWithInteger:[attributeDict[@"videoId"] integerValue]];
}
//在准备开始解析下一个节点的数据时,先把数据清空
//清空字符串的内容,因为马上要进入第三个方法,要重写拼接字符串了
[self.elementString setString:@""];
NSLog(@"开始节点:%@,%@",elementName,attributeDict);
}
//3.发现节点内容,解析节点之间的字符。 当解析器找到开始标记和结束标记之间的字符时,调用这个方法解析当前节点内的所有字符
-(void)parser:(nonnull NSXMLParser *)parser foundCharacters:(nonnull NSString *)string{
//开始拼接字符串, 将一个节点中读取到的数据进行拼接
[self.elementString appendString:string];
NSLog(@"发现节点内容:%@",string);
}
//4.结束节点,,在这个方法里通常进行数据的保存
-(void)parser:(nonnull NSXMLParser *)parser didEndElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName{
//如果遇到了结束节点符号,则进行数据的保存
if ([elementName isEqualToString:@"video"]) {
[self.videos addObject:self.currentVideo];
}else if(![elementName isEqualToString:@"videos"]){
//如果既不是数据的最后一个节点,也不是根节点,即为数据中间的节点,则将数据对应保存到模型中
//运用KVC保存,效率高,不过属性的名字一定要和节点的名称相对应
[self.currentVideo setValue:self.elementString forKey:elementName];
}
NSLog(@"结束节点:%@",elementName);
}
//5.结束文档
-(void)parserDidEndDocument:(nonnull NSXMLParser *)parser{
//xml真正解析结束,可以更新UI等,在主线程
dispatch_async(dispatch_get_main_queue(), ^{
// self.dataList = self.videos;//给tableView的模型数组赋值
});
NSLog(@"5:结束文档");
}
补充下属性申明
@interface ViewController () <NSXMLParserDelegate>
@property (nonatomic,strong)NSMutableArray *videos;//xml的数据容器
@property (nonatomic,strong)NSMutableString *elementString;//第三步骤拼接字符串
@property (nonatomic,strong)Video *currentVideo;//当前模型
@property (nonatomic,strong)NSMutableArray *dataList;//存放表格的所有数据
@end
也可以用第三方框架XMLReader读取比较方便,代码较少。
做点补充吧
//1. 转化成xmlReader能转化的类型
NSString *path = [[NSBundle mainBundle] pathForResource:@"demo.xml" ofType:nil];
NSURL *url = [NSURL fileURLWithPath:path];
NSData *data = [NSData dataWithContentsOfURL:url];
//2. 开始转化
NSError *error;
NSDictionary *dic = [XMLReader dictionaryForXMLData:data error:&error];
NSLog(@"%@",dic);
NSArray *list = [[dic objectForKey:@"students"]objectForKey:@"student"];
// NSLog(@"%@",list);
if (![list isKindOfClass:[NSArray class]])
{
// if 'list' isn't an array, we create a new array containing our object
list = [NSArray arrayWithObject:list];
}
//
// // we can loop through items safely now
NSMutableArray *nameArr = [NSMutableArray array];
for (NSDictionary *item in list)
{
Model *model = [[Model alloc]init];
[model setValuesForKeysWithDictionary:item];
[nameArr addObject: model];
}
//获得模型数据,就可以更新UI了
//NSLog(@"%@",nameArr);
//获取第一个学生的信息
Model *model2 = nameArr[0];
NSLog(@"属性:%@,name=%@,sex=%@,age=%@",model2.attribute ,model2.name,model2.sex,model2.age);
运用kvc方法,得注意key保持一致
model模型如下:
@interface Model : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *attribute;
@property (nonatomic, copy) NSString *text;//xmlReader必须要的
@property (nonatomic, copy) NSString *sex;
@property (nonatomic, copy) NSString *age;
@end
JSON和XML的对比
JSON的优点:格式简单,占用带宽小,易于读写,易于解析,易于维护,支持多语言
缺点:没有xml广泛,没有xml那样通用性
XML的优点:格式统一、符合标准,易于和其他系统进行远程交互,方便数据共享
缺点:文件庞大、占用带宽大、服务器端和客户端需要大量代码来解析xml,不易于维护