一、解析的基本概念
解析数据就是从事先准备好的数据格式中提取数据,常见的数据格式有XML和JSON数据格式。iOS对两种数据格式都提供了解析方式。
二、xml数据结构解析
xml:Extensible Markup Language(可扩展标记语言)。
下面是一段解析文件的示例:
<?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的方式进行解析:
//dom解析XML文件
-(void)domParser{
//获得文件路径
NSString* path = [[NSBundle mainBundle]pathForResource:@"XMLDemo" ofType:@"xml"];
//见文件转化为data类型
NSData* XMLData = [NSData dataWithContentsOfFile:path];
//将文件类型,通过note对象,转化为树形结构(一次性从内存中将xml文件转化为倒着的树形结构),在这里意味着将文件内容已经拉入了项目空间进行操作。
GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:XMLData options:0 error:nil];
//得到根节点
GDataXMLElement *rootElement = [doc rootElement];
//得到根节点的所有以“student”命名的子节点
NSArray* stuArr = [rootElement elementsForName:@"student"];
//初始化可变数组,用来存放学生的信息(需要注意的是,这里必须了解xml文件的数据结构,确定节点的末尾)
NSMutableArray* stumArr = [NSMutableArray array];
//得到所有Student节点的所有子节点,即Student对象中具体的个人
for (GDataXMLElement* itemElement in stuArr) {
NSArray* nameElement = [itemElement elementsForName:@"name"];
//从节点中取值
NSString *nameStr = [[nameElement objectAtIndex:0] stringValue];
NSArray* sexArr = [itemElement elementsForName:@"sex"];
NSString *sexStr = [[sexArr objectAtIndex:0] stringValue];
NSArray *ageArr = [itemElement elementsForName:@"age"];
NSString *ageStr = [[ageArr objectAtIndex:0] stringValue];
NSDictionary *dic = [[NSDictionary alloc]initWithObjectsAndKeys:nameStr,@"name",sexStr,@"sex",ageStr,@"age", nil];
[stumArr addObject:dic];
}
NSLog(@"%@",stumArr);
}
然后看看sax解析的方式:
//xml的sax解析
-(void)saxParser{
//获得文件路径
NSString* pathStr = [[NSBundle mainBundle] pathForResource:@"XMLDemo" ofType:@"xml"];
//转化为data文件
NSData* data = [NSData dataWithContentsOfFile:pathStr];
//sax解析
NSXMLParser* parser= [[NSXMLParser alloc] initWithData:data];
//指定代理,并导入协议,在sax解析的方式里,是通过逐行解析的方式去解析xml文件,在dialing方法中分步执行
[parser setDelegate:self];
//开始解析(同步,意思是解析不完成,下面的代码就不会执行)
BOOL isSuccessful = [parser parse];
if (isSuccessful) {
NSLog(@"解析成功");
}else{
NSLog(@"解析失败");
}
}
#pragma mark <NSXMLParserDelegate>
//开始解析
-(void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(@"开始解析%s",__FUNCTION__);
//初始化一个最大的容器
self.allStudentMArr = [NSMutableArray array];
}
//开始解析节点
/**
* Description
*
* @param parser 解析对象
* @param elementName 标签名称
* @param namespaceURI 命名空间指向的链接
* @param qName 命名空间的名称
* @param attributeDict 节点的属性
*/
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
NSLog(@"开始解析节点%s",__FUNCTION__);
if ([elementName isEqualToString:@"student"]) {
//当解析到Student的时候,说明已经到了获取该节点的子节点的时候了,所以应该初始化容器了
self.singleStudentMDic = [NSMutableDictionary dictionary];
}
}
//开始取值
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
NSLog(@"取值%s",__FUNCTION__);
if (self.noteValueString) {
// [self.noteValueString appendString:string];
NSString* str = [self.noteValueString stringByAppendingString:string];
// self.noteValueString = [str mutableCopy];
self.noteValueString = [NSMutableString stringWithString:str];
}else{
self.noteValueString = [NSMutableString stringWithString:string];
}
}
//解析完毕某个节点
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:@"name"]) {
[self.singleStudentMDic setObject: [self replaceStringWithString:self.noteValueString] forKey:elementName];
}
//每次解析玩一个节点,我们都需要将可变字符串清理一次,因为可变字符串是多次使用的
if ([elementName isEqualToString:@"sex"]) {
[self.singleStudentMDic setObject: [self replaceStringWithString:self.noteValueString] forKey:elementName];
}
if ([elementName isEqualToString:@"age"]) {
[self.singleStudentMDic setObject: [self replaceStringWithString:self.noteValueString] forKey:elementName];
}
if ([elementName isEqualToString:@"student"]) {
[self.allStudentMArr addObject:self.singleStudentMDic];
}
//每次对解析完毕的节点,必须将存储字符串置空。
self.noteValueString = nil;
}
//解析完毕
-(void)parserDidEndDocument:(NSXMLParser *)parser{
NSLog(@"%s",__FUNCTION__);
NSLog(@"%@",self.allStudentMArr);
}
//自定义的方法
-(NSString*)replaceStringWithString:(NSMutableString*)sourceString{
//剔除字符串中的空格、换行、制表符
NSString* resultString = [sourceString stringByReplacingOccurrencesOfString:@"\n" withString:@"" ];
resultString = [resultString stringByReplacingOccurrencesOfString:@"\r" withString:@""];
resultString = [resultString stringByReplacingOccurrencesOfString:@"\t" withString:@""];
resultString = [resultString stringByReplacingOccurrencesOfString:@" " withString:@""];
return resultString;
}
同时注意:sax解析和dom解析时都需要导入第三方文件
包括json解析也需要进行该操作:
在引入第三方文件时,一般会遇到一些问题。
问题一:部分头文件报错
解决办法:
在工程的设置界面,设置文件路径:
问题二:导入文件报错
解决办法:
如果是因为内存管理方式的报错,那么在ARC模式下添加MRC模式就可以了。
同样,dom解析还有另一个功能,是可以创建xml节点。
demo如下:
demo如下:
//通过dom解析的方式,为xml增加节点(sax解析只可以读取,不可添加)
-(void)domAddNote{
//获得文件路径
NSString* path = [[NSBundle mainBundle]pathForResource:@"XMLDemo" ofType:@"xml"];
//见文件转化为data类型
NSData* XMLData = [NSData dataWithContentsOfFile:path];
//将文件类型,通过note对象,转化为树形结构(一次性从内存中将xml文件转化为倒着的树形结构)
GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:XMLData options:0 error:nil];
//得到根节点
GDataXMLElement *rootElement = [doc rootElement];
//创建一个我们需要添加的节点(Student)
GDataXMLElement *creatElement = [GDataXMLNode elementWithName:@"student"];
GDataXMLElement* nameElement = [GDataXMLElement elementWithName:@"name" stringValue:@"金鹏"];
[creatElement addChild:nameElement];
GDataXMLElement* ageElement = [GDataXMLElement elementWithName:@"age" stringValue:@"99"];
[creatElement addChild:ageElement];
GDataXMLElement* sexElement = [GDataXMLElement elementWithName:@"sex" stringValue:@"男男女女"];
[creatElement addChild:sexElement];
[rootElement addChild:creatElement];
//得到根节点的所有子节点
NSArray* stuArr = [rootElement elementsForName:@"student"];
//初始化可变数组,用来存放学生的信息
NSMutableArray* stumArr = [NSMutableArray array];
//得到所有Student节点的所有子节点,即Student对象中具体的个人
for (GDataXMLElement* itemElement in stuArr) {
NSArray* nameElement = [itemElement elementsForName:@"name"];
NSString *nameStr = [[nameElement objectAtIndex:0] stringValue];
NSArray* sexArr = [itemElement elementsForName:@"sex"];
NSString *sexStr = [[sexArr objectAtIndex:0] stringValue];
NSArray *ageArr = [itemElement elementsForName:@"age"];
NSString *ageStr = [[ageArr objectAtIndex:0] stringValue];
NSDictionary *dic = [[NSDictionary alloc]initWithObjectsAndKeys:nameStr,@"name",sexStr,@"sex",ageStr,@"age", nil];
[stumArr addObject:dic];
}
NSLog(@"%@",stumArr);
}
三、json数据结构与解析
json数据示例:
{
"reason":"success",
"result":[
{
"movieId":"216609",
"movieName":"诡八楼",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583083"
},
{
"movieId":"216391",
"movieName":"摩登森林之美食总动员",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583246"
},
{
"movieId":"216162",
"movieName":"龟兔再跑",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583181"
},
{
"movieId":"215977",
"movieName":"森林孤影",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583247"
},
{
"movieId":"215874",
"movieName":"从哪来,到哪去",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583542"
},
{
"movieId":"215823",
"movieName":"有一天",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583092"
},
{
"movieId":"215372",
"movieName":"兰辉",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583163"
},
{
"movieId":"215365",
"movieName":"我是你的野蛮女友",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583708"
},
{
"movieId":"215115",
"movieName":"触不可及",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583077"
},
{
"movieId":"212024",
"movieName":"死亡派对",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583084"
},
{
"movieId":"210860",
"movieName":"女生宿舍",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583157"
},
{
"movieId":"209708",
"movieName":"不惧风暴",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583080"
},
{
"movieId":"206446",
"movieName":"黎明之眼",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583098"
},
{
"movieId":"205991",
"movieName":"一生一世",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583079"
},
{
"movieId":"205238",
"movieName":"缘来是游戏",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583162"
},
{
"movieId":"190893",
"movieName":"美女与野兽",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583090"
},
{
"movieId":"190537",
"movieName":"敢死队3",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583082"
},
{
"movieId":"183090",
"movieName":"空中营救",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583076"
},
{
"movieId":"181874",
"movieName":"动物也疯狂",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583243"
},
{
"movieId":"179197",
"movieName":"绝密跟踪",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583081"
},
{
"movieId":"174132",
"movieName":"分歧者:异类觉醒",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583102"
},
{
"movieId":"169864",
"movieName":"猩球崛起:黎明之战",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583078"
},
{
"movieId":"128888",
"movieName":"挑战者联盟",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583248"
},
{
"movieId":"49362",
"movieName":"共和国之旗",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583541"
},
{
"movieId":"42201",
"movieName":"红旗谱",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583536"
},
{
"movieId":"28678",
"movieName":"原色深海",
"pic_url":"http:\/\/v.juhe.cn\/movie\/picurl?2583539"
}
],
"error_code":0
}
解析demo:
//JSON解析
-(void)jsonData{
//先得到json文件的路径
NSString* path = [[NSBundle mainBundle]pathForResource:@"MovieList" ofType:@"txt"];
//将数据类型转化为nsdata类型
NSData *data = [NSData dataWithContentsOfFile:path];
NSString *dataString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSLog(@"%@",dataString);
//解析
NSError *error;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSLog(@"%@",dic);
}
当json数据串不是标准的数据文件时,需要对转化为的string进行剪切操作,从而进行工作。