iOS開(kāi)發(fā)——XML/JSON數(shù)據(jù)解析


除了XML和Json,文中還涉及到的一些知識(shí):第三方類(lèi)庫(kù)的使用,獲取本地文件內(nèi)容,網(wǎng)站API使用,GCD多線程編程,不做詳細(xì)介紹,在代碼出現(xiàn)的地方會(huì)注明。

先安利一波:

Json
XML

大數(shù)據(jù)時(shí)代,我們需要從網(wǎng)絡(luò)中獲取海量的新鮮的各種信息,就不免要跟著兩個(gè)家伙打交道,這是兩種結(jié)構(gòu)化的數(shù)據(jù)交換格式。一般來(lái)講,我們會(huì)從網(wǎng)絡(luò)獲取XML或者Json格式的數(shù)據(jù),這些數(shù)據(jù)有著特定的數(shù)據(jù)結(jié)構(gòu),必須對(duì)其進(jìn)行解析,得到我們可以處理的數(shù)據(jù)。所謂“解析”,就是從事先規(guī)定好的格式串中提取數(shù)據(jù)。解析的前提是數(shù)據(jù)的提供方與獲取方提前約定好格式,數(shù)據(jù)提供方按照格式提供數(shù)據(jù),數(shù)據(jù)獲取方按照格式獲取數(shù)據(jù)。

iOS開(kāi)發(fā)中,幾乎只要是與網(wǎng)絡(luò)相關(guān)的應(yīng)用,都離不開(kāi)對(duì)網(wǎng)絡(luò)數(shù)據(jù)的解析與應(yīng)用?,F(xiàn)總結(jié)幾種常用方式來(lái)解析網(wǎng)絡(luò)數(shù)據(jù):

  • Json格式:
    • NSJSONSerialization,官方提供的Json數(shù)據(jù)格式解析類(lèi),iOS5以后支持
    • JSONKit(第三方類(lèi)庫(kù))
    • SBJson
    • TouchJson
  • XML格式:
    • NSXMLParse,官方自帶
    • GDataXML,Google提供的開(kāi)元XML解析庫(kù)

按照目前的發(fā)展,Json正在逐步取代XML成為網(wǎng)絡(luò)數(shù)據(jù)的通用格式,所以我們重點(diǎn)來(lái)看Json格式的數(shù)據(jù)解析先。


準(zhǔn)備工作

在看如何使用Json和XML之前,我們還有些事情要做,一是準(zhǔn)備我們要解析的數(shù)據(jù),二是搭建一個(gè)界面來(lái)看實(shí)際效果,畢竟我們解析了數(shù)據(jù)就是要在應(yīng)用中展示出來(lái)的。

Json數(shù)據(jù)準(zhǔn)備

關(guān)于如何獲取網(wǎng)絡(luò)的數(shù)據(jù)在這里就不多贅述了,你只需要獲得一個(gè)從網(wǎng)站為開(kāi)發(fā)者提供的API接口中獲得我們想要的url就好了。我這里調(diào)用了豆瓣電影的API,隨便選了在豆瓣電影首頁(yè)的電影——《前任2:備胎反擊戰(zhàn)》,來(lái)看看豆瓣對(duì)這部電影的描述,由于標(biāo)簽太多,我這里只打算從中獲取電影名稱,體裁和劇情簡(jiǎn)介三部分打印出來(lái)。

我們可以先提前在瀏覽器中打開(kāi)看一下這個(gè)待會(huì)我們將要得到的東西:

是不是很亂。。。沒(méi)錯(cuò),網(wǎng)站返回的東西雖然看上去好像有點(diǎn)規(guī)律,但是還是難以辨別,這里不用擔(dān)心,我們可以使用一個(gè)叫做Json校驗(yàn)格式化工具的東西來(lái)優(yōu)化一下它的顯示,這里有一個(gè)在線的。我們把網(wǎng)站返回給我們的數(shù)據(jù)copy到這里,點(diǎn)擊校驗(yàn),如果沒(méi)有什么問(wèn)題的話,為了方便展示,我把它c(diǎn)opy到了Sublime中,我們看一下結(jié)果你會(huì)發(fā)現(xiàn)它變成了下面這個(gè)樣子,這樣看起來(lái)就舒服多了,我們也可以非常清楚地看到每一對(duì)“Key——Velue”對(duì),以及每個(gè)Velue的類(lèi)型,弄清楚了,待會(huì)兒方便我們查詢和顯示。

