iOS 詳解NSXMLParser方法解析XML資料方法

來源:互聯網
上載者:User

前一篇文章已經介紹了如何通過URL從網路上擷取xml資料。下面介紹如何將擷取到的資料進行解析。

下面先看看xml的資料格式吧!

<?xml version="1.0" encoding="UTF-8"?><Books><Book id="1"><title>Circumference</title><author>Nicholas Nicastro</author><summary>Eratosthenes and the Ancient</summary></Book><Book id="2"><title>Copernicus Secret</title><author>Jack Repcheck</author><summary>How the scientific revolution began</summary></Book><Book id="3"><title>Angels and Demons</title><author>Dan Brown</author><summary>Robert Langdon is summoned to a Swiss</summary></Book></Books>

顯然在這個xml中包括三本書的一些基本資料:id   title   author   summary  解析的過程就是將這些資料提取出來。

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

dom實現的原理是把整個xml文檔一次性讀出,放在一個樹型結構裡。在需要的時候,尋找特定節點,然後對節點進行讀或寫。他的主要優勢是實現簡單,讀寫平衡;缺點是比較占記憶體,因為他要把整個xml文檔都讀入記憶體,檔案越大,這種缺點就越明顯。

sax的實現方法和dom不同。他只在xml文檔中尋找特定條件的內容,並且只提取需要的內容。這樣做佔用記憶體小,靈活。

NSXMLParser 實現的是sax方法解析xml檔案。

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

一、將上面的xml資料儲存為Books.xml作為本地xml資料,並匯入項目中。

二、由於book中含有幾個屬性,所以這裡第一個book類。

Book.h檔案:

#import <Foundation/Foundation.h>@interface Book : NSObject@property (nonatomic, readwrite) NSInteger bookID;@property (nonatomic, retain) NSString  *title;@property (nonatomic, retain) NSString  *author;@property (nonatomic, retain) NSString  *summary;@end

Book.m檔案

#import "Book.h"@implementation Book@synthesize bookID;@synthesize title;@synthesize author;@synthesize summary;@end

三、要實現對xml資料的解析實際上是通過實現NSXMLParserDelegate委託中的幾個方法。

#pragma mark xmlparser  //step 1 :準備解析  - (void)parserDidStartDocument:(NSXMLParser *)parser  {   }  //step 2:準備解析節點  - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict  {   }  //step 3:擷取首尾節點間內容  - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string  {       }    //step 4 :解析完當前節點  - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName  {     }    //step 5:解析結束  - (void)parserDidEndDocument:(NSXMLParser *)parser  {   }  //step 6:擷取cdata塊資料  - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock  {  }  

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

下面分別介紹:

Step 1: 在開始解析之前的一些準備工作,例如初始化一些儲存變數。在我的這個例子中,使用了一個Book執行個體變數來儲存一本書(也即是一組資訊),一個可變數組來儲存這三本書(即每一組資訊都當成這個數組中的一個元素),(此次要注意理解資料變數之間的關係),其他變數就暫不介紹啦(待會看原始碼就可以了)。

Step 2: 當解析器遇到xml的根標籤和一組資訊的開始標籤時就開始調用這個方法,在這個xml檔案中,遇到Books(xml檔案的根標籤),Book(一組資訊的開始標籤)時就會調用這個方法。那麼也就可以知道這個方法在程式運行過程中被調用了多次。那麼就可以用 if 語句判斷遇到的是Books還是Book,然後做一些相應的操作(具體的話待會看原始碼)。

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict  {   }  

注意其中的參數: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等。那麼對讀到的標籤進行判斷後就可以進行儲存操作啦!

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName  {     } 

這裡標籤參數就是elementName。

Step 5:對整個xml檔案解析結束後的一些操作。

Step 6:這個暫不解釋(我還沒有用到)。

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

.h檔案

#import <UIKit/UIKit.h>@class AppDelegate,Book;@interface ViewController : UIViewController <NSXMLParserDelegate> {        NSMutableString *currentElementValue;  //用於儲存元素標籤的值        NSMutableArray *books;  //用於儲存一組書籍        Book *aBook;  //書籍執行個體,代表一本書        BOOL storingFlag; //查詢標籤所對應的元素是否存在        NSArray *elementToParse;  //要儲存的元素}- (IBAction)xmlButton:(id)sender;@end

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

.m檔案

#import "ViewController.h"#import "AppDelegate.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.    //初始化要解析的元素標籤    elementToParse = [[NSArray alloc] initWithObjects:@"title",@"author",@"summary", nil];}- (void)didReceiveMemoryWarning{    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {    if([elementName isEqualToString:@"Books"]) {        //Initialize the array.        //在這裡初始化用於儲存最終解析結果的陣列變數,我們是在當遇到Books根項目時才開始初始化        books = [[NSMutableArray alloc] init];        }    else if([elementName isEqualToString:@"Book"]) {                //Initialize the book.        //當碰到Book元素時,初始化用於儲存Book資訊的執行個體對象aBook                aBook = [[Book alloc] init];                //Extract the attribute here.        //從attributeDict字典中讀取Book元素的屬性                aBook.bookID = [[attributeDict objectForKey:@"id"] integerValue];                NSLog(@"ID:%i", aBook.bookID);        }    storingFlag = [elementToParse containsObject:elementName];  //判斷是否存在要儲存的對象}- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {    // 當用於儲存當前元素的值是空時,則先用值進行初始化賦值    // 否則就直接追加資訊    if (storingFlag) {        if (!currentElementValue) {            currentElementValue = [[NSMutableString alloc] initWithString:string];        }        else {            [currentElementValue appendString:string];        }    }    }// 這裡才是真正完成整個解析並儲存資料的最終結果的地方- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {        if ([elementName isEqualToString:@"Book"]) {        [books addObject:aBook];        aBook = nil;    }        if (storingFlag) {        //去掉字串的空格        NSString *trimmedString = [currentElementValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];                //將字串置空        [currentElementValue setString:@""];                if ([elementName isEqualToString:@"title"]) {            aBook.title = trimmedString;            NSLog(@"title :%@",aBook.title);        }        if ([elementName isEqualToString:@"author"]) {            aBook.author = trimmedString;            NSLog(@"author :%@",aBook.author);        }        if ([elementName isEqualToString:@"summary"]) {            aBook.summary = trimmedString;            NSLog(@"summary :%@",aBook.summary);        }    }    }- (IBAction)xmlButton:(id)sender {    //開啟xml檔案,讀取資料到NSData    NSString *path = [[NSBundle mainBundle] pathForResource:@"Books" ofType:@"xml"];    NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];    NSData *data = ;    ;        //測試從xml接受到的資料    NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];    NSLog(@"%@",dataString);        NSXMLParser *m_parser = [[NSXMLParser alloc] initWithData:data];    //設定該類本身為代理類,即該類在聲明時要實現NSXMLParserDelegate委託協議    [m_parser setDelegate:self];  //設定代理為本地        BOOL flag = [m_parser parse]; //開始解析    if(flag) {        NSLog(@"解析指定路徑的xml檔案成功");    }    else {        NSLog(@"解析指定路徑的xml檔案失敗");    }    }@end

說明:

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

2、結合我上面的解釋和代碼,應該可以理解整個xml解析的過程的。

3、這裡我用的是本地的xml檔案,如果是想進行網路xml資料的解析的話,那也是很簡單的,就是通過url擷取xml資料替換掉這裡的本地xml,通過url擷取xml可以參考上一篇博文。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.