<b>XML</b>: 可扩展标记语言(eXtensible Markup Language), 一般也叫XML文档(XML Document)
XML常用的解析方式
- 苹果原生: <b>NSXMLParser</b>-SAX 方式解析, 使用简单
- 第三方框架: <b>GDataXML</b>: DOM的解析方式, 是有谷歌开发的, 底层基于libxml2
XML解析数据结构
<students>
<student>
<name>刘备</name>
<zi>玄德</zi>
<say>汉贼不两立,王业不偏安</say>
<weapon>雌雄一对剑</weapon>
</student>
<student>
<name>关羽</name>
<zi>云长</zi>
<say>吾弟张翼德于百万军中取上将首级,如探囊取物</say>
<weapon>青龙偃月刀</weapon>
</student>
</students>
解析数据对应的model类
Student.h 文件
#import <Foundation/Foundation.h>
@interface Student : NSObject
//model类属性, 对应XML文件中的标签名(属性)
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *zi;
@property (strong, nonatomic) NSString *say;
@property (strong, nonatomic) NSString *weapon;
@end
Student.m文件
#import "Student.h"
@implementation Student
//model类的容错处理(作用: 是为了防止model类中的属性和XML文件中的标签名不一致时, 发生崩溃现象)
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
}
//字符处理(自动控制台中打印结果时, 若输出为汉字防止出现乱码)
- (NSString *)description{
return [NSString stringWithFormat:@"%@, %@, %@, %@",self.name, self.zi, self.say, self.weapon];
}
@end
第一种 :NSXMLParser解析方式
解析思想: 逐行进行解析
- 找到解析文档的目录地址
- 找到开始标签
2.1 找到子标签开始标签
2.2 找到含有内容的子标签的开始标签
2.3 提取内容
2.4 找到含有内容的子标签的结束标签
2.5 找到子标签结束标签
2.6 找到结束标签 - 循环开始, 直到遇到根节点的结束标签结束解析
NSXMLParser解析实现过程
#import "ViewController.h"
//引入Model类
#import "Student.h"
//第一步: 遵循代理协议
@interface ViewController ()<NSXMLParserDelegate>
//设置数据源数组
@property (strong, nonatomic) NSMutableArray *dataArray;
//保存当前遍历到的标签
@property (strong, nonatomic) NSString *currentElement;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//第二步: 获取要解析的文件路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"XML" ofType:@"txt"];
//第三步: 利用得到的path, 创建一个NSData对象
NSData *data = [NSData dataWithContentsOfFile:path];
//第四步: 利用创建的NSData对象, 创建一个NSXMLParser解析对象
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
//第五步: 设置代理
parser.delegate = self;
//第六步: 利用创建的解析对象, 调用解析方法
[parser parse];
}
#pragma mark -------- 代理方法 --------
//方法一: 开始解析
- (void)parserDidStartDocument:(NSXMLParser *)parser{
//初始化数据源数组
self.dataArray = [NSMutableArray array];
}
//方法二: 解析到开始标签
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
//记录当前解析到的标签
self.currentElement = elementName;
//XML文档中标志着是一个完整对象的标签, 1.如果解析到该标签则:
if ([self.currentElement isEqualToString:@"student"]) {
//2.创建一个对应的model类对象
Student *stu = [Student new];
//3.并放到数据源数组中
[self.dataArray addObject:stu];
}
}
//方法三: 解析到标签的值
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
//从数组中取出最后一个对象, 也就是当前的对象
Student *stu = self.dataArray.lastObject;
//赋值
// //方法一: 分别给该对象的不同属性fuz
// if ([self.currentElement isEqualToString:@"name"]) {
//
// stu.name = string;
// }
// if ([self.currentElement isEqualToString:@"zi"]) {
//
// stu.zi = string;
// }
// if ([self.currentElement isEqualToString:@"say"]) {
//
// stu.say = string;
// }
// if ([self.currentElement isEqualToString:@"weapon"]) {
//
// stu.weapon = string;
// }
//方法二: 利用model类赋值
[stu setValue:string forKey:self.currentElement];
}
//方法四: 解析到结束标签
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//如果解析到结束标签,则需要将该结束标签置为Nil, 否则会将赋给model的值重新赋值为空(因为在解析到结束标签时, 会去调用解析到值的方法. 而在解析到值的方法中, 他不识别是结束标签还是开始标签, 会将结束标签和开始标签看成是同一个Key值, 再去给该Key值setValue, 而此时结束标签的value是空值, 所以解析得到的结果为空)
self.currentElement = nil;
}
//方法五: 结束解析
- (void)parserDidEndDocument:(NSXMLParser *)parser{
//遍历得到的结果
for (Student *stu in self.dataArray) {
NSLog(@"%@", stu);
}
}
@end```
###第二种 :DOM解析方式
DOM: Document Object Model(文档对象模型)
#####解析思想: 以树的形式进行存储, 通过遍历根节点的子节点-->子节点...解析数据
> 将整个XML文档读入, 构建驻留内存的树结构(节点🌲), 通过遍历树结构的任意节点, 读取他的属性和值
#####解析前奏:
因为DOM解析使用的是第三个GData工具, 所以在使用之前需要进行配置:
第一步: 获取到GDataXMLNode.h/m文件, 将GDataXMLNode.h导入工程
第二步: 添加类库libxml2.tdb到工程中
![85ADD32F-3D2F-4F6B-BB5F-72704283CFD3.png](http://upload-images.jianshu.io/upload_images/1803308-b65eb8abde9db322.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
第三步: 在工程的"Bulid settings"页面找到"Header search path"项, 添加"/user/include/libxml2"
![7$A5X)OW01EVHUQ%}NK~FND.jpg](http://upload-images.jianshu.io/upload_images/1803308-5b9638d7c6cd8e34.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
第四步: 因为GData第三方工具是在MRC下使用的, 所以入果在ARC下建立的工程, 需要处理一下ARC与MRC的混编操作.
![
](http://upload-images.jianshu.io/upload_images/1803308-a5fe5c9287227add.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
####解析实现过程
```code
#import "ViewController.h"
#import "GDataXMLNode.h"
#import "Student.h"
@interface ViewController ()
//创建数据源数组(用来存放解析的数据)
@property (strong, nonatomic) NSMutableArray *dataArray;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//第一步: 获取解析文件
NSString *path = [[NSBundle mainBundle] pathForResource:@"XML" ofType:@"txt"];
//第二步: 以NSData对象进行解析
NSData *data = [NSData dataWithContentsOfFile:path];
##//第三步: 创建GDataXMLDocument对象, 此时XML文件内的所有节点, 以树的形式存在于GDataXMLDocument对象中
GDataXMLDocument *gDataXml = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
//第四步: 获取XML文档的根节点, 根节点里面包含了XML文档中所有内容
GDataXMLElement *rootElement = [gDataXml rootElement];
//第五步: 初始化数组, 存放解析数据
self.dataArray = [NSMutableArray array];
//第六步: 遍历XML文件的根节点, 获取子节点
for (GDataXMLElement *sub in rootElement.children) {
//初始化model类(在此处初始化model类,是因为XML文件的结构, 具体情况根据得到的XML文件决定)
Student *stu = [Student new];
//遍历子节点下的子节点(标签) , 取出子标签中的内容
for (GDataXMLElement *contentElement in sub.children) {
//赋值第一种方法:
if([contentElement.name isEqualToString:@"name"]){
//赋值
stu.name = contentElement.stringValue;
}
if ([contentElement.name isEqualToString:@"zi"]) {
//赋值
stu.zi = contentElement.stringValue;
}
if ([contentElement.name isEqualToString:@"say"]) {
//赋值
stu.say = contentElement.stringValue;
}
if ([contentElement.name isEqualToString:@"weapon"]) {
//赋值
stu.weapon = contentElement.stringValue;
}
//赋值第二种方法: 使用KVC对stu整个属性赋值
// [stu setValue:contentElement.stringValue forKeyPath:contentElement.name];
}
//将遍历出的model对象 , 赋给数据源数组
[self.dataArray addObject:stu];
}
//遍历数组,输出解析数据
for (Student *stu in self.dataArray) {
NSLog(@"%@", stu);
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end```