iOS 中 XML 解析 NSXMLParse和GDataXMLNode的使用

XML解析

  • 可擴(kuò)展標(biāo)記語(yǔ)言
  • XML的特點(diǎn),出身名門,W3C制定,微軟和IBM曾經(jīng)共同大力推薦過(guò)的數(shù)據(jù)格式
  • XML 指可擴(kuò)展標(biāo)記語(yǔ)言(eXtensible Markup Language)
    • 被設(shè)計(jì)用來(lái)傳輸和存儲(chǔ)數(shù)據(jù)
    • HTML 是設(shè)計(jì)用來(lái)表示頁(yè)面的

SAX解析

SAX是iOS默認(rèn)的解析XML的方式,simple API for XML . 是一種占用內(nèi)存非常低,但是只能讀取不能寫入的解析方式.因?yàn)樗且恍幸恍械慕馕龅?

  • 準(zhǔn)備一個(gè)模型以及兩個(gè)屬性接收解析出來(lái)的數(shù)據(jù).
#import "ViewController.h"
//導(dǎo)入模型類
#import "VideoModel.h"

//遵守代理協(xié)議
@interface ViewController ()<NSXMLParserDelegate>

//用于保存模型的數(shù)組
@property(nonatomic,strong)NSMutableArray <VideoModel *>*modelArr;

//用于臨時(shí)保存解析出來(lái)的數(shù)據(jù).
@property(nonatomic,strong)NSMutableString *mStr;

@end
  • NSXMLParse 類進(jìn)行解析. 主要通過(guò)實(shí)現(xiàn)對(duì)象代理方法來(lái)解析.比較復(fù)雜.
@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
    //URL 加載本地Apache服務(wù)器的數(shù)據(jù)解析
    NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"];
    
    //通過(guò)Session自動(dòng)開啟線程進(jìn)行異步任務(wù).
    [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        //創(chuàng)建xml解析器
        NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
        //設(shè)置代理
        parser.delegate = self;
        //解析開始
        [parser parse];
    }] resume];
    
}

//初始化可變數(shù)組
- (NSMutableArray *)modelArr
{
    if (_modelArr == nil) {
        _modelArr = [NSMutableArray array];
    }
    return _modelArr;
}

//初始化可變字符串
- (NSMutableString *)mStr
{
    if (_mStr == nil) {
        _mStr = [NSMutableString string];
    }
    return _mStr;
}
  • 真正用于解析的代理方法 只用這5個(gè),前后兩對(duì)方法,加上中間一個(gè)獲取數(shù)據(jù)的方法.
/**
 開始解析
 */
- (void)parserDidStartDocument:(NSXMLParser *)parser;
{
    //這里只是開始,貌似不用做什么
}

/**
 開始一個(gè)新標(biāo)簽,這個(gè)時(shí)候應(yīng)該創(chuàng)建對(duì)應(yīng)的模型對(duì)象或者準(zhǔn)備為模型的屬性賦值.
 @param parser 解析器
 @param elementName 標(biāo)簽元素名字
 @param attributeDict 標(biāo)簽的屬性
 */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(NSDictionary<NSString *, NSString *> *)attributeDict;
{
    //看一下xml的結(jié)構(gòu),決定這里是干什么.對(duì)應(yīng)當(dāng)前的xml應(yīng)該是判斷后創(chuàng)建模型對(duì)象
    /*
     <videos>
     <video videoId="1">
     <name>01.C語(yǔ)言-語(yǔ)法預(yù)覽</name>
     <length>320</length>
     <videoURL>/itcast/videos/01.C語(yǔ)言-語(yǔ)法預(yù)覽.mp4</videoURL>
     <imageURL>/itcast/images/head1.png</imageURL>
     <desc>C語(yǔ)言-語(yǔ)法預(yù)覽</desc>
     <teacher>李雷</teacher>
     </video>
     */
    if ([elementName isEqualToString:@"video"]) {
        //創(chuàng)建新的模型對(duì)象
        VideoModel *model = [VideoModel new];
        //取出屬性,為videoId賦值
        model.videoId = @(attributeDict[@"videoId"].intValue);
        //將模型保存到數(shù)組
        [self.modelArr addObject:model];
    }
    
}



