iOS 詳解NSXMLParser方法解析XML數據方法

轉載於:http://blog.csdn.net/crayondeng/article/details/8738811html

前一篇文章已經介紹瞭如何經過URL從網絡上獲取xml數據。下面介紹如何將獲取到的數據進行解析。數組

下面先看看xml的數據格式吧!網絡

[html]  view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <Books>  
  3. <Book id="1">  
  4. <title>Circumference</title>  
  5. <author>Nicholas Nicastro</author>  
  6. <summary>Eratosthenes and the Ancient</summary>  
  7. </Book>  
  8. <Book id="2">  
  9. <title>Copernicus Secret</title>  
  10. <author>Jack Repcheck</author>  
  11. <summary>How the scientific revolution began</summary>  
  12. </Book>  
  13. <Book id="3">  
  14. <title>Angels and Demons</title>  
  15. <author>Dan Brown</author>  
  16. <summary>Robert Langdon is summoned to a Swiss</summary>  
  17. </Book>  
  18. </Books>  
顯然在這個xml中包括三本書的一些基本數據:id   title   author   summary  解析的過程就是將這些數據提取出來。

先簡單介紹一下xml數據解析吧。xml數據的解析通常有兩種方式:SAX(Simple API for XML)和DOM (Document Object Model),事件和文檔。app

dom實現的原理是把整個xml文檔一次性讀出,放在一個樹型結構裏。在須要的時候,查找特定節點,而後對節點進行讀或寫。他的主要優點是實現簡單,讀寫平衡;缺點是比較佔內存,由於他要把整個xml文檔都讀入內存,文件越大,這種缺點就越明顯。

sax的實現方法和dom不一樣。他只在xml文檔中查找特定條件的內容,而且只提取須要的內容。這樣作佔用內存小,靈活。

NSXMLParser 實現的是sax方法解析xml文件。dom

下面進入主題介紹如何對xml進行解析:ide

1、將上面的xml數據保存爲Books.xml做爲本地xml數據,並導入項目中。函數

2、因爲book中含有幾個屬性,因此這裏第一個book類。測試

Book.h文件:atom

[cpp]  view plain copy
  1. #import <Foundation/Foundation.h>  
  2.   
  3. @interface Book : NSObject  
  4.   
  5. @property (nonatomic, readwrite) NSInteger bookID;  
  6. @property (nonatomic, retain) NSString  *title;  
  7. @property (nonatomic, retain) NSString  *author;  
  8. @property (nonatomic, retain) NSString  *summary;  
  9.   
  10. @end  

Book.m文件

[cpp]  view plain copy
  1. #import "Book.h"  
  2.   
  3. @implementation Book  
  4.   
  5. @synthesize bookID;  
  6. @synthesize title;  
  7. @synthesize author;  
  8. @synthesize summary;  
  9.   
  10. @end  

3、要實現對xml數據的解析其實是經過實現NSXMLParserDelegate委託中的幾個方法。url

[cpp]  view plain copy
  1. #pragma mark xmlparser    
  2. //step 1 :準備解析    
  3. - (void)parserDidStartDocument:(NSXMLParser *)parser    
  4. {    
  5.    
  6. }    
  7. //step 2:準備解析節點    
  8. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict    
  9. {    
  10.    
  11. }    
  12. //step 3:獲取首尾節點間內容    
  13. - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string    
  14. {    
  15.        
  16. }    
  17.     
  18. //step 4 :解析完當前節點    
  19. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName    
  20. {    
  21.      
  22. }    
  23.     
  24. //step 5:解析結束    
  25. - (void)parserDidEndDocument:(NSXMLParser *)parser    
  26. {    
  27.    
  28. }    
  29. //step 6:獲取cdata塊數據    
  30. - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock    
  31. {    
  32.   
  33. }    


在實現xml解析過程以上方法中的step3 、四、5是必須的,而step一、5可選。

下面分別介紹:

Step 1: 在開始解析以前的一些準備工做,例如初始化一些存儲變量。在個人這個例子中,使用了一個Book實例變量來存儲一本書(也便是一組信息),一個可變數組來存儲這三本書(即每一組信息都當成這個數組中的一個元素),(這次要注意理解數據變量之間的關係),其餘變量就暫不介紹啦(待會看源代碼就能夠了)。


Step 2: 當解析器遇到xml的根標籤和一組信息的開始標籤時就開始調用這個方法,在這個xml文件中,遇到Books(xml文件的根標籤),Book(一組信息的開始標籤)時就會調用這個方法。那麼也就能夠知道這個方法在程序運行過程當中被調用了屢次。那麼就能夠用 if 語句判斷遇到的是Books仍是Book,而後作一些相應的操做(具體的話待會看源代碼)。

[cpp]  view plain copy
  1. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict    
  2. {    
  3.    
  4. }    
注意其中的參數:elementName表示遇到的標籤,在這個程序中會遇到的是Books和Book;  解析到一個標籤時,開始的 標籤可能會有一些屬性,例如在這裏<Book id="1">

那麼id就是屬性啦,在這個方法中他是用一個字典來保存的即(NSDictionary *)attributeDict,那麼對這個字典操做就能夠獲得你要的value和key啦。

Step 3:當解析器找到開始標籤和結束標籤之間的字符時,就調用這個方法,讀取其中的內容。 注意:這裏讀取到的string在這個函數裏面咱們並不知道是那個屬性的內容,意思就是假如string的內容是Circumference(Book 的title),可是咱們不知道這個是title的內容;那麼在哪裏才知道,而後對它進行存儲操做呢,不要着急,就是Step4啦!

Step 4:當解析器讀到結束標籤時,就會調用這個方法。例如讀到Books,Book,title等。那麼對讀到的標籤進行判斷後就能夠進行存儲操做啦!

[cpp]  view plain copy
  1. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName    
  2. {    
  3.      
  4. }   
這裏標籤參數就是elementName。


Step 5:對整個xml文件解析結束後的一些操做。

Step 6:這個暫不解釋(我尚未用到)。


4、下面就是上代碼的時候啦

.h文件

[cpp]  view plain copy
  1. #import <UIKit/UIKit.h>  
  2.   
  3. @class AppDelegate,Book;  
  4. @interface ViewController : UIViewController <NSXMLParserDelegate> {  
  5.       
  6.     NSMutableString *currentElementValue;  //用於存儲元素標籤的值  
  7.       
  8.     NSMutableArray *books;  //用於存儲一組書籍  
  9.       
  10.     Book *aBook;  //書籍實例,表明一本書  
  11.       
  12.     BOOL storingFlag; //查詢標籤所對應的元素是否存在  
  13.       
  14.     NSArray *elementToParse;  //要存儲的元素  
  15. }  
  16. - (IBAction)xmlButton:(id)sender;  
  17.   
  18. @end  

說明:這裏我用一個按鍵來觸發xml解析。

.m文件

