05、网络解析
解析:从事先规定好的格式中提取数据
iOS开发常见的解析:XML解析,JSON解析
XML解析
XMl事例:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 根结点 是所有节点的父节点或者爷节点 -->
<students> <!--开始节点-->
<!--student的子节点,position就是该节点的属性-->
<student position="愤青">
<!--lyj是name节点的内容,我们可以将该节点所有的特性都用属性来表示,但是为了阅读起来方便,我们一般也会将该节点的特性用他的子节点来表示-->
<name>lyj</name>
<age>25</age>
<sex>男</sex>
</student>
<student>
<name>zza</name>
<age>22</age>
<sex>保密</sex>
</student>
</students> <!--结束节点-->
XML有两种解析方法:DOM(Document Object Model)解析和SAX(Simple API for XML)工具
1.SAX解析
SAX基本原理:采用事件驱动解析XML文件,以流式方式逐行的去读,它不需要解析完整个文档,在按内容顺序解析文档的过各中,SAX会判断当前讲到的字符是否合法XML语法中的某部分,如果符合就触发事件(例如startDocument()、endDocument()诸如此类的事件),它的特点是不会记录前面所碰到的标签,并且它是一个解析速度快并且占用内存少的XML解析器
特点:
一.是基于事件驱动的解析方式
二.逐行解析
三.只能读取(DOM解析可读可写)
四.一般只用做文档比较大的时候
//sax解析
-(void)saxPath{
//sax解析:基于事件驱动的解析方式,逐行解析
NSString* xmlPath=[[NSBundle mainBundle] pathForResource:@"xml" ofType:@"xml"];
NSString* xmlStr=[NSString stringWithContentsOfFile:xmlPath encoding:NSUTF8StringEncoding error:nil];
//字符串转data类型
NSData* xmlData=[xmlStr dataUsingEncoding:NSUTF8StringEncoding];
//参数:需要解析的文件内容
NSXMLParser* xmlParser=[[NSXMLParser alloc] initWithData:xmlData];
//设置代理
xmlParser.delegate=self;
//开始解析 同步的过程 当整个解析完成了才会执行下一行代码
BOOL isSuccess=[xmlParser parse];
if (isSuccess) {
NSLog(@"解析成功");
}else{
NSLog(@"解析失败");
}
//解析的过程不结束,就不会执行该打印
NSLog(@"我在解析的最底下");
}
下来遵循协议,实现协议方法,为了方便获取数据,声明一个字典和数组
@interface ViewController ()<NSXMLParserDelegate>
@property(nonatomic,strong)NSMutableArray* allDataArray;//存放所有student的节点
@property(nonatomic,strong)NSMutableDictionary* studentDic;//将student转换为字典
@property(nonatomic,strong)NSString* noteValueString;//存储节点中的值
#pragma mark--------parser解析的代理方法
//开始解析整个文档了
-(void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(@"开始解析整个文档了");
//初始化外部的可变数组,准备存放student节点
self.allDataArray=[[NSMutableArray alloc] init];
}
//当碰到开始节点或开始标签的时候会执行的代理方法
//elementName:标签名称(节点名),例如<name>
//namespaceURI:命名空间的标识名 例如<teacher xmlns:l="www.lanou3g.com">
//qName:命名空间的值,就是上面的 www.lanou3g.com
//attributeDict:标签的属性 例如 <student position="愤青"> position就是标签的属性,attributeDict=={pasition:"愤青"}
-(void)parser:(NSXMLParser*)parser didStartElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(nonnull NSDictionary<NSString *,NSString *> *)attributeDict{
NSLog(@"碰到开始标签----%@",elementName);
//当开始解析student节点的时候,说明我们要用到字典了,就需要对字典进行初始化
if ([elementName isEqualToString:@"student"]) {
self.studentDic=[[NSMutableDictionary alloc] init];
}
}
//取出标签中的值
//string:就是标签中的值
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
NSLog(@"正在解析的值为---%@",string);
//将节点的内容存储起来,以供节点解析结束使用
self.noteValueString=string;
}
//遇到当前正在解析标签结束标签
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
NSLog(@"碰到结束标签----%@",elementName);
if ([elementName isEqualToString:@"name"]) {
//说明name标签解析结束
[self.studentDic setObject:self.noteValueString forKey:elementName];
}
if ([elementName isEqualToString:@"age"]) {
//说明age标签解析结束
[self.studentDic setObject:self.noteValueString forKey:elementName];
}
if ([elementName isEqualToString:@"sex"]) {
//说明sex标签解析结束
[self.studentDic setObject:self.noteValueString forKey:elementName];
}
if ([elementName isEqualToString:@"student"]) {
//说明一个student已经解析完成,说明一个字典已经完整,应该将字典放入数组中了
[self.allDataArray addObject:self.studentDic];
}
}
//整个文档解析结束
-(void)parserDidEndDocument:(NSXMLParser *)parser{
NSLog(@"整个文档解析结束");
//当整个文档解析结束,说明所有的数据我们已经拿到,可以正常使用了
NSLog(@"----%@",self.allDataArray);
}
//当解析出错会调用的方法
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSLog(@"解析出现错误---%@",parseError.description);
}
2.DOM解析
dom解析基于文档驱动的解析方式,DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过遍历树结构可以检索任意XML节点,读取他的属性和值,而且通常情况下,可以借助XPath,直接查询XML节点
使用方法:
1.获取GDataXMLNode.h/m文件,将GDataXMLNode.h/m文件添加到工程中
2.向工程中增加“libxml2.dylib”动态库
具体做法 选中整个工程 在Build Phases的倒数第二个选项中点“+”号,搜索libxml2.dylib 并添加
3.在工程的“Build Settings”页中找到“Header Search Path” 点击添加 "/usr/include/libxml2"
4.导入“GDataXMLNode.h”文件到头文件 如果工程能编译通过,说明添加成功
注意:
(1)在工程的Build phases设置的Link Binary With Libraries里面点击加号,搜索libxml2.tbd,选择添加
(2)在工程的Build Settings设置里面搜索search,找到Search paths选项下的Header Search Paths,加入一条/usr/include/libxml2这里三个反斜杠不能少
222.png(3)在工程的Build Settings设置里面搜索Other Linker Flags,找到Other Linker Flags,双击空白处输入-lxml2
3333.png
这样在编译就不会报错啦。☺️
//dom解析 基于文档驱动的解析方式
-(void)domParser{
//需要获取解析的源文件
NSString* xmlPath=[[NSBundle mainBundle] pathForResource:@"xml" ofType:@"xml"];
NSString* xmlStr=[NSString stringWithContentsOfFile:xmlPath encoding:NSUTF8StringEncoding error:nil];
//字符串转data类型
NSData* xmlData=[xmlStr dataUsingEncoding:NSUTF8StringEncoding];
//dom解析
//step1:将源xml文件转换成树状结构的文档放在内存中,以供遍历获取每个节点
GDataXMLDocument* xmlDoc=[[GDataXMLDocument alloc] initWithData:xmlData encoding:NSUTF8StringEncoding error:nil];
//step2:获取根节点 就相当于获取到了students节点
GDataXMLElement* rootElement=[xmlDoc rootElement];
//step3:获取我们需要的子节点
//参数:我们需要获取的标签名
// NSArray* studentArray=[rootElement elementsForName:@"student"];
//初始化一个可变数组,准备存放所有的student转换成的字典
NSMutableArray* allStudentsArray=[[NSMutableArray alloc] init];
//添加节点(向现有的文档动态的增加一个student节点)
//节点创建 <student></student>
GDataXMLElement* studentElement = [GDataXMLElement elementWithName:@"student"];
//将student节点加入到它的父节点中
// [rootElement addChild:studentElement];
//为student增加子节点
GDataXMLElement* nameElement = [GDataXMLElement elementWithName:@"name" stringValue:@"ze an"];
GDataXMLElement* ageElement = [GDataXMLElement elementWithName:@"age" stringValue:@"23"];
GDataXMLElement* genderElement = [GDataXMLElement elementWithName:@"gender" stringValue:@"未知"];
[studentElement addChild:nameElement];
[studentElement addChild:ageElement];
[studentElement addChild:genderElement];
[rootElement addChild:studentElement];
NSArray* studentArray=[rootElement elementsForName:@"student"];
//step4:遍历数组
//stuNode:对应一个student节点
/*<student>
<name></name>
<age></age>
<sex></sex>
</student>
*/
//每执行一次循环体,就相当于获取了一个完整的student节点,结构如上
// for (GDataXMLElement* stuelement in studentArray) {
// //初始化一个字典
// NSMutableDictionary* studentDic=[[NSMutableDictionary alloc] init];
//// NSString* name=[[[stuelement elementsForName:@"name"] firstObject] stringValue];
// //获取name节点
// GDataXMLElement* nameElement=[stuelement elementsForName:@"name"].firstObject;
// //取出节点中的值
// NSString* name=[nameElement stringValue];
// //将name的值放入字典中
// [studentDic setObject:name forKey:@"name"];
//
// //获取age节点
// GDataXMLElement* ageElement=[stuelement elementsForName:@"age"].firstObject;
// NSString* age=[ageElement stringValue];
// [studentDic setObject:age forKey:@"age"];
//
// //获取sex节点
// GDataXMLElement* sexElement=[stuelement elementsForName:@"sex"].firstObject;
// NSString* sex=[sexElement stringValue];
// [studentDic setObject:sex forKey:@"sex"];
// //将字典放入数组中
// [allStudentsArray addObject:studentDic];
// }
// NSLog(@"----%@",allStudentsArray);
for (GDataXMLElement* studentNode in studentArray) {
//遍历获取student所有的子节点
NSArray* subStudentNode=[studentNode children];
NSMutableDictionary* studentDic=[[NSMutableDictionary alloc] init];
for (GDataXMLElement* subOfStudentNode in subStudentNode) {
//获取子节点的名称
NSString* noteName=[subOfStudentNode name];
//获取节点内容
NSString* noteValue=[subOfStudentNode stringValue];
[studentDic setObject:noteValue forKey:noteName];
}
// 将字典加入到数组中
[allStudentsArray addObject:studentDic];
}
NSLog(@"----%@",allStudentsArray);
}
3.JSON解析
//json解析
-(void)jsonParser{
//获取要解析的json源文件
NSString* jsonPath=[[NSBundle mainBundle] pathForResource:@"DemoJson" ofType:@"json"];
NSString* jsonStr=[NSString stringWithContentsOfFile:jsonPath encoding:NSUTF8StringEncoding error:nil];
//字符串转data类型
NSData* jsonData=[jsonStr dataUsingEncoding:NSUTF8StringEncoding];
//json解析
NSDictionary* dic= [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];
NSLog(@"---%@",dic);
}