找到了目標(biāo),下一步我們先做個(gè)界面的模子出來(lái),展示我們解析過(guò)的數(shù)據(jù)。大概就是下面這個(gè)樣子,點(diǎn)擊不同的按鈕,可以以不同的方式解析獲得的數(shù)據(jù)并在TextView中打印。

界面搭好之后不要忘了關(guān)聯(lián)到代碼。

XML數(shù)據(jù)準(zhǔn)備

我們?cè)陧?xiàng)目中新建一個(gè)xml文件,編寫(xiě)其中的內(nèi)容,待會(huì)兒解析內(nèi)容并打印到TextView。

XML內(nèi)容為Person,有幾個(gè)學(xué)生的信息,包括學(xué)號(hào),姓名,性別和年齡,一會(huì)兒根據(jù)這些創(chuàng)建模型。


NSJSONSerialization

接下來(lái)就正式開(kāi)始。蘋(píng)果官方給出的解析方式是性能最優(yōu)越的,雖然用起來(lái)稍顯復(fù)雜。

首先我們?cè)谏厦嬉呀?jīng)有了我希望得到的信息的網(wǎng)站的API給我們的URL,在OC中,我要加載一個(gè)NSURL對(duì)象,來(lái)向網(wǎng)站提交一個(gè)Request。到這里需要特別注意了,iOS9的時(shí)代已經(jīng)來(lái)臨,我們先前在舊版本中使用的某些類(lèi)或者方法都已經(jīng)被蘋(píng)果官方棄用了。剛剛我們向網(wǎng)站提交了一個(gè)Request,在以往,我們是通過(guò)NSURLConnection中的sendSynchronousRequest方法來(lái)接受網(wǎng)站返回的Response的,但是在iOS9中,它已經(jīng)不再使用了。從官方文檔中,我們追根溯源,找到了它的替代品——NSURLSession類(lèi)。這個(gè)類(lèi)是iOS7中新的網(wǎng)絡(luò)接口,蘋(píng)果力推之,并且現(xiàn)在用它完全替代了NSURLConnection。關(guān)于它的具體用法,還是蠻簡(jiǎn)單的,直接上代碼(ViewController.m文件):

#import "ViewController.h"

@interface ViewController ()
@property (retain, nonatomic) IBOutlet UITextView *textView;
@property (nonatomic, strong) NSMutableDictionary *dic;
@property (nonatomic,strong) NSString *text;
@end

@implementation ViewController
- (IBAction)NSJson:(UIButton *)sender {
    //GCD異步實(shí)現(xiàn)
    dispatch_queue_t q1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(q1, ^{
        
        //加載一個(gè)NSURL對(duì)象
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://api.douban.com/v2/movie/subject/25881786"]];
 
        //使用NSURLSession獲取網(wǎng)絡(luò)返回的Json并處理
        NSURLSession *session = [NSURLSession sharedSession];
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error){
        
            //從網(wǎng)絡(luò)返回了Json數(shù)據(jù),我們調(diào)用NSJSONSerialization解析它,將JSON數(shù)據(jù)轉(zhuǎn)換為Foundation對(duì)象(這里是一個(gè)字典)
            self.dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
            
            NSString *title = [self.dic objectForKey:@"original_title"];
            NSMutableArray *genresArray = [self.dic objectForKey:@"genres"];
            NSString *genres = [NSString stringWithFormat:@"%@/%@", [genresArray objectAtIndex:0], [genresArray objectAtIndex:1]];
            NSString *summary = [self.dic objectForKey:@"summary"];
        
            self.text = [NSString stringWithFormat:@"電影名稱:\n%@\n體裁:\n%@\n劇情簡(jiǎn)介:\n%@", title, genres, summary];
            
            //更新UI操作需要在主線程
            dispatch_async(dispatch_get_main_queue(), ^{
                self.textView.text = self.text;
            });
        }];
        //調(diào)用任務(wù)
        [task resume];
    });
}

