iOS網(wǎng)絡(luò)數(shù)據(jù)解析之XML解析詳解(GDataXMLNode&原生NSXMLParser)

在iOS開發(fā)中,大多數(shù)情況下,從網(wǎng)絡(luò)獲取的數(shù)據(jù)通常分兩種肴沫。
JSON格式或者XML格式。

JSON是一種輕量級(jí)的數(shù)據(jù)格式蕴忆,一般用于數(shù)據(jù)交互

JSON數(shù)據(jù)類似OC中的字典颤芬,解析方式也有很多

ios5中apple增加了解析JSON的api:NSJSONSerialization (性能最好)

下面是NSJSONSerialization常用的兩個(gè)方法

// JSON數(shù)據(jù) > OC對(duì)象
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;

// OC對(duì)象 > JSON數(shù)據(jù) 
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;

另外Github上關(guān)于解析JSON的框架也有很多,JSONKit套鹅、SBJson站蝠、TouchJSON、JSONModel等芋哭。

關(guān)于JSON解析不做贅述沉衣,本文主要講解XML解析。

雖然現(xiàn)在大部分公司中給我們的數(shù)據(jù)都是JSON减牺,但是不排除一些比較老的公司中還在使用XML格式的數(shù)據(jù)豌习,去年剛?cè)胄械臅r(shí)候接到的第一個(gè)項(xiàng)目中數(shù)據(jù)就是XML格式的,數(shù)據(jù)量又大又復(fù)雜拔疚,其中一個(gè)模塊返回的XML數(shù)據(jù)接近1M肥隆,當(dāng)時(shí)真的是被虐成狗。

<h3>XML概述</h3>

XML全稱是Extensible Markup Language稚失,譯作“可擴(kuò)展標(biāo)記語(yǔ)言”
跟JSON一樣栋艳,也是常用的一種用于交互的數(shù)據(jù)格式
一般也叫XML文檔(XML Document)

一個(gè)常見的XML文檔一般由元素(Element)屬性(Attribute)組成

一個(gè)元素包括了開始標(biāo)簽和結(jié)束標(biāo)簽
擁有元素內(nèi)容:<city>上海</city>
沒有元素內(nèi)容:<city></city>
沒有元素內(nèi)容的簡(jiǎn)寫:<city/> 

一個(gè)元素可以嵌套若干個(gè)子元素(不能出現(xiàn)交叉嵌套)
<citys>
    <city>
        <name>上海</name>
        <weather>大暴雨</weather>
          <air>舒適</air>
    </city>
</citys>

規(guī)范的XML文檔最多只有1個(gè)根元素,其他元素都是根元素的子孫元素
XML中的所有空格和換行句各,都會(huì)當(dāng)做具體內(nèi)容處理

一個(gè)元素可以擁有多個(gè)屬性吸占,屬性值必須用 雙引號(hào)"" 或者 單引號(hào)'' 括住。
<city name="上海" weather="大暴雨" air="舒適" />

屬性表示的信息也可以用子元素來(lái)表示凿宾,比如

   <city>
        <weather>大暴雨</weather>
          <air>舒適</air>
    </city>

關(guān)于XML具體的語(yǔ)法請(qǐng)百度or谷歌矾屯。
<h3>XML解析方式</h3>

DOM解析:一次性將整個(gè)XML文檔加載進(jìn)內(nèi)存,比較適合解析小文件
SAX解析:從根元素開始初厚,按順序一個(gè)元素一個(gè)元素往下解析件蚕,比較適合解析大文件

iOS SDK 提供了兩個(gè)xml框架。

  1. NSXMLParser:它是基于objective-c語(yǔ)言的sax解析框架产禾,是ios sdk默認(rèn)的xml解析框架排作,不支持dom模式。
  2. libxml2: 它是基于c語(yǔ)言的xml解析器亚情,被蘋果整合在ios sdk中妄痪,支持sax和dom模式。

第三方xml解析框架

  1. tbxml:它是輕量級(jí)的dom模式解析庫(kù)楞件,不支持xml文檔驗(yàn)證和xpath,只能讀取xml文檔拌夏,不能寫xml文檔僧著。
  2. touchxml:它是基于dom模式的解析庫(kù),與 tbxml類似障簿,只能讀取xml文檔,不能寫xml文檔栅迄。
  3. kissxml:它是基于dom模式的解析庫(kù)站故,基于touchxml,主要的不同是可以寫入xml文檔。
  4. Gdataxml:它是基于dom模式的解析庫(kù)毅舆,由google開發(fā)西篓,可以讀寫xml文檔,支持xpath查詢憋活。

<h3>具體解析實(shí)例</h3>
通過標(biāo)題岂津,應(yīng)該知道本文講解的是NSXMLParser解析與Gdataxml解析。
我從之前項(xiàng)目中截取一段數(shù)據(jù)作為例子分別使用兩種方式解析