/**
 解析到標(biāo)簽中間的文字 標(biāo)簽中的文字不是一次性能讀完的,可能會(huì)分幾次調(diào)用這個(gè)方法,所以創(chuàng)建一個(gè)可變字符串保存起來(lái).

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



/**
 解析到一個(gè)元素結(jié)束的地方.

 @param parser 解析器
 @param elementName 元素名字
 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName;
{
    //進(jìn)行判斷,外層標(biāo)簽不進(jìn)行KVC,否則崩潰.如果標(biāo)簽過(guò)多也可以重寫model的方法 里面什么都不做就可以避免KVC報(bào)錯(cuò)
    //- (void)setValue:(id)value forUndefinedKey:(NSString *)key
    if (![elementName isEqualToString:@"video"] && ![elementName isEqualToString:@"videos"]) {
        //獲取當(dāng)前model
        VideoModel *model = self.modelArr.lastObject;
        //屬性的值就是解析出來(lái)的string,key則是標(biāo)簽的名字
        [model setValue:self.mStr forKey:elementName];
    }
    //最后對(duì)mStr進(jìn)行清空,準(zhǔn)備進(jìn)行下一個(gè)標(biāo)簽的解析
    self.mStr.string = @"";
}
/**
 結(jié)束解析
 */
- (void)parserDidEndDocument:(NSXMLParser *)parser;
{
    //所有標(biāo)簽解析完畢,打印數(shù)組看看是否轉(zhuǎn)換成功.
    NSLog(@"%@",self.modelArr);
}

@end

  • 當(dāng)然寫完以后一定記得封裝到對(duì)應(yīng)的模型中,創(chuàng)建模型方法.那么在控制器中一句代碼就搞定了.
- (NSArray *)parserXML:(NSString *)URLString;
{
    //URL
    NSURL *url = [NSURL URLWithString:URLString];   
    //通過(guò)Session自動(dòng)開啟線程進(jìn)行異步任務(wù).   
    [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        //創(chuàng)建xml解析器
        NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
        //設(shè)置代理
        parser.delegate = self;
        //解析開始
        [parser parse];
    }] resume];
    
    return self.modelArr;
}
控制器一句話搞定加載

DOM解析

因?yàn)閕OS不能直接使用MAC的解析方式,所以DOM解析使用第三方框架.GDataXMLNode
它有增加刪除等方法,頭文件里面有對(duì)應(yīng)的方法,這里我們僅使用它來(lái)進(jìn)行XML的反序列化. 也就是解析

如果你不是通過(guò)控制臺(tái)中pod加載的框架

  • pod init
  • pod GDataXML-HTML
  • pod install

那么你可能會(huì)碰到引入框架后#import <libxml/tree.h>報(bào)錯(cuò)的問(wèn)題.

按照注釋,在project->build Settings ->Header Search PathsOther Linker Flags 中分別添加兩個(gè)地址

  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
使用pod install 導(dǎo)入框架會(huì)自動(dòng)進(jìn)行配置,非常方便

DOM的解析有點(diǎn)類似于字典轉(zhuǎn)模型的過(guò)程.根據(jù)解析的XML的結(jié)構(gòu)不同嵌套層次也不同.
由于整個(gè)解析過(guò)程比較連貫,所以直接復(fù)制粘貼整段代碼

  • 下面是全部代碼,注釋非常詳細(xì).
#import "VideoModel.h"

#import <GDataXMLNode.h>

@interface ViewController ()


@end

@implementation ViewController



- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    //1. 通過(guò)URL獲取XML的Data數(shù)據(jù).
    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數(shù)據(jù),創(chuàng)建GData對(duì)象 這里創(chuàng)建方法接收的是一個(gè)XML的string,所以先轉(zhuǎn)換Data成String
        NSString *xmlString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        
        //這個(gè)方法可以進(jìn)去看看實(shí)現(xiàn),默認(rèn)是用UTF-8編碼
        GDataXMLDocument *GD = [[GDataXMLDocument alloc]initWithXMLString:xmlString error:nil];
        
        //3. 創(chuàng)建對(duì)象以后,取出根元素的子元素.返回的數(shù)組中都是GDataXMLElement
        NSArray *rootArr = GD.rootElement.children;
        
        //4. 那么現(xiàn)在要做的就是遍歷這個(gè)數(shù)組,對(duì)每一個(gè)元素進(jìn)行操作,轉(zhuǎn)換成模型了,這個(gè)過(guò)程類似于字典轉(zhuǎn)模型.
        
        //創(chuàng)建一個(gè)可變數(shù)組保存轉(zhuǎn)換好的模型
        NSMutableArray *modelArrM = [NSMutableArray array];
        for (GDataXMLElement *element in rootArr) {
            
            
            // 1. 取出數(shù)組中的每一個(gè)元素后,先將這一組的video標(biāo)簽的屬性videoId取出來(lái)
            /*
             1. 屬性返回的是一個(gè)數(shù)組,我們的屬性只有一個(gè),所以取出第一個(gè).元素類型是GDataXMLNode
             2. 通過(guò)這個(gè)結(jié)構(gòu)我們不難發(fā)現(xiàn),elment對(duì)應(yīng)的是一個(gè)樹枝節(jié)點(diǎn),它包含attributes數(shù)組,`屬性`一定是到頭了,是葉子節(jié)點(diǎn).所以這個(gè)數(shù)組中存的是多個(gè)GDataXMLNode類型的元素.
             3. GDataXMLNode是GDataXMLElement的父類.node有對(duì)應(yīng)的方法name,stringValue.返回鍵值對(duì).
             */
            GDataXMLNode *node = element.attributes.firstObject;
            //NSLog(@"name = %@ value = %@",node.name,node.stringValue);
            
            //2. 創(chuàng)建一個(gè)模型將video標(biāo)簽的屬性保存 KVC
            VideoModel *model = [VideoModel new];
            [model setValue:node.stringValue forKey:node.name];
            
            //3. 取出video標(biāo)簽的子標(biāo)簽,數(shù)組,每個(gè)子元素依然是GDataXMLElement 代表著一個(gè)一個(gè)的標(biāo)簽.
            //NSLog(@"element.children = %@",[element.children.firstObject class]);
            
            //循環(huán)遍歷數(shù)組
            for (GDataXMLElement *elementTag in element.children) {
                //4. 這里的每一個(gè)tag就是最后的葉子借點(diǎn)了. name 是 key xml是value
                //NSLog(@"%@",elementTag);
                [model setValue:elementTag.XMLString forKey:elementTag.name];
                
            }
            
            //5. 將添加完元素的模型保存到數(shù)組
            [modelArrM addObject:model];
            
        }
        
        //轉(zhuǎn)換完畢,看看結(jié)果
        NSLog(@"%@",modelArrM);
        
    }] resume];
      
}
@end

轉(zhuǎn)換完畢.看看結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,745評(píng)論 18 399
  • 1. XML總結(jié) 1.1. XML簡(jiǎn)介 XML : 可擴(kuò)展的標(biāo)記語(yǔ)言。(和HTML非常類似的) 可擴(kuò)展的。 自定義...
    Ethan_Walker閱讀 3,378評(píng)論 0 12
  • JSON JSON和XML都是需要解析的 JSON是一種輕量級(jí)的數(shù)據(jù)格式,一般用于數(shù)據(jù)交互服務(wù)器返回給客戶端的數(shù)據(jù)...
    JonesCxy閱讀 2,015評(píng)論 2 10
  • 一、緒論 上周工作需要了解項(xiàng)目的一些大體內(nèi)容,結(jié)果在xml解析這一塊看的迷迷糊糊的,所以在這里把學(xué)習(xí)到xm...
    cao健強(qiáng)閱讀 4,551評(píng)論 1 7
  • 一、用戶指標(biāo) 新增用戶(新用戶):第一次啟動(dòng)應(yīng)用的用戶(以設(shè)備為判斷標(biāo)準(zhǔn))數(shù)。 活躍用戶:?jiǎn)?dòng)過(guò)應(yīng)用的用戶(按照設(shè)...
    Smile竹_閱讀 1,044評(píng)論 0 1

友情鏈接更多精彩內(nèi)容