還是要再提一下,因?yàn)樯婕暗搅司W(wǎng)絡(luò)請(qǐng)求,我們?cè)谶@里用了一點(diǎn)關(guān)于使用GCD實(shí)現(xiàn)多線程的內(nèi)容,以后再專門(mén)介紹吧。我們運(yùn)行程序,點(diǎn)擊NSJSONSerialization按鈕,就看到我們要的內(nèi)容啦!

SBJson

事實(shí)上上面的解析過(guò)程還是挺復(fù)雜的,主要是牽扯到了NSURLSession的使用。那接下來(lái)來(lái)看看一些第三方Json解析庫(kù)的使用。SBJson用起來(lái)就簡(jiǎn)單多了。首先我們?nèi)ハ螺d這個(gè)類(lèi)庫(kù),Github啊,CSDN啊,51啊哪里的任何一個(gè)地方都有,很好找。下載下來(lái)后導(dǎo)入我們的項(xiàng)目就可以直接運(yùn)行了。有些第三方類(lèi)庫(kù)由于年代久遠(yuǎn)可能是不支持ARC的,SBJson還好,下面那個(gè)JsonKit可就不這么和諧了,這個(gè)待會(huì)再講。我們這次點(diǎn)擊第二個(gè)按鈕來(lái)實(shí)現(xiàn)它。為了以示區(qū)分,這次我換了一部電影,來(lái)看看《移動(dòng)迷宮2 Maze Runner: The Scorch Trials》吧!

//上面先導(dǎo)入包:
#import "ViewController.h"
#import "SBJson.h"

//實(shí)現(xiàn):
- (IBAction)SBJson:(UIButton *)sender {
    //GCD異步實(shí)現(xiàn)
    dispatch_queue_t q1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(q1, ^{
        
        //還是先獲取url
        NSURL *url = [NSURL URLWithString:@"https://api.douban.com/v2/movie/subject/25995508"];
        //返回上面url的內(nèi)容,格式為Json放在了字符串里
        NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
        //實(shí)例化SBJson對(duì)象,將Json格式字符串解析,轉(zhuǎn)化為字典。
        SBJsonParser *parser = [[SBJsonParser alloc] init];
        self.dic = [parser objectWithString:jsonString error:nil];
            
    
        NSString *title = [self.dic objectForKey:@"original_title"];
        NSMutableArray *genresArray = [self.dic objectForKey:@"genres"];
        NSString *genres = [NSString stringWithFormat:@"%@/%@", [genresArray objectAtIndex:0], [genresArray objectAtIndex:1]];
        NSString *summary = [self.dic objectForKey:@"summary"];
        self.text = [NSString stringWithFormat:@"電影名稱:\n%@\n體裁:\n%@\n劇情簡(jiǎn)介:\n%@", title, genres, summary];
            
        //更新UI操作需要在主線程
        dispatch_async(dispatch_get_main_queue(), ^{
            self.textView.text = self.text;
        });
        
    });
}

看劇情好像很不錯(cuò)呢,打算去看一下~~

JsonKit

事實(shí)上,它雖然不支持ARC,但JsonKit是在性能上僅次于蘋(píng)果原生解析器的第三方類(lèi)庫(kù)。我們?cè)趯?dǎo)入它的包以后編譯會(huì)出現(xiàn)一大堆報(bào)錯(cuò),這時(shí)候不用慌,我們會(huì)發(fā)現(xiàn)大部分是ARC的問(wèn)題,解決方法也挺簡(jiǎn)單,我們進(jìn)入項(xiàng)目的Target,找到Build Phases里面的Compile Sources,接著找我們的問(wèn)題源頭JsonKit.m,雙擊更改它的Compiler Flags標(biāo)簽為“-fno-objc-arc”,再次編譯,就好啦~


//上面先導(dǎo)入包:
#import "ViewController.h"
#import "JsonKit.h"

//實(shí)現(xiàn)
- (IBAction)JsonKit:(UIButton *)sender {
    //GCD異步實(shí)現(xiàn)
    dispatch_queue_t q1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(q1, ^{
        
        //還是先獲取url
        NSURL *url = [NSURL URLWithString:@"https://api.douban.com/v2/movie/subject/26279433"];
        NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
        //代碼越來(lái)越簡(jiǎn)單了有木有!!就一個(gè)方法搞定~
        self.dic = [jsonString objectFromJSONStringWithParseOptions:JKParseOptionLooseUnicode];
        
        
        NSString *title = [self.dic objectForKey:@"original_title"];
        NSMutableArray *genresArray = [self.dic objectForKey:@"genres"];
        NSString *genres = [NSString stringWithFormat:@"%@/%@", [genresArray objectAtIndex:0], [genresArray objectAtIndex:1]];
        NSString *summary = [self.dic objectForKey:@"summary"];
        self.text = [NSString stringWithFormat:@"電影名稱:\n%@\n體裁:\n%@\n劇情簡(jiǎn)介:\n%@", title, genres, summary];
        
        //更新UI操作需要在主線程
        dispatch_async(dispatch_get_main_queue(), ^{
            self.textView.text = self.text;
        });
    });
}

雖然我們只用了一個(gè)方法,但是這可不代表JsonKit類(lèi)庫(kù)里就只有這一個(gè)解析的方法,我們可以去看看它的源碼來(lái)找尋一番。一般來(lái)講,如果json是“單層”的,即value都是字符串、數(shù)字,可以使用objectFromJSONString方法,這個(gè)也比較簡(jiǎn)單。如果json有嵌套,即value里有array、object,如果再使用objectFromJSONString,程序可能會(huì)報(bào)錯(cuò),這時(shí)我們最好使用objectFromJSONStringWithParseOptions也就是我代碼里使用的這個(gè)方法,因?yàn)殡娪绑w裁的Value是數(shù)組類(lèi)型的。

這部電影叫《剩者為王》,好可怕。。。

TouchJson

來(lái)看看最后一個(gè):

//導(dǎo)入包:
#import "ViewController.h"
#import "CJSONSerializer.h"
#import "CJSONDeserializer.h"


//
- (IBAction)TouchJson:(UIButton *)sender {
    //GCD異步實(shí)現(xiàn)
    dispatch_queue_t q1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(q1, ^{
        
        //還是先獲取url
        NSURL *url = [NSURL URLWithString:@"https://api.douban.com/v2/movie/subject/22265299"];
        NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
        //還是一句話的事兒
        self.dic = [[CJSONDeserializer deserializer] deserialize:[jsonString dataUsingEncoding:NSUTF8StringEncoding] error:nil];
        
        
        NSString *title = [self.dic objectForKey:@"original_title"];
        NSMutableArray *genresArray = [self.dic objectForKey:@"genres"];
        NSString *genres = [NSString stringWithFormat:@"%@/%@", [genresArray objectAtIndex:0], [genresArray objectAtIndex:1]];
        NSString *summary = [self.dic objectForKey:@"summary"];
        self.text = [NSString stringWithFormat:@"電影名稱:\n%@\n體裁:\n%@\n劇情簡(jiǎn)介:\n%@", title, genres, summary];
        
        //更新UI操作需要在主線程
        dispatch_async(dispatch_get_main_queue(), ^{
            self.textView.text = self.text;
        });
    });
}

《絕命海拔 Everest》,冒險(xiǎn)類(lèi)電影,本人不是很感冒,據(jù)說(shuō)是根據(jù)真實(shí)事件改編的。

Json解析總結(jié)

