小时候的记忆与大家一起分享,愿君安好!
解析的基本概念
- 解析: 从事先规定好的格式中提取数据
- 解析的前提: 提前约定好格式,数据提供方按照格式提供数据,数据获取方则按照格式获取数据 OS开发常见的解析: XML解析,JSON解析
XML_stu.txt在我们的工程中引入要解析的文件这个只是一个简单例子(根据数据创建并引入一个Student类去处理数据)
XML解析 :
- 可拓展标记语言 (eXtensible Markup Language)
XML数据格式的功能:
1 : 数据交换
2 : 内容管理
3 : 用作配置文件
XML数据结构的语法
1 : 文档声明 --在 XML文档在最前面必须写一个文档声明.
- 1.1 简单的文档声明 : <?xml version="1.0"?>
- 1.2 用 encoding 属性, 来说明文档字符编码 :<?xml version="1.0" encoding="UTF-8">
2 : (元素 Element)节点使用一对标签表示:起始和结束标签
- (1)有元素内容:<name>你</name>
- (2)无元素内容:<name></name> 而且一个元素可以嵌套若干个子元素,但不能出现交叉嵌套
3 : 根节点是起始节点,只有一个,节点可以嵌套
4 : 节点可以有值,存储在一对标签中.
5 : 规范的 XML 文档最多只有一个根元素, 其他的都是根元素的子孙元素;
6 : 在XML中, 空格和换行,都会被当做具体的内容去处理;
7 : 属性 (Atribute) : 一个元素可以拥有多个属性,例如 <video name="小黄人" hobby="banana"/> [video元素拥有name, hobby两个属性]
- (1): 属性的值必须使用""或者''括住
- (2): 属性表示的信息也可以用子元素来表示,例如:
<video>
<name>小黄人</name>
<hobby>banana</hobby>
</video>
解析方式,逐行进行解析
1:打开XML文档
2: 开始节点 (开始标签)
3: 发现元素里面的内容
4: 结束节点 (结束标签)
5: 循环开始, 直到遇到</persons>解析才彻底结束
iOS中XML解析方式有很多
1: 苹果原生:NSXMLParser --SAX方式解析,使用简单
2: 第三方框架:
(1)libxml2 : 纯C语言,默认被包含进了iOS SDK, 同时支持DOM 和 SAX 解析
(2)GDataXMl: DOM的解析方式, 是由谷歌开发的, 底层基于libxml2
第一种 : SAX解析 (系统自带的XML方法)
SAX 工具 : Simple API for XML. 基于事件驱动的解析方式,逐行解析数据.(采用协议回调机制)
1 : NSXMLParser: NSXMLParser是iOS自带的XML解析类,采用SAX方式解析数据
2 : 解析过程由NSXMLParserDelegate协议方法回调
3 : 解析过程: 开始标签-> 取值(model赋值) -> 结束标签 ->取值(这个时候我们要了解是否要还给我们model赋值)
- 要使用iOS中系统的SAX解析 需要遵守 NSXMLParserDelegate 协议
@interface ViewController ()<NSXMLParserDelegate>
- 声明属性 数据源数组 用于存储解析数据给你使用
@property (nonatomic, strong) NSMutableArray *data;
- 声明一个用于存储当前的标签名字的属性 (后面具体使用)
@property (nonatomic, copy) NSString *currentElement;
- 在一个触发的行为里面开始实现数据解析我这里在一个控制器里面使用点击方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// [NSBundle mainBundle] 代表的是你的应用包(其实就是你Xcode左面的那个文件夹栏)
// [pathForResource:@"文件名" ofType:@"文件格式"];NSString *path = [[NSBundle mainBundle] pathForResource:@"XML_stu" ofType:@"txt"];
// 通过文件路径 创建一个NSData对象NSData *data = [NSData dataWithContentsOfFile:path];
// SAX解析使用类
parser.delegate = self;```
// 开始解析 执行这个方法
``` [parser parse];```
}
- ###执行代理方法
- ####第一步 : 开始解析文档
// 1 : 开始解析文档
```- (void)parserDidStartDocument:(NSXMLParser *)parser
{
//我们需要解析文档了 就需要自己保存解析的数据 在这里初始化数据源数组
self.data = [NSMutableArray array];
}```
- ####第二步 : 检测到开始标签
- // 第一个参数:类
- // 第二个参数: elementName 标签的名字
- // 以下三个基本为nil,一般不会使用
- // 第三个参数: 节点里面的命名空间(xmlns)
- // 第四个参数: qName 这个我还没弄明白 大家谁知道可以帮助一下 等我知道来修改
- // 第五个参数: attributeDict 标签的属性
// 2 : 检测到开始标签
>
```code
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict
{// 给currentElement 赋值 这个属性就是记录每次的检测的开始标签(其实目的就是对应的Student的属性去给model赋值)
self.currentElement = elementName;
// 如果标签的名字是student 则表示 要创建model(这里就是Student类实例对象) 并添加到数据源数组
if ([elementName isEqualToString:@"student"])
{
Student *model = [Student new];
[self.data addObject:model];
}
NSLog(@"<开始标签名>== %@", elementName);
}
第三步 : 检测到标签的值 * ( 这一步 : 我的理解是 当找到不管是开始标签还是结束标签都回去找标签的对应值 所以在后面的第四步 需要让 self.currentElement = nil 不然结束标签对应\n 也是说没有值 那么导致又一次走给Model赋值结果Model值就没有给对给成了对应的结束标签的一般空值 我们要的是开始标签对应的值所以这样操作)*
- // 第一个参数 : 类
- // 第二个参数 : 对应的标签下的值
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// 将检测到的值 存入Model的具体属性(*根据获取的标签的名字通过KVC赋值*)
// 给数组的最后的 model赋值
[[self.data lastObject] setValue:string forKey:self.currentElement];
NSLog(@"<string值=> == %@ ", string);
NSLog(@"<key=> == %@",self.currentElement);
}```
- ###第四步 : 检测到结束标签
// 4 : 检测到结束标签
>```obj
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// 这里上面已经说过结束标签找到后依然会走第三步去赋值 所以我们让Key为空就不会把我们已经存在的值去改掉了
self.currentElement = nil;
NSLog(@"<结束标签>== %@", elementName);
}
第五步 : 结束解析文档
// 5 : 结束解析文档 (这里你可以做一些操作,比如打印你的数据源数组看看数据解析是否成功 我这里的Student类重写了description方法可以直接打印看到数据不然看到地址)
• (void)parserDidEndDocument:(NSXMLParser *)parser
{
for (Student *stu in self.data)
{
NSLog(@"%@",stu);
}
}```
第二种方法 : DOM工具:(谷歌公司封装的OC代码块 第三方工具)
** DOM: Document Object Model (文件对象模型) . DOM方式解析XML时, 读入整个XML文档并构建一个驻留内存的树结构(节点树), 通过遍历树结构可以检索任意XML节点, 读取它的属性和值. 而且通常情况下, 可以借助XPath, 直接查询XML节点.**
GDataXMLNode :
1 : 采用DOM方式解析数据
2 : iOS包含一个C语言的动态链接库libxml2.tbd,解析熟读比NSXMLParser快.
3 :GDdataXMLNode是Google提供的XML解析类, 对libxml2.tbd(xcode7以前是 .dylib)进行了Objective-C的封装,能对较小或中等的xml文档进行读写操作且支持Path语法.
使用方法:
1 : 获取GDataXMLNode.h /.m 文件,将GDataXMLNode.h /.m文件添加到工程中
2 : 向工程中增加”libxml2.tbd”动态库
3 : 在工程的”Build Settings”页中找到”Header Search Path”项,添加 "/usr/include/libxml2 "
4 : 导入”GDataXMLNode.h / .m” 文件到头文件中,如工程能编译通过,则说明GDataXMLNode添加成功.
属性和方法:
- 这个代码较少我直接把整个.m放上供参考
#import "Vc2ViewController.h"
#import "GDataXMLNode.h"
#import "Student.h"
@interface Vc2ViewController ()
//数据源数组@property (nonatomic, strong) NSMutableArray *dataArray;
@end
@implementation Vc2ViewController
[super viewDidLoad];}```
```obj
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.dataArray = [NSMutableArray array];
NSString *path = [[NSBundle mainBundle] pathForResource:@"XML_stu" ofType:@"txt"];
NSData *data = [NSData dataWithContentsOfFile:path];
NSError *error = nil;```
// GDataXMLDocument XML的DOM解析使用的类
// 第一个参数 : 解析的data对象
// 第二个参数 : 一般就是0
// 第三个参数 : error信息
``` GDataXMLDocument *document = [[GDataXMLDocument alloc] initWithData:data options:0 error:&error];```
///获取到根节点里面所有的东西,也就是说获取到students里面包含的所有东西
```obj
GDataXMLElement *rootElment = [document rootElement];
NSLog(@"<rootElement == > == %@",rootElment);
for ( GDataXMLElement *subElement in rootElment.children)
{
// 在这获取到的subElement保存的是student标签里面的内容,所以这里创建对象
Student *student = [Student new];
[self.dataArray addObject:student];
for (GDataXMLElement *element in subElement.children)
{
// element 保存的就是student标签的所有子标签
// 根据标签的名字给 属性赋值
// element.name 标签的名字
// element.stringValue 标签的值
// 第一种赋值方法: 逐一对应属性赋值
if ([element.name isEqualToString:@"name"])
{
student.name = element.stringValue;
}
if ([element.name isEqualToString:@"gender"])
{
student.gender = element.stringValue;
}
if ([element.name isEqualToString:@"hobby"])
{
student.hobby = element.stringValue;
}
if ([element.name isEqualToString:@"age"])
{
student.age = [element.stringValue integerValue];
}
// 第二种: 赋值方法 setValue 的方法赋值更简单: (2 选 1 即可 )
[stu setValue:tempE.stringValue forKey:tempE.name];
}
NSLog(@"<subElement>==%@",subElement);
for (Student *stu in self.dataArray)
{
NSLog(@"<学生>= %@",stu);
}
}
}```
___
____
- #XML的优缺点:
- 优点 :
1 : 格式统一,符合标准
2 : 容易与其他系统进行远程交互,数据共享比较方便
- 缺点:
1 : XML文件格式文件庞大, 格式复杂, 传输占用带宽.
2 : 服务器端和客户端都需要花费大量代码来解析XML,不论服务器端还是客户端都使用代码变得异常复杂和不容易维护
3 : 客服端不容浏览器之间解析XML的方式不一致,需要重复编写很多代码
4 : 服务器端和客户端解析XML花费资源和时间
____
____
____
#JOSN解析 :
- ###JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式.JSON采用完全独立于语言的文本格式,易于阅读和编写,同时也易于机器解析和生成.这些特性使JSON成为理想的数据交换语言.
- ###JSON文件有两种结构:
> - 对象: “名称/值” 对的集合 .不同的语言中,它被理解为对象,记录, 结构, 字典, 哈希表, 有键列表, 或者关联数组. 以 ” {“ 开始,以 “}” 结束, 是”名称/值” 对的集合. 名称和值中间用 “:” 隔开, 多个 “名称/值” 对之间用 “,” 隔开 .
- 数组: 值的有序列表. 在大部分语言中, 它被理解为数组 . 以 “[“ 开始, 以 ”]” 结束, 中间是数据. 数据已 “,” 分隔.
- JSON中的数据类型 : 字符串, 数值 ,BOOL, 对象,数组
![举例](http://upload-images.jianshu.io/upload_images/1523603-219928ee8be06d44.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- ##功能:
>- ###数据交换
- ###内容管理
- ###配置文件
![引入这个我们需要解析的数据 JSON_stu.txt](http://upload-images.jianshu.io/upload_images/1523603-2417bb8b68e61249.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- ##NSJSONSerialization工具:(系统自带的)
> ````- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{````
//获取文件路径
```` NSString *path = [[NSBundle mainBundle]pathForResource:@"JSON_stu" ofType:@"txt"];````
//创建数据对象
```` NSData *data = [NSData dataWithContentsOfFile:path]; ````
// NSJSONReadingMutableContainers 返回一个数组或者字典
// NSJSONReadingMutableLeaves 返回一个字符串
// NSJSONReadingAllowFragments 返回一个任意类型的对象 (既可以是字典也可以是数组或者字符串 只要是 JSON 有效数据片段)
// 将json数据转化成需要的格式
```code
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error:nil];
NSLog(@"array --> %@",array);
for (NSDictionary *dict in array)
{
NSLog(@"dict --> %@",[dict objectForKey:@"content"]);
}
}````
____
____
- ##JSONKit工具:(第三方工具)
- 首先要引入第三方框架(JSONKit到你的工程)用这个第三方就简单了许多但是需要引入也是蛮麻烦,有时候还要设置你的编码,因为JSONKit实在mrc下的可以这样来改
![JSON解析配置Build Phases](http://upload-images.jianshu.io/upload_images/1523603-be1f0983800f83bc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 解析方法实现(还是比较好记忆的吧)
> ```obj
- (void)touchesBegan:(NSSet<UITouch*> *)touches withEvent:(UIEvent*)event
{
NSString*path = [[NSBundlemainBundle]pathForResource:@"JSON_stu" ofType:@"txt"];
NSData*data = [NSDatadataWithContentsOfFile:path];
//将json数据转化成需要的格式
NSArray*array = [data objectFromJSONData];
NSLog(@"array ---> %@",array);
}```
- ##JSON优缺点:
> ##优点:
1. 数据格式比较简单,易于读写,格式都是压缩的,占用带宽小.
2. 易于解析这种语言
3. 支持多种语言,包括ActionScript ,C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等语言服务器端语言,便于服务器端的解析
4. 因为JSON格式能够直接为服务器端代码使用, 大大简化了服务器端和客户端的代码开发量,但是完成的任务不变, 且易于维护.
> ##缺点:
1. 没有XML格式这么推广的深入人心和使用广泛,没有XML的通用性!
2. JSON格式目前在Web Service中推广还属于初级阶段