[cpp]  view plain copy
  1. #import "ViewController.h"  
  2. #import "AppDelegate.h"  
  3.   
  4. @interface ViewController ()  
  5.   
  6. @end  
  7.   
  8. @implementation ViewController  
  9.   
  10. - (void)viewDidLoad  
  11. {  
  12.     [super viewDidLoad];  
  13.     // Do any additional setup after loading the view, typically from a nib.  
  14.     //初始化要解析的元素標籤  
  15.     elementToParse = [[NSArray alloc] initWithObjects:@"title",@"author",@"summary", nil];  
  16. }  
  17.   
  18. - (void)didReceiveMemoryWarning  
  19. {  
  20.     [super didReceiveMemoryWarning];  
  21.     // Dispose of any resources that can be recreated.  
  22. }  
  23.   
  24. - (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {  
  25.     if([elementName isEqualToString:@"Books"]) {  
  26.         //Initialize the array.  
  27.         //在這裏初始化用於存儲最終解析結果的數組變量,咱們是在當遇到Books根元素時纔開始初始化  
  28.         books = [[NSMutableArray alloc] init];  
  29.         }  
  30.     else if([elementName isEqualToString:@"Book"]) {  
  31.           
  32.         //Initialize the book.  
  33.         //當碰到Book元素時,初始化用於存儲Book信息的實例對象aBook  
  34.           
  35.         aBook = [[Book alloc] init];  
  36.           
  37.         //Extract the attribute here.  
  38.         //從attributeDict字典中讀取Book元素的屬性  
  39.           
  40.         aBook.bookID = [[attributeDict objectForKey:@"id"] integerValue];  
  41.           
  42.         NSLog(@"ID:%i", aBook.bookID);  
  43.         }  
  44.     storingFlag = [elementToParse containsObject:elementName];  //判斷是否存在要存儲的對象  
  45. }  
  46.   
  47. - (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {  
  48.     // 當用於存儲當前元素的值是空時,則先用值進行初始化賦值  
  49.     // 不然就直接追加信息  
  50.     if (storingFlag) {  
  51.         if (!currentElementValue) {  
  52.             currentElementValue = [[NSMutableString alloc] initWithString:string];  
  53.         }  
  54.         else {  
  55.             [currentElementValue appendString:string];  
  56.         }  
  57.     }  
  58.       
  59. }  
  60.   
  61. // 這裏纔是真正完成整個解析並保存數據的最終結果的地方  
  62. - (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {  
  63.       
  64.     if ([elementName isEqualToString:@"Book"]) {  
  65.         [books addObject:aBook];  
  66.         aBook = nil;  
  67.     }  
  68.       
  69.     if (storingFlag) {  
  70.         //去掉字符串的空格  
  71.         NSString *trimmedString = [currentElementValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];  
  72.           
  73.         //將字符串置空  
  74.         [currentElementValue setString:@""];  
  75.           
  76.         if ([elementName isEqualToString:@"title"]) {  
  77.             aBook.title = trimmedString;  
  78.             NSLog(@"title :%@",aBook.title);  
  79.         }  
  80.         if ([elementName isEqualToString:@"author"]) {  
  81.             aBook.author = trimmedString;  
  82.             NSLog(@"author :%@",aBook.author);  
  83.         }  
  84.         if ([elementName isEqualToString:@"summary"]) {  
  85.             aBook.summary = trimmedString;  
  86.             NSLog(@"summary :%@",aBook.summary);  
  87.         }  
  88.     }  
  89.       
  90. }  
  91.   
  92. - (IBAction)xmlButton:(id)sender {  
  93.     //打開xml文件,讀取數據到NSData  
  94.     NSString *path = [[NSBundle mainBundle] pathForResource:@"Books" ofType:@"xml"];  
  95.     NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];  
  96.     NSData *data = [file readDataToEndOfFile];  
  97.     [file closeFile];  
  98.       
  99.     //測試從xml接受到的數據  
  100.     NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
  101.     NSLog(@"%@",dataString);  
  102.       
  103.     NSXMLParser *m_parser = [[NSXMLParser alloc] initWithData:data];  
  104.     //設置該類自己爲代理類,即該類在聲明時要實現NSXMLParserDelegate委託協議  
  105.     [m_parser setDelegate:self];  //設置代理爲本地  
  106.       
  107.     BOOL flag = [m_parser parse]; //開始解析  
  108.     if(flag) {  
  109.         NSLog(@"解析指定路徑的xml文件成功");  
  110.     }  
  111.     else {  
  112.         NSLog(@"解析指定路徑的xml文件失敗");  
  113.     }      
  114. }  
  115. @end  


說明:

一、其中我用了一些NSLog來輸出相關的信息驗證,實際使用過程當中,去掉就ok啦!

二、結合我上面的解釋和代碼,應該能夠理解整個xml解析的過程的。

三、這裏我用的是本地的xml文件,若是是想進行網絡xml數據的解析的話,那也是很簡單的,就是經過url獲取xml數據替換掉這裏的本地xml,經過url獲取xml能夠參考上一篇博文。

相關文章
相關標籤/搜索