吶,上述四種方式已經(jīng)很清楚了,從代碼量上來(lái)看,除了那些廢話,原生的解析類(lèi)庫(kù)是實(shí)現(xiàn)起來(lái)最復(fù)雜的,其他三種倒是挺簡(jiǎn)單,通過(guò)封裝,只對(duì)外提供一個(gè)簡(jiǎn)單地接口調(diào)用就能實(shí)現(xiàn)解析功能,性能上都還可以接受。不過(guò)從我親身提回來(lái)講,覺(jué)得JsonKit是里面最快的,可能是代碼寫(xiě)的不夠好,原生的解析方式如果好好優(yōu)化一下的話應(yīng)該是性能最好的。在實(shí)際的使用過(guò)程中選擇一種方式就好。

NSXMLParse

關(guān)于XML,有兩種解析方式,分別是SAX(Simple API for XML,基于事件驅(qū)動(dòng)的解析方式,逐行解析數(shù)據(jù),采用協(xié)議回調(diào)機(jī)制)和DOM(Document Object Model ,文檔對(duì)象模型。解析時(shí)需要將XML文件整體讀入,并且將XML結(jié)構(gòu)化成樹(shù)狀,使用時(shí)再通過(guò)樹(shù)狀結(jié)構(gòu)讀取相關(guān)數(shù)據(jù),查找特定節(jié)點(diǎn),然后對(duì)節(jié)點(diǎn)進(jìn)行讀或?qū)懀?。蘋(píng)果官方原生的NSXMLParse類(lèi)庫(kù)采用第一種方式,即SAX方式解析XML,它基于事件通知的模式,一邊讀取文檔一邊解析數(shù)據(jù),不用等待文檔全部讀入以后再解析,所以如果你正打印解析的數(shù)據(jù),而解析過(guò)程中間出現(xiàn)了錯(cuò)誤,那么在錯(cuò)誤節(jié)點(diǎn)之間的數(shù)據(jù)會(huì)正常打印,錯(cuò)誤后面的數(shù)據(jù)不會(huì)被打印。解析過(guò)程由NSXMLParserDelegate協(xié)議方法回調(diào)。

插句題外話先,我在寫(xiě)這種方式解析XML數(shù)據(jù)的Demo時(shí)折騰了整整一天,說(shuō)起來(lái)都有些不好意思了。程序運(yùn)行的時(shí)候一直出現(xiàn)不能完成解析的情況,各種查各種試,真的是整了整整一天的時(shí)間。就在崩潰的邊緣的時(shí)候,我竟然發(fā)現(xiàn)在我自己寫(xiě)XML文件時(shí)少寫(xiě)了一個(gè)“/。。。瞬間感覺(jué)整個(gè)世界都崩塌了。所以特地記下來(lái)警示自己也順便給大家提個(gè)醒,在這種低級(jí)失誤上浪費(fèi)整整一天的時(shí)間,要多不值有多不值。謹(jǐn)記,謹(jǐn)記。

我們遵循MVC,首先我們創(chuàng)建模型,新建一個(gè)person類(lèi),存放XML文件中描述的person屬性。再來(lái)一個(gè)解析XML文件的工具類(lèi)XMLUtil,我們?cè)诶锩鎸?shí)現(xiàn)文件的獲取,代理方法的實(shí)現(xiàn)。

先來(lái)看這兩個(gè)類(lèi)的代碼:

//person.h

#import <Foundation/Foundation.h>

@interface person : NSObject
@property (nonatomic, copy) NSString *pid;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *sex;
@property (nonatomic, copy) NSString *age;
@end

//XMLUtil.h

#import <Foundation/Foundation.h>
#import "person.h"
//聲明代理
@interface XMLUtil : NSObject<NSXMLParserDelegate>
//添加屬性
@property (nonatomic, strong) NSXMLParser *par;
@property (nonatomic, strong) person *person;
//存放每個(gè)person
@property (nonatomic, strong) NSMutableArray *list;
//標(biāo)記當(dāng)前標(biāo)簽,以索引找到XML文件內(nèi)容
@property (nonatomic, copy) NSString *currentElement;

