数据解析 - XML

XML: 可扩展标记语言(eXtensible Markup Language), 一般也叫XML文档(XML Document)

XML常用的解析方式

  1. 苹果原生: NSXMLParser-SAX 方式解析, 使用简单
  2. 第三方框架: GDataXML: DOM的解析方式, 是有谷歌开发的, 底层基于libxml2

XML解析数据结构


    
        刘备
        玄德
        汉贼不两立,王业不偏安
        雌雄一对剑
    

    
        关羽
        云长
        吾弟张翼德于百万军中取上将首级,如探囊取物
        青龙偃月刀
    


解析数据对应的model类

Student.h 文件

#import 

@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解析方式

解析思想: 逐行进行解析
  1. 找到解析文档的目录地址
  1. 找到开始标签
    2.1 找到子标签开始标签
    2.2 找到含有内容的子标签的开始标签
    2.3 提取内容
    2.4 找到含有内容的子标签的结束标签
    2.5 找到子标签结束标签
    2.6 找到结束标签
  2. 循环开始, 直到遇到根节点的结束标签结束解析

NSXMLParser解析实现过程

#import "ViewController.h"
//引入Model类
#import "Student.h"
//第一步: 遵循代理协议
@interface ViewController ()
//设置数据源数组
@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 *)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```

你可能感兴趣的:(数据解析 - XML)