iOS開發實踐之XML
xml與json的對比,前面文章已經提供參考,至於xml的文法結構也不在這詳述。 直奔iOS中解析xml的方法。
iOS中的XML解析(Dom和SAX)
Dom方式使用的是文件物件模型解析,它首先要將xml檔案整個讀入記憶體中,然後再來構建Dom對象,在DOM對象裡,xml檔案中的所有元素都可以當做節點(Node)對象來處理。這種方式優點是方便對文檔進行增加、刪除、修改、添加等操作,缺點是它首先要將整個檔案讀入記憶體中在解析,如果檔案大。會很消耗記憶體,並且它的執行速度慢。
SAX解析XML檔案採用事件驅動的方式進行,也就是說,SAX是漸進式掃描檔案,遇到合格設定條件後就會觸發特定的事件,回調你寫好的事件處理常式。使用SAX的優勢在於其解析速度較快,佔用記憶體較少(相對於DOM而言)。而且SAX在解析檔案的過程中得到自己需要的資訊後可以隨時終止解析,並不一定要等檔案全部解析完畢。凡事有利必有弊,其劣勢在於SAX採用的是串流方式,當遇到某個標籤的時候,它並不會記錄下以前所遇到的標籤,也就是說,在處理某個標籤的時候,所能夠得到的資訊就是標籤的名字和屬性,至於標籤內部的嵌套結構,上層標籤、下層標籤以及其兄弟節點的名稱等等與其結構相關的資訊都是不得而知的。實際上就是把XML檔案的結構資訊丟掉了,如果需要得到這些資訊的話,只能你自己在程式裡進行處理了。所以相對DOM而言,SAX處理XML文檔沒有DOM方便,SAX處理的過程相對DOM而言也比較複雜。
總結:
DOM:一次性將整個XML文檔載入進記憶體,比較適合解析小檔案
SAX:SAX採用事件驅動,從根項目開始,按順序一個元素一個元素往下解析,比較適合解析大檔案。
解析方法:
蘋果原生
NSXMLParser:SAX方式解析,使用簡單
第三方架構
libxml2:純C語言,預設包含在iOS SDK中,同時支援DOM和SAX方式解析
GDataXML:DOM方式解析,由Google開發,基於libxml2
XML解析方式的選擇建議
大檔案:NSXMLParser、libxml2
小檔案:GDataXML
GDataXML:
常用的類
GDataXMLDocument:代表整個XML文檔
GDataXMLElement:代表文檔中的每個元素
常用方法:
elementsForName:根據元素名稱得到元素節點
attributeForName:方法可以獲得屬性值
更多的操作xml的方法和屬性,查閱GDataXMLNode.h
使用步驟:
1、下載GDataXMLNode ,:http://download.csdn.net/detail/zhixinhuacom/9417644,並 解壓將其中的GDataXMLNode.h 和 GDataXMLNode.m檔案拖到項目中。
2、由於GDataXML基於libxml2庫,因此要匯入libxml2
3、設定libxml2的標頭檔搜尋路徑(為了能找到libxml2庫的所有標頭檔)
在Head Search Path中加入/usr/include/libxml2
4、設定連結參數(自動連結libxml2庫)
在Other Linker Flags中加入-lxml2
5、如果報arc錯誤,則設定GDataXML編譯參數
6、匯入#import "GDataXMLNode.h" 標頭檔就可以使用了。
例子:
解析下面格式的xml
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSURL *url = [NSURL URLWithString:@"http://localhost:8080/myService/video?type=XML"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { //1、載入xml資料 GDataXMLDocument *document = [[GDataXMLDocument alloc]initWithData:data options:0 error:nil]; //2、擷取xml根項目(videos) GDataXMLElement *root = document.rootElement; // //元素子節點個數(不包括子節點下的節點)// NSInteger childCount = root.childCount;// //元素名稱// NSString *elementName = root.name;// //節點內容字串// NSString *xmlStr = root.XMLString;// NSLog(@"childCount=%ld\nelementName=%@\nxmlStr=%@",childCount,elementName,xmlStr); //3、擷取根項目的所有video元素 NSArray *elements = [root elementsForName:@"video"]; for (GDataXMLElement *element in elements) { //4、擷取屬性植 NSString *idStr = [element attributeForName:@"id"].stringValue; NSString *name = [element attributeForName:@"name"].stringValue; NSString *length = [element attributeForName:@"length"].stringValue; NSString *image = [element attributeForName:@"image"].stringValue; NSString *url = [element attributeForName:@"url"].stringValue; NSLog(@"id=%@",idStr); NSLog(@"name=%@",name); NSLog(@"length=%@",length); NSLog(@"image=%@",image); NSLog(@"url=%@",url); } }];}
NSXMLParser:
NSXMLParser採取的是SAX方式解析,特點是事件驅動,下面情況都會通知代理:
(1)當掃描到文檔(Document)的開始與結束
(2)當掃描到元素(Element)的開始與結束
一:使用步驟:
1、傳入XML資料,建立解析器
NSXMLParser *parser = [[NSXMLParseralloc] initWithData:data];
2、設定代理,監聽解析過程
parser.delegate =self;
3、開始解析
[parserparse];
二:NSXMLParserDelegate常用代理方法:
當掃描到文檔的開始時調用(開始解析)
- (void)parserDidStartDocument:(NSXMLParser *)parser
當掃描到文檔的結束時調用(解析完畢)
- (void)parserDidEndDocument:(NSXMLParser *)parser
當掃描到元素的開始時調用(attributeDict存放著元素的屬性)
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
當掃描到元素的結束時調用
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
例子:同樣解析上面格式的xml
#import "ViewController.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib.}-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSURL *url = [NSURL URLWithString:@"http://localhost:8080/myService/video?type=XML"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { //1、傳入xml,建立解析器 NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data]; //2、設定代理、監聽解析過程 parser.delegate = self; //3、開始解析 [parser parse]; }];}#pragma mark NSXMLParserDelegate代理方法//當掃描到元素的開始時調用(attributeDict存放著元素的屬性)-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{ NSLog(@"===========%@元素開始解析========",elementName); if ([@"videos" isEqualToString:elementName]) { NSLog(@"%@是根節點",elementName); return; } NSString *idStr = attributeDict[@"id"]; NSString *name = attributeDict[@"name"]; NSString *length = attributeDict[@"length"]; NSString *image = attributeDict[@"image"]; NSString *urlStr = attributeDict[@"url"]; NSLog(@" \n id=%@ \n name=%@\n length=%@ \n image=%@ \n url=%@",idStr,name,length,image,urlStr); };//當掃描到元素的結束時調用-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{ NSLog(@"===========%@元素解析結束========",elementName); }//當掃描到文檔的開始時調用(開始解析)-(void)parserDidStartDocument:(NSXMLParser *)parser{ NSLog(@"parserDidStartDocument=====開始解析=======");}//當掃描到文檔的結束時調用(解析完畢)-(void)parserDidEndDocument:(NSXMLParser *)parser{ NSLog(@"parserDidEndDocument=====解析完畢========");}@end
解析輸入結果: