iOS 中 XML 解析 NSXMLParse和GDataXMLNode的使用

XML解析

  • 可扩展标记语言
  • XML的特点,出身名门,W3C制定,微软和IBM曾经共同大力推荐过的数据格式
  • XML 指可扩展标记语言(eXtensible Markup Language)
    • 被设计用来传输和存储数据
    • HTML 是设计用来表示页面的

SAX解析

SAX是iOS默认的解析XML的方式,simple API for XML . 是一种占用内存非常低,但是只能读取不能写入的解析方式.因为他是一行一行的解析的.

  • 准备一个模型以及两个属性接收解析出来的数据.
#import "ViewController.h"
//导入模型类
#import "VideoModel.h"

//遵守代理协议
@interface ViewController ()

//用于保存模型的数组
@property(nonatomic,strong)NSMutableArray *modelArr;

//用于临时保存解析出来的数据.
@property(nonatomic,strong)NSMutableString *mStr;

@end
  • NSXMLParse 类进行解析. 主要通过实现对象代理方法来解析.比较复杂.
@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
    //URL 加载本地Apache服务器的数据解析
    NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"];
    
    //通过Session自动开启线程进行异步任务.
    [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        //创建xml解析器
        NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
        //设置代理
        parser.delegate = self;
        //解析开始
        [parser parse];
    }] resume];
    
}

//初始化可变数组
- (NSMutableArray *)modelArr
{
    if (_modelArr == nil) {
        _modelArr = [NSMutableArray array];
    }
    return _modelArr;
}

//初始化可变字符串
- (NSMutableString *)mStr
{
    if (_mStr == nil) {
        _mStr = [NSMutableString string];
    }
    return _mStr;
}
  • 真正用于解析的代理方法 只用这5个,前后两对方法,加上中间一个获取数据的方法.
/**
 开始解析
 */
- (void)parserDidStartDocument:(NSXMLParser *)parser;
{
    //这里只是开始,貌似不用做什么
}

/**
 开始一个新标签,这个时候应该创建对应的模型对象或者准备为模型的属性赋值.
 @param parser 解析器
 @param elementName 标签元素名字
 @param attributeDict 标签的属性
 */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(NSDictionary *)attributeDict;
{
    //看一下xml的结构,决定这里是干什么.对应当前的xml应该是判断后创建模型对象
    /*
     
     
     */
    if ([elementName isEqualToString:@"video"]) {
        //创建新的模型对象
        VideoModel *model = [VideoModel new];
        //取出属性,为videoId赋值
        model.videoId = @(attributeDict[@"videoId"].intValue);
        //将模型保存到数组
        [self.modelArr addObject:model];
    }
    
}



/**
 解析到标签中间的文字 标签中的文字不是一次性能读完的,可能会分几次调用这个方法,所以创建一个可变字符串保存起来.

 @param parser 解析器
 @param string 文字
 */
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
{
    [self.mStr appendString:string];
}



/**
 解析到一个元素结束的地方.

 @param parser 解析器
 @param elementName 元素名字
 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName;
{
    //进行判断,外层标签不进行KVC,否则崩溃.如果标签过多也可以重写model的方法 里面什么都不做就可以避免KVC报错
    //- (void)setValue:(id)value forUndefinedKey:(NSString *)key
    if (![elementName isEqualToString:@"video"] && ![elementName isEqualToString:@"videos"]) {
        //获取当前model
        VideoModel *model = self.modelArr.lastObject;
        //属性的值就是解析出来的string,key则是标签的名字
        [model setValue:self.mStr forKey:elementName];
    }
    //最后对mStr进行清空,准备进行下一个标签的解析
    self.mStr.string = @"";
}
/**
 结束解析
 */
- (void)parserDidEndDocument:(NSXMLParser *)parser;
{
    //所有标签解析完毕,打印数组看看是否转换成功.
    NSLog(@"%@",self.modelArr);
}

@end

  • 当然写完以后一定记得封装到对应的模型中,创建模型方法.那么在控制器中一句代码就搞定了.
- (NSArray *)parserXML:(NSString *)URLString;
{
    //URL
    NSURL *url = [NSURL URLWithString:URLString];   
    //通过Session自动开启线程进行异步任务.   
    [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        //创建xml解析器
        NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
        //设置代理
        parser.delegate = self;
        //解析开始
        [parser parse];
    }] resume];
    
    return self.modelArr;
}
iOS 中 XML 解析 NSXMLParse和GDataXMLNode的使用_第1张图片
控制器一句话搞定加载

DOM解析

因为iOS不能直接使用MAC的解析方式,所以DOM解析使用第三方框架.GDataXMLNode
它有增加删除等方法,头文件里面有对应的方法,这里我们仅使用它来进行XML的反序列化. 也就是解析

如果你不是通过控制台中pod加载的框架

  • pod init
  • pod GDataXML-HTML
  • pod install

那么你可能会碰到引入框架后#import 报错的问题.

按照注释,在project->build Settings ->Header Search PathsOther Linker Flags 中分别添加两个地址

  1. /usr/include/libxml2
  2. -lxml2
  • 原文注释
// libxml includes require that the target Header Search Paths contain
//
//   /usr/include/libxml2
//
// and Other Linker Flags contain
//
//   -lxml2
iOS 中 XML 解析 NSXMLParse和GDataXMLNode的使用_第2张图片
使用pod install 导入框架会自动进行配置,非常方便

DOM的解析有点类似于字典转模型的过程.根据解析的XML的结构不同嵌套层次也不同.
由于整个解析过程比较连贯,所以直接复制粘贴整段代码

  • 下面是全部代码,注释非常详细.
#import "VideoModel.h"

#import 

@interface ViewController ()


@end

@implementation ViewController



- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    //1. 通过URL获取XML的Data数据.
    NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"];
    
    [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //2. 获取到Data数据,创建GData对象 这里创建方法接收的是一个XML的string,所以先转换Data成String
        NSString *xmlString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        
        //这个方法可以进去看看实现,默认是用UTF-8编码
        GDataXMLDocument *GD = [[GDataXMLDocument alloc]initWithXMLString:xmlString error:nil];
        
        //3. 创建对象以后,取出根元素的子元素.返回的数组中都是GDataXMLElement
        NSArray *rootArr = GD.rootElement.children;
        
        //4. 那么现在要做的就是遍历这个数组,对每一个元素进行操作,转换成模型了,这个过程类似于字典转模型.
        
        //创建一个可变数组保存转换好的模型
        NSMutableArray *modelArrM = [NSMutableArray array];
        for (GDataXMLElement *element in rootArr) {
            
            
            // 1. 取出数组中的每一个元素后,先将这一组的video标签的属性videoId取出来
            /*
             1. 属性返回的是一个数组,我们的属性只有一个,所以取出第一个.元素类型是GDataXMLNode
             2. 通过这个结构我们不难发现,elment对应的是一个树枝节点,它包含attributes数组,`属性`一定是到头了,是叶子节点.所以这个数组中存的是多个GDataXMLNode类型的元素.
             3. GDataXMLNode是GDataXMLElement的父类.node有对应的方法name,stringValue.返回键值对.
             */
            GDataXMLNode *node = element.attributes.firstObject;
            //NSLog(@"name = %@ value = %@",node.name,node.stringValue);
            
            //2. 创建一个模型将video标签的属性保存 KVC
            VideoModel *model = [VideoModel new];
            [model setValue:node.stringValue forKey:node.name];
            
            //3. 取出video标签的子标签,数组,每个子元素依然是GDataXMLElement 代表着一个一个的标签.
            //NSLog(@"element.children = %@",[element.children.firstObject class]);
            
            //循环遍历数组
            for (GDataXMLElement *elementTag in element.children) {
                //4. 这里的每一个tag就是最后的叶子借点了. name 是 key xml是value
                //NSLog(@"%@",elementTag);
                [model setValue:elementTag.XMLString forKey:elementTag.name];
                
            }
            
            //5. 将添加完元素的模型保存到数组
            [modelArrM addObject:model];
            
        }
        
        //转换完毕,看看结果
        NSLog(@"%@",modelArrM);
        
    }] resume];
      
}
@end

iOS 中 XML 解析 NSXMLParse和GDataXMLNode的使用_第3张图片
转换完毕.看看结果

你可能感兴趣的:(iOS 中 XML 解析 NSXMLParse和GDataXMLNode的使用)