解析XML文件的两种方式 SAX和DOM
1、数据解析
- 解析的基本概念
- 所谓“解析”:从事先规定好的格式中提取数据
- 解析的前提:提前约定好格式,数据提供方按照格式提供数据、数据获取方则按照格式获取数据
- iOS开发常见的解析:XML解析、JSON解析
2、XML数据结构
- XML:Extensible Markup language(可扩展标记语言),主流数据格式之一,可以用来存储和传输数据。
- XML数据格式的功能
- 数据交换
- 内容管理
- 用作配置文件
- XML数据结构的语法
- 声明
- 节点使用一对标签表示:起始和结束标签。
- 根节点是起始节点,只有一个,节点可以嵌套。
- 节点可以有值,存储在一对儿标签中。
- XML示例
3、JSON数据结构
- JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。JSON采用完全独立于语言的文本格式,易于阅读和编写,同时也易于机器解析和生成。这些特性使JSON成为理想的数据交换语言。
- JSON数据结构的语法
- JSON文件有两种结构:
- 对象:“名称/值”对的集合。不同的语言中,它被理解为对象,记录,结构,字典,哈希表,有键列表,或者关联数组。以“{”开始,以“}”结束,是“名称/值”对的集合。名称和值中间用“:”隔开。多个“名称/值”对之间用“,”隔开。
- 数组: 值的有序列表。在大部分语言中,它被理解为数组。以“[”开始,以“]”结束,中间是数据。数据以“,”分隔。
- JSON中的数据类型:字符串、数值、BOOL、对象、数组。
- JSON示例
- JSON数据结构的功能
- 数据交换
- 内容管理
- 配置文件
4、XML与JSON两种数据结构的优缺点
- XML优缺点
- 优点:
- 格式统一,符合标准。
- 容易与其他系统进行远程交互, 数据共享比较方便。
-
缺点:
- XML文件格式文件庞大,格式复杂, 传输占用带宽。
- 服务器端和客户端都需要花费大量代码来解析XML,不论服务器端还是客户端都使代码变的异常复杂和不容易维护。
- 客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码。
- 服务器端和客户端解析XML花费资源和时间。
- 优点:
- JSON优缺点
- 优点:
- 数据格式比较简单,易于读写,格式都是压缩的,占用带宽小。
- 易于解析这种语言。
- 支持多种语言,包括ActionScript,C,C#,ColdFusion,Java,JavaScript,Perl,PHP,Python,Ruby等语言服务器端语言,便于服务器端的解析。
- 因为JSON格式能够直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,但是完成的任务不变,且易于维护。
-
缺点:
- 没有XML格式这么推广的深入人心和使用广泛,没有XML那么通用性。
- JSON格式目前在Web Service中推广还属于初级阶段 。
- 优点:
5、SAX解析XML文件
解析的XML文件
StudentInformation_XML.txt
1 <students> 2 <student> 3 <name>小暖心</name> 4 <gender>女</gender> 5 <age>18</age> 6 <hobby>傲然</hobby> 7 </student> 8 <student> 9 <name>MBBoy</name> 10 <gender>男</gender> 11 <age>20</age> 12 <hobby>借牙签</hobby> 13 </student> 14 <student> 15 <name>海</name> 16 <gender>男</gender> 17 <age>16</age> 18 <hobby>助人为乐</hobby> 19 </student> 20 <student> 21 <name>-1</name> 22 <gender>男</gender> 23 <age>69</age> 24 <hobby>芳芳女神</hobby> 25 </student> 26 <student> 27 <name>yyp</name> 28 <gender>女</gender> 29 <age>18</age> 30 <hobby>学习</hobby> 31 </student> 32 </students>
SAX:Simple API for XML 。 基于事件驱动的解析方式,逐行解析数据(采用协议回调机制)
- 核心类:NSXMLParser是iOS自带的XML解析类,采用SAX方式解析数据。
- 解析过程有NSXMLParserDelegate协议方法回调
- 解析过程:开始标签->取值->结束标签->取值
使用NSXMLParse要先创建它,设置各种属性,主要用到一下几个方法:
SAM解析XML数据步骤
1 #pragma mark - sax解析XML文件 2 - (IBAction)saxParserActionXMLDocument:(UIButton *)sender { 3 // 1.获取文件路径 4 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"StudentInformation_XML" ofType:@"txt"]; 5 // 2.将文件转换成NSData类型的对象 6 NSData *data = [NSData dataWithContentsOfFile:filePath]; 7 // NSLog(@"%@",data); 8 // 3.设置SAX解析,并关联相关的XML文件 9 NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; 10 // 4.设置代理 11 parser.delegate = self; 12 // 5.开始解析 13 [parser parse]; 14 } 15 16 #pragma mark - NSXMLParserDelegate的协议方法 17 #pragma mark - 1.文档解析 18 - (void)parserDidStartDocument:(NSXMLParser *)parser { 19 // 数组初始化 20 self.dataArray = [NSMutableArray array]; 21 } 22 23 #pragma mark - 2.开始标签解析 24 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict { 25 // 根据需求需要的标签去获取相关的数据 26 if ([elementName isEqualToString:@"student"]) { 27 Student *student = [[Student alloc] init]; 28 // 在这里不需要赋值 29 // 将数据对象添加到数组中 30 [self.dataArray addObject:student]; 31 } 32 // 将当前的标签值传给currentElement属性 33 self.currentElement = elementName; 34 } 35 36 #pragma mark - 3.解析标签中的内容,给对象赋值 37 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { 38 // 从数组中取出相关的student对象,每次从数组中去最后一个元素,保证每次取出的对象都是刚刚存入的对象 39 Student *student = [self.dataArray lastObject]; 40 // KVC赋值 41 [student setValue:string forKey:self.currentElement]; 42 } 43 44 #pragma mark - 4.结束标签 45 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { 46 self.currentElement = nil; 47 } 48 49 #pragma mark - 5.结束文档解析 50 - (void)parserDidEndDocument:(NSXMLParser *)parser { 51 // 打印校验 52 for (Student *student in self.dataArray) { 53 NSLog(@"name = %@, gender = %@, age = %ld, hobby = %@", student.name, student.gender, student.age, student.hobby); 54 } 55 } 56 57 #pragma mark - 6.查看相关的错误处理 58 - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { 59 NSLog(@"错误信息error = %@", parseError); 60 }
6、DOM解析XML文件(第三方类:GDataXMLNote.h/m)
DOM:Document Object Model(文档对象模型)。DOM方式解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过遍历树结构可以检索任意XML节点,读取它的属性和值。而且通常情况下,可以借助XPath,直接查询XML节点。
- 采用DOM方式解析数据
- iOS中包含一个C语言的动态链接库libxml2.dylib(xcode7以后改为libxml2.tbd),解析速度比NSXMLParser快。
- GDataXMLNode是Google提供的开源XML解析类,对libxml2.tbd进行了Objective-C的封装,能对较小或中等的xml文档进行读写操作且支持XPath语法。
GDataXMLElement类的用到的属性和方法
GDataXMLNote解析XML文件步骤
- 获取GDataXMLNode.h/m文件,将GDataXMLNode.h/m文件添加到工程中。
- 向工程中增加“libxml2.dylib”动态库。
- 导入"GDataXMLNode.h"文件到头文件中,此时编译失败,然后在工程的"Build Settings"页中找到"Header Search Path"项,添加"/usr/include/libxml2"。在"Other Linker Flags"项,添加"-lxml2"
- 此时编译报错,GDataXMLNote是非ARC文件,运行在ARC环境下会报错,按如下步骤,在Compile Source里找到刚引入的GDataXMLNote.m文件,添加"-fno-objc-arc"
1 #pragma mark - --------------------------------------------- 2 #pragma mark - DOM解析XML文件 3 - (IBAction)domParserActionXMLDocument:(UIButton *)sender { 4 // 1.引入libxml2.tbd动态库 5 // 2.引入第三方GDataXMLNode 6 // 3.获取文件路径 7 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"StudentInformation_XML" ofType:@"txt"]; 8 // 4.根据路径获取NSData类型的数据 9 NSData *data = [NSData dataWithContentsOfFile:filePath]; 10 // 4.5 初始化数组 11 self.dataArray = [NSMutableArray array]; 12 // 5.设置DOM解析,创建GDataXMLDocument对象,此时XML文件内所有的节点以树的形式存在GDataXMLDocument 13 GDataXMLDocument *document = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil]; 14 // 6.获取根节点,根节点里面包含了XML的所有信息 15 GDataXMLElement *rootElement = document.rootElement; 16 // 7.遍历获取相对应的子节点(student) 17 for (GDataXMLElement *studentElement in rootElement.children) { 18 Student *student = [[Student alloc] init]; 19 // 遍历子节点(student)的子节点(name,gender,age,hobby) 20 for (GDataXMLElement *element in studentElement.children) { 21 NSLog(@"%@",element); 22 // KVC:根据标签给student对象赋值 23 // element.name 标签的名字 24 // element.stringValue 标签的值 25 [student setValue:element.stringValue forKey:element.name]; 26 } 27 // 将student对象添加到数组中 28 [self.dataArray addObject:student]; 29 } 30 // 遍历检验 31 for (Student *student in self.dataArray) { 32 NSLog(@"name = %@, gender = %@, age = %ld, hobby = %@", student.name, student.gender, student.age, student.hobby); 33 } 34 }
解析的JSON文件
StudentInformation_json.txt
1 [ 2 { 3 "name":"凯凯", 4 "gender":"男", 5 "age":"18", 6 "hobby":"PS" 7 }, 8 { 9 "name":"YH", 10 "gender":"男", 11 "age":"20", 12 "hobby":"女" 13 }, 14 { 15 "name":"ZF", 16 "gender":"男", 17 "age":"20", 18 "hobby":"玩毛" 19 }, 20 { 21 "name":"小明", 22 "gender":"男", 23 "age":"22", 24 "hobby":"滚出去" 25 }, 26 { 27 "name":"淮予", 28 "gender":"女", 29 "age":"21", 30 "hobby":"小暖心" 31 } 32 ]
7、系统自带Foundation框架解析JSON数据
NSJSONSerialization 里面包含了两个方法来通过不同数据形式解析JSON数据。
1 #pragma mark - --------------------------------------------------- 2 #pragma mark - 系统自带Foundation框架解析JSON数据 3 - (IBAction)foundationParserActionJSONDocument:(UIButton *)sender { 4 // 1.获取文件路径 5 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"StudentInformation_json" ofType:@"txt"]; 6 // 2.根据路径获取NSData类型的数据 7 NSData *data = [NSData dataWithContentsOfFile:filePath]; 8 // 2.5 初始化数组 9 self.dataArray = [NSMutableArray array]; 10 // 3.解析 11 NSArray *resultArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; 12 // 4.遍历数组,使用KVC给Student对象赋值 13 for (NSDictionary *dict in resultArray) { 14 Student *student = [[Student alloc] init]; 15 [student setValuesForKeysWithDictionary:dict]; 16 [self.dataArray addObject:student]; 17 } 18 // 遍历检验 19 for (Student *student in self.dataArray) { 20 NSLog(@"name = %@, gender = %@, age = %ld, hobby = %@", student.name, student.gender, student.age, student.hobby); 21 } 22 }
8、使用第三方类JSONKit来解析JSON数据
引入JSONKit.h/m文件,并设置非ARC文件在ARC环境下运行。
1 1 #pragma mark - ------------------------------------------------- 2 2 #pragma mark - 使用第三方类JSONKit来解析JSON数据 3 3 - (IBAction)jsonkitParserActionJSONDocument:(UIButton *)sender { 4 4 // 1.引入第三方类 -- 设置 非arc文件在arc环境下运行 5 5 // 2.获取文件路径 6 6 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"StudentInformation_json" ofType:@"txt"]; 7 7 // 3.根据路径获取NSData类型的数据 8 8 NSData *data = [NSData dataWithContentsOfFile:filePath]; 9 9 // 3.5初始化数组 10 10 self.dataArray = [NSMutableArray array]; 11 11 // 4. 解析 与NSJSONSerialization解析的唯一差别 12 12 NSArray *resultArray = [data objectFromJSONData]; 13 13 // 5.遍历数组,使用KVC给Student对象赋值 14 14 for (NSDictionary *dict in resultArray) { 15 15 Student *student = [[Student alloc] init]; 16 16 [student setValuesForKeysWithDictionary:dict]; 17 17 [self.dataArray addObject:student]; 18 18 } 19 19 // 遍历检验 20 20 for (Student *student in self.dataArray) { 21 21 NSLog(@"name = %@, gender = %@, age = %ld, hobby = %@", student.name, student.gender, student.age, student.hobby); 22 22 } 23 23 }
总结:
1.数据解析:从某种格式的数据中提取自己所需要的数据
2.主流的数据交换格式有两种:XML和JSON
3.XML解析分为两种:SAX解析和DOM解析
4.XML解析工具:NSXMLParser、GDataXMLNode、TochXML和KissXML等
5.JSON解析工具:JSONKit、NSJSONSerialization、TouchJSON和SBJSON等,其中NSJSONSerialization是系统提供的解析类,其解析效率是最高的