<CrReport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
 <CrRptByHour>
  <CrReportByHour>
   <Hour>10</Hour>
   <Caption>10-12</Caption>
   <CrChannel>0.8</CrChannel>
   <CrRegion>0.6</CrRegion>
   <CrArea>0.7</CrArea>
  </CrReportByHour>
  <CrReportByHour>
   <Hour>12</Hour>
   <Caption>12-14</Caption>
   <CrChannel>1.5</CrChannel>
   <CrRegion>0.9</CrRegion>
   <CrArea>1.0</CrArea>
  </CrReportByHour>
 </CrRptByHour>
 <CrRptByDay>
  <CrReportByDay>
   <Date>2015-03-02T00:00:00+08:00</Date>
   <WeekDay>1</WeekDay>
   <CrChannel>0.0330</CrChannel>
   <CrRegion>0.0290</CrRegion>
   <CrArea>0.0290</CrArea>
  </CrReportByDay>
  <CrReportByDay>
   <Date>2015-03-02T00:00:00+08:00</Date>
   <WeekDay>2</WeekDay>
   <CrChannel>0.0310</CrChannel>
   <CrRegion>0.0280</CrRegion>
   <CrArea>0.0300</CrArea>
  </CrReportByDay>
 </CrRptByDay>
 <CrRptSubTotal>
  <CrReportSubTotal>
   <RegionType>0</RegionType>
   <Caption>SA Channel</Caption>
   <CrYTD>0.0310</CrYTD>
   <CrQTD>0.0310</CrQTD>
   <CrMTD>0.0290</CrMTD>
   <CrWTD>0.0000</CrWTD>
   <CrYersterday>0.0000</CrYersterday>
   <CrToday>0</CrToday>
  </CrReportSubTotal>
  <CrReportSubTotal>
   <RegionType>1</RegionType>
   <Caption>SA North B</Caption>
   <CrYTD>0.0280</CrYTD>
   <CrQTD>0.0280</CrQTD>
   <CrMTD>0.0280</CrMTD>
   <CrWTD>0.0000</CrWTD>
   <CrYersterday>0.0000</CrYersterday>
   <CrToday>0</CrToday>
  </CrReportSubTotal>
 </CrRptSubTotal>
</CrReport>

<h4>GDataXML</h4>
要使用GDataXML悦即,先要對(duì)項(xiàng)目進(jìn)行一些配置.
1>導(dǎo)入libxml2動(dòng)態(tài)庫(kù)
targets--Build Phases--link Binary With Libraries


image

image

2>設(shè)置libxml2的頭文件搜索路徑(為了能找到libxml2庫(kù)的所有頭文件)
在Head Search Path中加入/usr/include/libxml2


image

3>設(shè)置鏈接參數(shù)(自動(dòng)鏈接libxml2庫(kù))
在Other Linker Flags中加入-lxml2


image

4>由于GDataXML是非ARC的吮成,因此得設(shè)置編譯參數(shù)


image

CMD+B 編譯通過沒有報(bào)錯(cuò)說明環(huán)境配置成功。

GDataXML中常用的類
GDataXMLDocument: 代表整個(gè)XML文檔
GDataXMLElement: 代表文檔中的每個(gè)元素
使用attributeForName:方法可以獲得屬性值

上代碼(下面這段怎么編輯都有點(diǎn)問題辜梳,所以截圖了)

Snip20150826_32.png

輸出內(nèi)容如下


image

你可以下載代碼試著解析CrRptByDay與CrRptSubTotal中的內(nèi)容粱甫。

GdataXML的最吸引人的在于他支持xpath語(yǔ)法,關(guān)于xpath語(yǔ)法內(nèi)容還還請(qǐng)各位看官另行搜索作瞄。我把之前項(xiàng)目中封裝的一整套解析工具也放到代碼中XML文件夾中茶宵,其中大量使用xpath,有興趣的朋友可以下載來(lái)研究一下宗挥。

另外完整數(shù)據(jù)涉及之前公司的商業(yè)機(jī)密乌庶,所有沒有放進(jìn)去,大家湊合看吧契耿。


<h4>NSXMLParser</h4>

NSXMLParser屬于SAX解析瞒大,是從上往下依次解析每個(gè)元素,在解析到每個(gè)元素的時(shí)候會(huì)通知代理宵喂,所以使用NSXMLParser必須遵守他的協(xié)議糠赦。
使用非常簡(jiǎn)單

 // 創(chuàng)建解析器
 NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
 // 設(shè)置代理
 parser.delegate = self;
 // 開始解析
 [parser parse];

NSXMLParser的delegate

/**
 *  解析到文檔的開頭時(shí)會(huì)調(diào)用
 */
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
//    NSLog(@"parserDidStartDocument----");
}

