数据解析 - XML

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

XML常用的解析方式

  1. 苹果原生: <b>NSXMLParser</b>-SAX 方式解析, 使用简单
  2. 第三方框架: <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解析方式

解析思想: 逐行进行解析
  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 ()<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```
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容