//聲明parse方法,通過(guò)它實(shí)現(xiàn)解析
-(void)parse;
@end



//XMLUtil.m

#import "XMLUtil.h"

@implementation XMLUtil

- (instancetype)init{
    self = [super init];
    if (self) {
        //獲取事先準(zhǔn)備好的XML文件
        NSBundle *b = [NSBundle mainBundle];
        NSString *path = [b pathForResource:@"test" ofType:@".xml"];
        NSData *data = [NSData dataWithContentsOfFile:path];
        self.par = [[NSXMLParser alloc]initWithData:data];
        //添加代理
        self.par.delegate = self;
        //初始化數(shù)組,存放解析后的數(shù)據(jù)
        self.list = [NSMutableArray arrayWithCapacity:5];
    }
    return self;
}

//幾個(gè)代理方法的實(shí)現(xiàn),是按邏輯上的順序排列的,但實(shí)際調(diào)用過(guò)程中中間三個(gè)可能因?yàn)檠h(huán)等問(wèn)題亂掉順序
//開(kāi)始解析
- (void)parserDidStartDocument:(NSXMLParser *)parser{
    NSLog(@"parserDidStartDocument...");
}
//準(zhǔn)備節(jié)點(diǎn)
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(NSDictionary<NSString *, NSString *> *)attributeDict{
    
    self.currentElement = elementName;
    
    if ([self.currentElement isEqualToString:@"student"]){
        self.person = [[person alloc]init];
        
    }
    
}
//獲取節(jié)點(diǎn)內(nèi)容
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
   
    if ([self.currentElement isEqualToString:@"pid"]) {
        
        [self.person setPid:string];
    }else if ([self.currentElement isEqualToString:@"name"]){
        [self.person setName:string];
    }else if ([self.currentElement isEqualToString:@"sex"]){
        [self.person setSex:string];
    }else if ([self.currentElement isEqualToString:@"age"]){
        
        [self.person setAge:string];
    }
}

//解析完一個(gè)節(jié)點(diǎn)
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName{
    
    if ([elementName isEqualToString:@"student"]) {
        [self.list addObject:self.person];
    }
    self.currentElement = nil;
}

//解析結(jié)束
- (void)parserDidEndDocument:(NSXMLParser *)parser{
    NSLog(@"parserDidEndDocument...");
}

//外部調(diào)用接口
-(void)parse{
    [self.par parse];
    
}

@end

OK,總算是大功告成,如果對(duì)代理的使用比較熟悉的話,這部分內(nèi)容其實(shí)還蠻簡(jiǎn)單的。如果被代碼轉(zhuǎn)來(lái)轉(zhuǎn)去弄暈了的話可以在每個(gè)block的最后都加一個(gè)打印輸出,做好標(biāo)記,你就能弄懂程序的執(zhí)行順序了。

我們點(diǎn)擊NSXMLParse,有了!

GDataXML

來(lái)看GDataXML,它是一種DOM方式的解析類(lèi)庫(kù)。DOM實(shí)現(xiàn)的原理是把整個(gè)xml文檔一次性讀出,放在一個(gè)樹(shù)型結(jié)構(gòu)里。在需要的時(shí)候,查找特定節(jié)點(diǎn),然后對(duì)節(jié)點(diǎn)進(jìn)行讀或?qū)憽?/p>

在使用之前呢,我們還是先從網(wǎng)上下載GDataXML包,里面兩個(gè)文件GDataXMLNode.h和GDataXMLNode.m導(dǎo)入到項(xiàng)目中來(lái),編譯,發(fā)現(xiàn)報(bào)錯(cuò)了,這是因?yàn)镚DataXML是依賴libmxl2的,我們要去項(xiàng)目的Target中做一些設(shè)置。

  • 找到項(xiàng)目的Tarfet,進(jìn)入Build Phases里面的Link Binary With Libraries,點(diǎn)擊“加號(hào)”,搜索libxml,把出現(xiàn)的包添加進(jìn)去,這里最新版的XCode7和iOS9中,是libxml.2.2.tbd。
  • 再來(lái)到Build Settings,我們可以搜索一下,找到Header Search Paths,添加路徑“/usr/include/libxml2”。
  • 再找到Other Link Flags,添加“-libxml2“
  • 還有就是如果你下載的GDataXML是不支持ARC的,那么你就要像上面那樣去添加“-fno-objc-arc”,這個(gè)視你下載的GDataXML包版本而定。