/**
 *  解析到一個(gè)元素的開始就會(huì)調(diào)用
 *
 *  @param elementName   元素名稱
 *  @param attributeDict 屬性字典
 */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    一般情況,如果數(shù)據(jù)是這種格式,把內(nèi)容放到屬性中
 <CrReportByHour Hour=@"10" Caption=@"10-12" CrChannel=@"0.8" CrRegion=@"0.6" CrArea=@"0.7"/>
 系統(tǒng)會(huì)自動(dòng)把以上內(nèi)容轉(zhuǎn)為字典存放到attributeDict這個(gè)字典中
 可以用KVC通過字典給模型直接復(fù)制(字典中的key必須都能在模型中找到)
}

/**
 *  解析到一個(gè)元素的結(jié)束就會(huì)調(diào)用
 *
 *  @param elementName   元素名稱
 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
//    NSLog(@"didEndElement----%@", elementName);
}

/**
 *  解析到文檔的結(jié)尾時(shí)會(huì)調(diào)用(解析結(jié)束)
 */
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
//    NSLog(@"parserDidEndDocument----");
}

如果解析下面這段XML锅棕,直接在開始解析的方法中打印字典log輸出

<CrReport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
 <CrRptByHour>
  <CrReportByHour Hour="10" Caption="10-12" CrChannel="0.8" CrRegion="0.6" CrArea="0.7" />
        <CrReportByHour Hour="10" Caption="10-14" CrChannel="1.5" CrRegion="0.9" CrArea="1.0" />
 </CrRptByHour>
</CrReport>

image

看到熟悉的字典大家應(yīng)該懂了拙泽。

無(wú)奈當(dāng)時(shí)服務(wù)器返回的數(shù)據(jù)不是這種格式,而且內(nèi)容全都嵌入在元素中裸燎。
這里我們需要用到一個(gè)代理方法

// 當(dāng)解析器找到開始標(biāo)記和結(jié)束標(biāo)記之間的字符時(shí)顾瞻,調(diào)用這個(gè)方法解析當(dāng)前節(jié)點(diǎn)的所有字符 
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    //string 就是每個(gè)元素中包含的內(nèi)容,我們需要在這里拿到并記錄自己需要的數(shù)據(jù)
    self.currentString = string;
}

當(dāng)初由于項(xiàng)目需要在不同的地方展示這份XML中三分?jǐn)?shù)據(jù)德绿,所有我當(dāng)時(shí)的思路是在需要解析的地方創(chuàng)建解析工具類荷荤,傳入父元素名退渗,來(lái)獲取下面子節(jié)點(diǎn)的所有內(nèi)容.

根據(jù)自己傳入的元素名來(lái)判斷
在開始解析元素的方法中初始化可變字典,并且添加到全局的數(shù)組中
在上面的方法中用全局變量來(lái)記錄string值
在結(jié)束元素解析的方法中用用當(dāng)前元素作為key蕴纳,記錄的string為value寫入字典中会油。

XMLParser* parser = [[XMLParser alloc] parseDataByData:xmlData];

    //傳入節(jié)點(diǎn)名稱獲取內(nèi)容 CrReportByHour、CrReportByDay古毛、CrReportSubTotal
    NSMutableArray* array = [parser searchDataWithRootElement:@"CrReportByHour"];
    
    NSLog(@"%@",array);

array的輸出內(nèi)容是


image

具體實(shí)現(xiàn)代碼大家下載來(lái)自己看吧翻翩,那時(shí)候剛?cè)胄校a寫的很渣稻薇。
代碼下載:https://github.com/hongfenglt/XMLParse

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嫂冻,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子塞椎,更是在濱河造成了極大的恐慌桨仿,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件案狠,死亡現(xiàn)場(chǎng)離奇詭異服傍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)莺戒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門伴嗡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人从铲,你說我怎么就攤上這事瘪校。” “怎么了名段?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵阱扬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我伸辟,道長(zhǎng)麻惶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任信夫,我火速辦了婚禮窃蹋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘静稻。我一直安慰自己警没,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布振湾。 她就那樣靜靜地躺著杀迹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪押搪。 梳的紋絲不亂的頭發(fā)上树酪,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天浅碾,我揣著相機(jī)與錄音,去河邊找鬼续语。 笑死垂谢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疮茄。 我是一名探鬼主播埂陆,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼娃豹!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起购裙,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤懂版,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后躏率,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體躯畴,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年薇芝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蓬抄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夯到,死狀恐怖嚷缭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耍贾,我是刑警寧澤阅爽,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站荐开,受9級(jí)特大地震影響付翁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晃听,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一百侧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧能扒,春花似錦佣渴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至越平,卻和暖如春频蛔,著一層夾襖步出監(jiān)牢的瞬間灵迫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工晦溪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瀑粥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓三圆,卻偏偏與公主長(zhǎng)得像狞换,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子舟肉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容