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