一、JSON与XML的优缺点
XML与JSON共同点:
1.格式统一,符合标准
2.容易与其他系统继续远程交互,数据共享比较方便
缺点:
1.XML文件格式文件庞大,格式赋值,传输占用带宽
2.服务器端和客户端都需要花费大量的代码来解析XML,不论服务器还是客户端都使代码变得异常复杂不易维护
3.客户端不同浏览器直接解析XML的方式不一致,需要重复编写很多代码
3.服务器端和客户端解析XML花费资源和数据
JSON
优点:
1.数据格式比较简单,易于读写,格式都是压缩的,占用带宽小
2.易于解析这种语言
3.支持多种语言,包括ACtionScript,C,C#,java,PHP,Python等,方便服务器端解析
4.以为JSON格式能够直接为服务器端代码使用,大大简化了服务器端的代码量,且易于维护
缺点:
1.没有XML格式推广的深入人心和使用广泛
2.JSON在Web Service中推广还属于初级阶段。
二、JSON解析
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,才有完全独立于语言的文本格式,易于阅读和编写,与易于解析和生成。
JSON文件有两种结构:
对象:“名称/值”对的集合,可以理解为字典
数组:值的有序列表
NSJSONSerializationi里面包含了两种方法来通过不同的数据形式解析JSON数据
//解析 NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; NSDictionary *dic2 = [NSJSONSerialization writeJSONObject:<#(nonnull id)#> toStream:<#(nonnull NSOutputStream *)#> options:<#(NSJSONWritingOptions)#> error:<#(NSError * _Nullable __autoreleasing * _Nullable)#>]
//通用的json解析方法 //有时json文件前面会有一些不属于json的字符,人为去除 -(void)normalJsonData { //得到路径 NSString *path = [[NSBundle mainBundle]pathForResource:@"MovieList" ofType:@"txt"]; //由于不确定是否为标准格式的json串,先用字符串来接收文件数据 NSString *fileStr = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; //判断字符串是否存在并且是以 { 或者 [ 开始的,,是则说明文件为标准json串,否则需要截取字符 if (!(fileStr && ([fileStr hasPrefix:@"{"] || [fileStr hasPrefix:@"["])) ) { //声明不是标准格式json,找到第一个{ 和 [ 的位置 NSRange range = [fileStr rangeOfString:@"{"]; NSRange range_1 = [fileStr rangeOfString:@"["]; NSLog(@"%@,%@",NSStringFromRange(range),NSStringFromRange(range_1)); if (range.location > range_1.location) { // 中括号 [ 开头从中括号位置开始截取 fileStr = [fileStr substringFromIndex:range_1.location]; } else { // 花括号{ 开头 fileStr = [fileStr substringFromIndex:range.location]; } } //经过处理fileStr为标准的json串 NSData *resultData = [fileStr dataUsingEncoding:NSUTF8StringEncoding]; //解析 id resultValue = [NSJSONSerialization JSONObjectWithData:resultData options:NSJSONReadingAllowFragments error:nil]; NSLog(@"id = %@",resultValue); }
三、XML解析
XML有两种解析方法:DOM(Document Object Model)解析和SAX(Simple API for XML)工具
1.DOM解析XML,使用GDataXMLNode文件
DOM解析时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过遍历树结构可以检索任意XML节点,读取属性和值。
通常可以借助XPath,直接查询XML节点
iOS包含一个C语言动态链接库libxml2.tbd(xcode7以前为libxml2.dylib)
GDataXMLNode是Google提供的开元XML解析类,对libxml2.tbd进行了Objective-C的封装,能对较小或中等的xml稳定进行读写操作并指出XPath语法。
(1)拖入GDataXMLNode的.h和.m文件到工程
这时候进行编译,会报错"libxml/tree/h file not found"
(3)在工程的Build Settings设置里面搜索search,找到Search paths选项下的Header Search Paths,加入一条/usr/include/libxm2,这里三个反斜杠不能少
这时候进行编译,可能会出现20个左右的错误,因为GDataXMLNode.m文件使用的是MRC模式,如果我们的工程是ARC模式下的,是不能使用autorelease等内存操作的。
(4)再进入Build phases设置的Compile Sources选项中,选择GDataXMLNode.m文件,点击文件后面的空白,添加一句-fno-objc-arc。
这时候再编译,终于没啥问题了,可以开始用了,别嫌麻烦,sax不用配置但用起来麻烦
要解析的XML文件为下面的内容文件名为XMLDemo.xml
<?xml version="1.0" encoding="utf-8"?> <!--此行包含XML的版本信息和编码格式--> <students><!--这是开始标签,也就是根节点--> <student attribute = "吉祥物"><!--student为根节点的子节点,name节点的父节点, attribute是它的属性--> <name>李帅</name><!--洛洛受为name节点的值--> <sex>无</sex> <age>14</age> </student> <student attribute = "吉祥物之基友"> <name>建华</name> <sex>随条件改变</sex> <age>17</age> </student> </students><!--节点的结束标签都是以/加标签名称组成 -->
//dom解析 -(void)domParser { //获得文件路径 NSString *path = [[NSBundle mainBundle]pathForResource:@"XMLDemo" ofType:@"xml"]; //用NSData接收 NSData *xmlData = [NSData dataWithContentsOfFile:path]; //将文件类型通过note对象转换为树形结构(一次性从内存中将XML文件转换为倒着的树形结构) GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:xmlData options:0 error:nil]; //得到根节点 GDataXMLElement *rootElement = [doc rootElement]; //得到根节点的所有节点,这个方法很重要,通过这个方法一层层得到子节点 NSArray *stuElement = [rootElement elementsForName:@"student"]; //初始化一个可变数组,用来存放每个学生的信息 NSMutableArray *allStudentMArray = [[NSMutableArray alloc]init]; //得到student节点的所有子节点 for (GDataXMLElement* itemElement in stuElement) { //itemElement是student节点,分别取出student的子节点 NSArray *nameElement = [itemElement elementsForName:@"name"]; NSString *name = [[nameElement objectAtIndex:0]stringValue]; NSArray *sexElement = [itemElement elementsForName:@"sex"]; NSString *sex = [[sexElement objectAtIndex:0]stringValue]; NSArray *ageElement = [itemElement elementsForName:@"age"]; NSString *age = [[ageElement objectAtIndex:0]stringValue]; NSDictionary *dic = [[NSDictionary alloc]initWithObjectsAndKeys:name,@"name",sex,@"sex",age,@"age", nil]; [allStudentMArray addObject:dic]; //得到节点的属性 NSArray *attributes = itemElement.attributes; //得到属性节点 GDataXMLNode *node = [itemElement attributeForName:@"attribute"]; NSLog(@"attr = %@ , node.name = %@ node.stringValue = %@ ",attributes[0],node.name,node.stringValue); } NSLog(@"%@",allStudentMArray); } //通过dom解析的方式为xml增加节点(sax解析只可以读取,不可以添加) -(void)domAddNote { //获得文件路径 NSString *path = [[NSBundle mainBundle]pathForResource:@"XMLDemo" ofType:@"xml"]; //用NSData接收 NSData *xmlData = [NSData dataWithContentsOfFile:path]; //得到 GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:xmlData options:0 error:nil]; //得到根节点 GDataXMLElement *rootElement = [doc rootElement]; //创建一个我们需要添加的节点(student) GDataXMLElement *createElement = [GDataXMLNode elementWithName:@"student"]; GDataXMLElement *nameNode = [GDataXMLElement elementWithName:@"name" stringValue:@"成功"]; [createElement addChild:nameNode]; GDataXMLElement *sexNode = [GDataXMLElement elementWithName:@"sex" stringValue:@"男"]; [createElement addChild:sexNode]; GDataXMLElement *ageNode = [GDataXMLElement elementWithName:@"age" stringValue:@"11"]; [createElement addChild:ageNode]; //将创建好的student节点添加到根节点 [rootElement addChild:createElement]; // [rootElement removeChild:createElement];//删除 //得到所有的student节点 NSArray *stuElementArray = [rootElement elementsForName:@"student"]; //遍历根节点 for (GDataXMLElement *stuItem in stuElementArray) { //name NSString *name = [[[stuItem elementsForName:@"name"]objectAtIndex:0]stringValue]; NSString *sex = [[[stuItem elementsForName:@"sex"]objectAtIndex:0]stringValue]; NSString *age = [[[stuItem elementsForName:@"age"]objectAtIndex:0]stringValue]; NSLog(@"name = %@,sex = %@,age = %@",name,sex,age); } }
2.SAX解析
SAX是基于事件驱动的解析方式,逐行进行事件解析(采用协议回调机制)
解析过程:开始标签->取值->结束标签->取值
//xml的sax解析,逐行解析 -(void)saxParser { NSString *path = [[NSBundle mainBundle]pathForResource:@"XMLDemo" ofType:@"xml"]; NSData *data = [NSData dataWithContentsOfFile:path]; //sax解析 NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data]; //指定代理 parser.delegate = self; //开始解析(同步,解析未完成,下面的代码就不会执行 BOOL isSuccess = [parser parse]; if (isSuccess) { NSLog(@"sax ok"); } else { NSLog(@"sax fs"); } }
SAX解析的代理方法
//导入协议NSXMLParserDelegate @interface RootViewController ()<NSXMLParserDelegate> #pragma mark -- sax解析的代理方法 //开始解析 -(void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"开始解析"); self.allStudentsMArray = [[NSMutableArray alloc]init]; } //解析结束 -(void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"解析结束"); NSLog(@"array -- %@",self.allStudentsMArray); } //开始解析节点 //elementName:标签名称 //namespaceURI;命名空间指向的链接 //qName:命名空间代名词 //attributeDict:节点的属性值 -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict { NSLog(@"开始解析节点--%@",elementName); if ([elementName isEqualToString:@"student"]) { //当解析到student的时候,说明已经到了该获取该节点子节点的值的时候,应该初始化容器了 self.singleStudentDic = [NSMutableDictionary dictionary]; } } //string为所需要的值的一部分 -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { if (self.noteValueMstring) { //对解析数据进行拼接 [self.noteValueMstring appendString:string]; NSLog(@"%@",_noteValueMstring); } else { self.noteValueMstring = [NSMutableString stringWithString:string]; } } //节点结束 -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{ if ([elementName isEqualToString:@"name"]) { //说明name取值结束 [_singleStudentDic setObject:[self replaceStringWith:_noteValueMstring] forKey:elementName]; } if ([elementName isEqualToString:@"age"]) { //说明age节点取值完成 [_singleStudentDic setObject:[self replaceStringWith:_noteValueMstring] forKey:elementName]; } if ([elementName isEqualToString:@"sex"]) { [_singleStudentDic setObject:[self replaceStringWith:_noteValueMstring] forKey:elementName]; } if ([elementName isEqualToString:@"student"]) { //说明student的解析结束了,该把字典放入数组了 [self.allStudentsMArray addObject:_singleStudentDic]; // [_singleStudentDic removeAllObjects];在开始解析节点的时候对dic进行了初始化 } //每次解析完成一个节点,都需要将可变字符串清理一次 _noteValueMstring = nil; } //替换特殊字符,SAX解析会把XML中的各种换行和tab空格等字符解析出来,人为修改一下 -(NSString*)replaceStringWith:(NSString*)sourceStr { NSString *resultStr = [sourceStr stringByReplacingOccurrencesOfString:@"\r" withString:@""]; resultStr = [resultStr stringByReplacingOccurrencesOfString:@"\n" withString:@""]; resultStr = [resultStr stringByReplacingOccurrencesOfString:@"\t" withString:@""]; resultStr = [resultStr stringByReplacingOccurrencesOfString:@" " withString:@""]; return resultStr; }