XML文件写法
<Classes>//根节点
<Class1>//开始标签
<Students>
<Student position = "CEO">//"CEO"节点属性
//节点属性
<name>hmx</name>
<age>23</age>
<height>160</height>
<Student>
<name>xiaoming</name>
<age>24</age>
<height>170</height>
</Student>
</Students>
</Class1>
</Classes>
XML解析
SAX:逐行解析(主类:NSXMLParser)
逐行解析顾名思义就是一行一行的读取解析,需要遵循代理<NSXMLParserDelegate>
SAX一般分为5步
1.开始解析
- (void)parserDidStartDocument:(NSXMLParser *)parser;
2.开始解析标签
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict;
3.标签对应的值
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
4.结束解析标签
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
5.结束解析
- (void)parserDidEndDocument:(NSXMLParser *)parser;
以上面的Student为例子
1.创建一个Student的model类
//Student的model类h文件
#import <Foundation/Foundation.h>
@interface Student : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) float height;
@end
2.定义一个全局变量数组用来存储解析后的数据,定义一个全局变量用来存储标签,因为我们要通过标签来判断数据
@property (nonatomic, strong) NSMutableArray *studentArray;
@property (nonatomic, strong) NSString *currentElementName;
3.这里使用一个UIbutton动作来进行解析,点击button就进行XML解析,UIButton创建不在多说
//点击按钮进行解析
- (IBAction)SAXDidTapAction:(UIButton *)sender {
//获取文件绝对路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"student" ofType:@"txt"];
//创建一个NSData
NSData *data = [NSData dataWithContentsOfFile:path];
//初始化XMLParser
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:data];
xmlParser.delegate = self;
[xmlParser parse];
}
4.遵循协议,重写方法,记得数组需要先初始化
//开始解析
- (void)parserDidStartDocument:(NSXMLParser *)parser {
NSLog(@"DidStart");
}
//解析开始元素(标签)
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
//记录当前elementName
self.currentElementName = elementName;
//创建学生属性并添加到数组中
if ([elementName isEqualToString:@"Student"]) {
Student *student = [[Student alloc] init];
[self.studentArray addObject:student];
}
}
//每一个标签对应的值
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
//获取最后一个元素
Student *stu = [self.studentArray lastObject];
//KVC模式赋值,记得在Student类中重写方法
//- (void)setValue:(id)value forUndefinedKey:(NSString *)key;
[stu setValue:string forKey:self.currentElementName];
}
//解析结束标签
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
//这里设置为空的原因: foundCharacters方法在结束标签处会调用一次,
//不置为空会再次进入KVC赋值,Student内容会变为空或0
self.currentElementName = @"";
}
//结束解析
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(@"DidEnd");
for (Student *stu in self.studentArray) {
NSLog(@"%@", stu);
}
}
DOM解析:通过GDataXMLNode类进行解析,该类会将数据全部解析完毕,在使用前先做一些处理
1.将文件添加到工程(http://pan.baidu.com/s/1eSrvPgY)
2.在工程中添加动态库: libxml2.dylib
3.在工程的Build Settings中找到Header Search Path项 添加/usr/include/libxml2
4.将第三方库文件改为ARC MRC通用状态,找到Build Phases中的Compile Sources中的GDataXMLNode.m文件双击添加-fno-objc-arc
程序
- 初始化GDataXMLDocument
//data为路径,解析例子同SAX, data为SAX中的data
GDataXMLDocument *GDocument = [[GDataXMLDocument alloc] initWithData:data options:0 error:&error];
- 获取根节点
GDataXMLElement *rootElement = GDocument.rootElement;
- 获取子节点
for (GDataXMLElement *subElement in rootElement.children) {
Student *stu = [[Student alloc] init];
//找到student的子节点, 也就是name age height,然后赋值
for (GDataXMLElement *contactElement in subElement.children) {
[stu setValue:contactElement.stringValue forKey:contactElement.name];
}
[self.studentArray addObject:stu];
}
通过XMLDictionary类进行解析
NSDictionary *dict = [NSDictionary dictionaryWithXMLData:data];
NSArray *array = dict[@"Student"];
for (NSDictionary *stuDict in array) {
Student *stu = [[Student alloc] init];
[stu setValuesForKeysWithDictionary:stuDict];
[self.studentArray addObject:stu];
}
上面的均为简单的例子,下面来看一个比较复杂的例子,这里使用XMLDictionary类进行解析: Cartoon.xml进行解析
这里我们只需要两个数据,name跟desc
- 创建Model类
Model.h
@interface CartoonModel : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *desc;
@end
Model.m
#import "CartoonModel.h"
@implementation CartoonModel
//当没有找到key时会进入这个方法
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
}
@end
- 数据解析
//这里使用懒加载方法,cartoonArray为全局变量(NSMutableArray)
- (NSMutableArray *)cartoonArray {
if (!_cartoonArray) {
_cartoonArray = [[NSMutableArray alloc] init];
//获取绝对路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"Cartoon" ofType:@"xml"];
NSData *data = [NSData dataWithContentsOfFile:path];
//使用方法dictionaryWithXMLData将数据转换为字典
NSDictionary *dict = [NSDictionary dictionaryWithXMLData:data];
//通过字典的key获取下级字典
NSDictionary *resultDict = dict[@"results"];
//通过数组接收数据
NSArray *albumInfoDict = resultDict[@"AlbumInfo"];
//通过model类接收数组内部的各个model数据
for (NSDictionary *modelDict in albumInfoDict) {
CartoonModel *model = [[CartoonModel alloc] init];
//KVC模式赋值
[model setValuesForKeysWithDictionary:modelDict];
[_cartoonArray addObject:model];
}
}
return _cartoonArray;
}