XML的两种解析方法及区别:
1.SAX 解析,逐行解析,(采用协议回调机制)速度慢 OC级别解析.
2.DOM 解析,全体读,再分树形结构,C语言级别解析 ,是SAX解析的十几倍.
SAX 解析
解析方法
// 获取bundle包内xml 文件路径
NSString *bundle = [[NSBundle mainBundle] pathForResource:@"Student" ofType:@"xml"];
// 转换为二进制对象
NSData *data = [NSData dataWithContentsOfFile:bundle];
// 以二进制对象初始化
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
//开始解析
[parser parse];
[parser release];
关于节点名称,最好定义为静态变量,这样后面用起来方便,而且不易写错
// 方便使用,不易写错
static NSString *kRoot = @"root";
static NSString *kStuArray = @"stu_array";
static NSString *kStudent = @"student";
static NSString *kName = @"name";
static NSString *kAge = @"age";
static NSString *kTel = @"tel";
遵循 NSXMLParserDelegate 协议,并且实现下面三个方法
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
在开始解析方法里,我们要判断什么时候创建字典,以及什么时候创建model对象
#pragma mark - 开始解析
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// 判断什么时候创建字典
if ([elementName isEqualToString:kStuArray]) {
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
// 取出 attributeDict 里的值,存入 dic 里面
[dic addEntriesFromDictionary:attributeDict];
// 创建存放学生的数组
NSMutableArray *stus = [NSMutableArray array];
[dic setObject:stus forKey:@"array"];
// dic 存入数组
[_stuArray addObject:dic];
}
// 判断什么时候创建学生对象
if ([elementName isEqualToString:kStudent]) {
StudentModel *stu = [[StudentModel alloc] init];
// 找到 学生对应的字典 里的数组
NSMutableDictionary *lastDic = [_stuArray lastObject];
NSMutableArray *lastArray = [lastDic objectForKey:@"array"];
[lastArray addObject:stu];
[stu release];
}
取值函数我们只要将获得的字符串存起来,以结束解析时,根据判断,来确定取出来的十model的哪一个属性值,
@interface SaxXmlParser : NSObject<NSXMLParserDelegate>
{
NSMutableArray *_stuArray;
// 测试存值不能是成员变量,会崩溃!!!!!!!!!!!!!
// NSString *_currentValue;
}
// 测试存值设置为属性!!!!!!!!!!!!!
@property (nonatomic,copy) NSString *currentValue;
这里要注意,接收字符串的变量,要定义为属性,不要定义为成员变量,定义为成员变量会崩溃
#pragma mark - 取值
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// 获取字符串,传给 结束解析函数,进行判断是哪一个属性
self.currentValue = string;
// NSLog(@"解析中...");
// NSLog(@"\nparser == %@\nstring == %@",parser,string);
}
解析结束方法里,判断取出来的字符串是model的哪一个属性
#pragma mark -结束解析
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// 判断取出来的是 student哪个属性
if ([elementName isEqualToString:kName]) {
NSMutableDictionary *dic = [_stuArray lastObject];
NSMutableArray *array = [dic objectForKey:@"array"];
StudentModel *stu = [array lastObject];
stu.name = _currentValue;
}
if ([elementName isEqualToString:kAge]) {
NSMutableDictionary *dic = [_stuArray lastObject];
NSMutableArray *array = [dic objectForKey:@"array"];
StudentModel *stu = [array lastObject];
stu.age = _currentValue;
}
if ([elementName isEqualToString:kTel]) {
NSMutableDictionary *dic = [_stuArray lastObject];
NSMutableArray *array = [dic objectForKey:@"array"];
StudentModel *stu = [array lastObject];
stu.tel = _currentValue;
}
// 判断解析完事
if ([elementName isEqualToString:kRoot]) {
NSLog(@"_stuArray == %@",_stuArray);
// 5.调用协议方法
[self.delegate sendArrayToMainView:_stuArray];
}
// NSLog(@"结束解析");
// NSLog(@"\nparser == %@\nelementName == %@\nnamespaceURI == %@\nqName == %@",parser,elementName,namespaceURI,qName);
}
至此,SAX解析完成。可以用协议传值,将获得的数组传给其他页面
DOM 解析
DOM解析的准备工作:
1.准备好GDataXMLNode 第三方类,这是Google写的
2.导入libxml2.dylib 类库
3.添加 Header Search Paths 如下图
#pragma mark DOM 解析
- (void)domParser
{
NSString *str = [[NSBundle mainBundle] pathForResource:@"Student" ofType:@"xml"];
NSData *data =[NSData dataWithContentsOfFile:str];
NSError *error = nil;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:GDataXMLDocumentKind error:&error];
if (error) {
NSLog(@"error = %@",error);
}
// 获得根节点
GDataXMLElement *root = [doc rootElement];
// NSLog(@"\nroot == %@",root);
// 获取 节点名为 stu_list 的所有 节点数组
NSArray *array = [root elementsForName:@"stu_list"];
// NSLog(@"array = %@",array);
// // 获取 节点名为 stu_array 的所有 节点数组
GDataXMLElement *stu_list = [array firstObject];
NSArray *stuArray = [stu_list elementsForName:@"stu_array"];
// 获取数组里 节点
for (GDataXMLElement *stuA in stuArray) {
// 获得属性名为 name 的节点
GDataXMLNode *node = [stuA attributeForName:@"name"];
// 取节点所对应的内容
NSString *attStr = [node stringValue];
// 存入字典
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setObject:attStr forKey:@"name"];
// 字典里存数组
NSMutableArray *array = [NSMutableArray array];
[dic setObject:array forKey:@"array"];
// 将字典存入大数组
[_stuArray addObject:dic];
// 获得节点名为 student 的所有节点
NSArray *students = [stuA elementsForName:@"student"];
// 遍历
for (GDataXMLElement *stu in students) {
// 创建model 添加到数组
StudentModel *model = [[StudentModel alloc] init];
[array addObject:model];
// 获得所有student 子节点
NSArray *children = [stu children];
for (GDataXMLElement *child in children) {
// 取出节点的内容
NSString *childValue = [child stringValue];
// 判断节点名
if ([[child name] isEqualToString:@"name"]) {
model.name = childValue;
}
if ([[child name] isEqualToString:@"age"]) {
model.age = childValue;
}
if ([[child name] isEqualToString:@"tel"]) {
model.tel = childValue;
}
}
}
}
}
一下是xml内数据结构
<root>
<stu_list>
<stu_array name = "A">
<student>
<name>小苹果</name>
<age>18</age>
<tel>120</tel>
</student>
<student>
<name>蓝翔</name>
<age>20</age>
<tel>110</tel>
</student>
</stu_array>
<stu_array name = "B">
<student>
<name>杀马特</name>
<age>19</age>
<tel>100</tel>
</student>
<student>
<name>土豆</name>
<age>20</age>
<tel>120</tel>
</student>
</stu_array>
</stu_list>
</root>