再次編譯,就順利通過(guò)了。

接下來(lái)看看我們?cè)趺从眠@個(gè)東西。貼代碼之前我真的想說(shuō)一句,比起蘋(píng)果原生的類(lèi)庫(kù),這些開(kāi)源的第三方類(lèi)庫(kù)真的在用起來(lái)的時(shí)候不知道有多舒服,懶人必備啊。在實(shí)際的開(kāi)發(fā)中可以為我們節(jié)省很多的時(shí)間與精力,但是還是要搞懂人家原生的東西,這樣才叫學(xué)會(huì)了么。

//ViewController.m

- (IBAction)GDataXML:(id)sender {
    
    NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"xml"];
    NSData *data = [[NSData alloc]initWithContentsOfFile:path];
    //對(duì)象初始化
    GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:data error:nil];
    //獲取根節(jié)點(diǎn)
    GDataXMLElement *rootElement = [doc rootElement];
    //獲取其他節(jié)點(diǎn)
    NSArray *students = [rootElement elementsForName:@"student"];
    //初始化可變數(shù)組,用來(lái)顯示到textView
    self.GDatatext = [[NSMutableString alloc]initWithString:@""];
    for (GDataXMLElement *student in students) {
        //獲取節(jié)點(diǎn)屬性
        GDataXMLElement *pidElement = [[student elementsForName:@"pid"] objectAtIndex:0];
        NSString *pid = [pidElement stringValue];
        
        
        GDataXMLElement *nameElement = [[student elementsForName:@"name"] objectAtIndex:0];
        NSString *name = [nameElement stringValue];
        
        
        GDataXMLElement *sexElement = [[student elementsForName:@"sex"] objectAtIndex:0];
        NSString *sex = [sexElement stringValue];
        
        
        GDataXMLElement *ageElement = [[student elementsForName:@"age"] objectAtIndex:0];
        NSString *age = [ageElement stringValue];
        
        //調(diào)整一下姿勢(shì),添加到可變長(zhǎng)字符串~~
        NSString *t = [NSString stringWithFormat:@"學(xué)號(hào):%@ 姓名:%@ 性別:%@ 年齡:%@\n", pid, name, sex, age];
        [self.GDatatext appendString:t];
    }
    self.textView.text = self.GDatatext;
}

就一段,是不是看起來(lái)非常的舒服呢!

跑一下,跟我們剛才使用的NSXMLParse是不是一樣呢?

哈,搞定!

XML解析總結(jié)

上述兩種解析用到的類(lèi)庫(kù)分別代表了兩種典型的XML數(shù)據(jù)解析方式,SAX和DOM,各有優(yōu)勢(shì),比如在應(yīng)對(duì)比較大數(shù)據(jù)量的XML文件時(shí),后者由于需要先讀取整個(gè)文檔,性能和速度上就必然不及前者了。

其實(shí)現(xiàn)在在實(shí)際應(yīng)用中XML已經(jīng)越來(lái)越少了,但是說(shuō)起iOS中的網(wǎng)絡(luò)編程,就免不了和XML格式的數(shù)據(jù)打交道。還有就是,我們?cè)谶@里僅僅介紹了兩種常用的XML解析方式,如同解析Json數(shù)據(jù)一樣,解析XML文件也有很多種方法,除了上述兩種,還有比如像TBXML, TouchXML, KissXML, TinyXML等等,具體的使用方法可以去Github上找,都有使用方法的說(shuō)明的。

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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