好吧,一下博文轉自:http://www.tuicool.com/articles/Qnmu6fphp
對xml進行解析的標準有兩種:sax以及dom。css
首先這兩種標準並非針對java的,他們在各類語言環境下均可以實現。dom是真正的國際標準。sax是事實的標準,它不禁任何商業組織維 護,而是由一個非商業的組織在運做。就像iso7層模型和tcp/ip同樣,雖然sax不是正式的標準,可是一點不影響其在xml解析領域的地位。html
dom實現的原理是把整個xml文檔一次性讀出,放在一個樹型結構裏。在須要的時候,查找特定節點,而後對節點進行讀或寫。它的主要優點是實現簡單,讀寫平衡;缺點是比較佔內存,由於他要把整個xml文檔都讀入內存,文件越大,這種缺點就越明顯。java
sax的實現方法和dom不一樣。數組
SAX解析XML,是基於事件通知的模式,一邊讀取XML文檔一邊處理,沒必要等整個文檔加載完以後才採起操做,當在讀取解析過程當中遇到須要處理的對象,會發出通知對其進行處理。因爲該方法 只在xml文檔中查找特定條件的內容,而且只提取須要的內容。這樣作佔用內存小,靈活,正好知足咱們的需求。ruby
在iOS中,能夠經過NSXMLParser實現sax方法解析xml文件。app
對於NSXMLParser,經常使用的初始化方法有兩種:經過XML的URL初始化和經過本地的XML文件初始化。dom
1.使用NSXMLParser解析XML網址數據tcp
首先給出一個XML資源網址: http://rss.sina.com.cn/tech/index.shtml ,也就是新浪新聞頻道列表,能夠用來練習解析XML數據。ui
使用NSXMLParser解析XML數據的關鍵是實現NSXMLParserDelegate中的方法:
#pragma mark -
#pragma mark NSXMLParserDelegate /* 開始解析xml文件,在開始解析xml節點前,經過該方法能夠作一些初始化工做 */ - (void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"開始解析xml文件"); } /* 當解析器對象遇到xml的開始標記時,調用這個方法開始解析該節點 */ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { NSLog(@"發現節點"); } /* 當解析器找到開始標記和結束標記之間的字符時,調用這個方法解析當前節點的全部字符 */ - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { NSLog(@"正在解析節點內容"); } /* 當解析器對象遇到xml的結束標記時,調用這個方法完成解析該節點 */ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"解析節點結束"); } /* 解析xml出錯的處理方法 */ - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"解析xml出錯:%@", parseError); } /* 解析xml文件結束 */ - (void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"解析xml文件結束"); }
在這裏我選擇了 view-source:http://rss.sina.com.cn/news/allnews/tech.xml 進行解析。
其中一項內容是:
<item> <title> <![CDATA[蘋果設計主管艾維:設計最重要的是全心投入]]> </title> <link>http://go.rss.sina.com.cn/redirect.php?url=http://tech.sina.com.cn/it/2013-10-11/14588806471.shtml</link> <author>SINA.com</author> <guid>http://go.rss.sina.com.cn/redirect.php?url=http://tech.sina.com.cn/it/2013-10-11/14588806471.shtml</guid> <category> <![CDATA[科技新聞]]> </category> <pubDate>Fri, 11 Oct 2013 06:58:40 GMT</pubDate> <comments></comments> <description> <![CDATA[ 新浪科技訊 北京時間10月11日下午消息,蘋果首席設計師喬尼・艾維(Jony Ive)接受媒體採訪時表示,設計產品的過程當中最重要的是要真心重視這項工做,付出本身最大的努力。並且要增強與各類材料的親身接觸,不能過分依賴電腦建模。 「在對待人們不會馬上發現的事情時,我....]]> </description> </item>
在這裏要解析的是新聞的標題title,摘要description,發佈時間pubDate。
首先聲明三個數組來存儲這些新聞內容:
static NSString *xmlURLString = @"http://rss.sina.com.cn/news/allnews/tech.xml"; // 要解析的XML網址 @interface ViewController () <NSXMLParserDelegate> @property (nonatomic, strong) NSMutableArray *newsTitles; // 標題 @property (nonatomic, strong) NSMutableArray *newsDescription; // 摘要 @property (nonatomic, strong) NSMutableArray *newsPublicDates; // 發佈時間 @property (nonatomic, strong) NSMutableString *tempString; // 用於臨時保存解析的字符數據 @property (nonatomic, strong) NSXMLParser *xmlParser; // XML解析器 @end
看看程序的界面:
有一個spinner_view用來指示正在解析xml數據,parse按鈕按下後開始解析xml數據,showxml_textView用於顯示解析後的新聞內容。
在按下parse按鈕後,對解析器進行初始化並啓動解析:
- (IBAction)parseXML:(id)sender { xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:xmlURLString]]; xmlParser.delegate = self; [xmlParser parse]; }
必需要設置解析器的委託爲本身。
在parse方法調用後,將觸發NSXMLParser中的方法,開始進行XML解析工做:
#pragma mark - #pragma mark NSXMLParserDelegate /* 開始解析xml文件,在開始解析xml節點前,經過該方法能夠作一些初始化工做 */ - (void)parserDidStartDocument:(NSXMLParser *)parser { [spinner_view startAnimating]; newsTitles = nil; newsDescription = nil; newsPublicDates = nil; tempString = nil; showxml_textView.text = @""; NSLog(@"開始解析xml文件"); } /* 當解析器對象遇到xml的開始標記時,調用這個方法開始解析該節點 */ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { NSLog(@"發現節點"); if([elementName isEqualToString:@"title"]) { if(newsTitles == nil) newsTitles = [[NSMutableArray alloc] init]; } else if([elementName isEqualToString:@"description"]) { if(newsDescription == nil) newsDescription = [[NSMutableArray alloc] init]; } else if([elementName isEqualToString:@"pubDate"]) { if(newsPublicDates == nil) newsPublicDates = [[NSMutableArray alloc] init]; } else { } } /* 當解析器找到開始標記和結束標記之間的字符時,調用這個方法解析當前節點的全部字符 */ - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { NSLog(@"正在解析節點內容"); if(self.tempString == nil) self.tempString = [[NSMutableString alloc] init]; [self.tempString appendString:string]; } /* 當解析器對象遇到xml的結束標記時,調用這個方法完成解析該節點 */ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"解析節點結束"); if([elementName isEqualToString:@"title"]) { [newsTitles addObject:self.tempString]; } else if([elementName isEqualToString:@"description"]) { [newsDescription addObject:self.tempString]; } else if([elementName isEqualToString:@"pubDate"]) { [newsPublicDates addObject:self.tempString]; } else { } self.tempString = nil; } /* 解析xml出錯的處理方法 */ - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"解析xml出錯:%@", parseError); } /* 解析xml文件結束 */ - (void)parserDidEndDocument:(NSXMLParser *)parser { if (!tempString) { tempString = [[NSMutableString alloc] init]; } for (int i = 2; i < 10; i++) { [tempString appendString:newsTitles[i + 1]]; [tempString appendString:newsDescription[i]]; [tempString appendString:newsPublicDates[i]]; [tempString appendString:@"\n------------------------------------------------"]; } showxml_textView.text = tempString; NSLog(@"解析xml文件結束"); [spinner_view stopAnimating]; }
簡單說一說該解析過程:
(1)在parse方法調用後,受委託的類首先調用委託中的
/* 開始解析xml文件,在開始解析xml節點前,經過該方法能夠作一些初始化工做 */
- (void)parserDidStartDocument:(NSXMLParser *)parser
方法進行一些初始化工做,好比清空保存新聞內容的數組,對界面內容操做等。
(2)在解析過程當中,若是遇到xml開始標記,代表已經遇到了一個xml節點,此時將調用委託中的
/* 當解析器對象遇到xml的開始標記時,調用這個方法開始解析該節點 */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
方法開始解析這個節點。
這個時候,應該對存儲節點的數組進行初始化工做。
(3)在解析節點時,將調用委託中的
/* 當解析器找到開始標記和結束標記之間的字符時,調用這個方法解析當前節點的全部字符 */
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
方法解析該節點中的全部字符。此時能夠用一個tempString變量保存其中的字符內容。
(4)在遇到一個xml結束標記後,代表解析該xml節點結束,此時能夠調用
/* 當解析器對象遇到xml的結束標記時,調用這個方法完成解析該節點 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
完成解析後的工做,例如將解析獲得的結果存入數組中。
(5)若是解析出錯,將調用
/* 解析xml出錯的處理方法 */
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"解析xml出錯:%@", parseError); }
進行出錯處理。
(6)若是解析沒有出錯,也就是在成功解析整個XML文件後,將調用
/* 解析xml文件成功 */
- (void)parserDidEndDocument:(NSXMLParser *)parser
在該方法中可使用xml解析後的完整數據。
運行結果:
2.使用NSXMLParser解析本地的XML文件
能夠在Xcode中新建一個RTF文件,而後將XML中的文字內容粘貼到該文件中,例如:
<?xml version="1.0" encoding="UTF-8"?>
<Data> <Movie> <title>good lucky to you</title> <box>111</box> <summary>This is a story</summary> </Movie> <Movie> <title>hello</title> <box>99</box> <summary>oh,yes</summary> </Movie> <Movie> <title>Cold</title> <box>100</box> <summary>I love cold weather</summary> </Movie> </Data>
最後將rtf後綴改成xml就能夠了。
若是修改xml文件中的內容,好比去掉一個</summary>,那麼在解析xml文件時將會出錯,例如:
2013-10-11 16:46:27.777 XMLParserDemo[5636:a0b] 解析xml出錯:Error Domain=NSXMLParserErrorDomain Code=76 "The operation couldn’t be completed. (NSXMLParserErrorDomain error 76.)" UserInfo=0x8c40f70 {NSXMLParserErrorLineNumber=20, NSXMLParserErrorColumn=13, NSXMLParserErrorMessage=Opening and ending tag mismatch: summary line 0 and Movie }
此時,程序將調用出錯處理方法
/* 解析xml出錯的處理方法 */
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"解析xml出錯:%@", parseError); }
但最終不會調用
- (void)parserDidEndDocument:(NSXMLParser *)parser
也就是說,只有解析xml成功,纔會有parserDidEndDocument:方法的調用。
和解析xml的url數據惟一不一樣的是解析器的初始化方法不一樣,這裏的是:
- (IBAction)parseXML:(id)sender {
// xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:xmlURLString]];
NSString *path = [[NSBundle mainBundle] pathForResource:@"xml" ofType:@"xml"]; // 找到文件路徑 NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; // 建立文件處理器 NSData *data = [file readDataToEndOfFile]; // 讀取文件中的二進制數據 [file closeFile]; // 關閉文件 xmlParser = [[NSXMLParser alloc] initWithData:data]; // 經過文件中的二進制數據初始化xml解析器 xmlParser.delegate = self; // 設置委託 [xmlParser parse]; // 開始轉換 }
對於解析url的xml數據的解析器初始化方法爲:
xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:xmlURLString]];
解析本地xml文件的解析器的初始化方法爲:
NSFileHandle *file = [ NSFileHandle fileHandleForReadingAtPath :path]; // 建立文件處理器
NSData *data = [file readDataToEndOfFile ]; // 讀取文件中的二進制數據
xmlParser = [[ NSXMLParser alloc ] initWithData :data]; // 經過文件中的二進制數據初始化 xml 解析器
其解析過程是同樣的,只是修改一下各個節點的節點名就能夠了。