卡特琳娜 21牛頭 22
XML文件的解析是在代理方法中完成的.需要實現以下代理方法.
1.開始解析`XML`文件. 2.找開始節點(標簽). 3.找節點之間的內容. 4.找結束節點. 5.結束解析`XML`文件. 6.監聽`XML`文件是否解析出錯.
/// 下載二進制的XML數據 - (void)downloadXML { // 獲取URL NSURL *url = [NSURL URLWithString:@"http://localhost/videos.xml"]; // 創建請求 NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 發送異步請求,請求自建服務器中的demo.json數據 [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { // 判斷鏈接是否錯誤 if (connectionError) { NSLog(@"鏈接錯誤 %@",connectionError); return; } // 檢查響應體是否有錯 NSHTTPURLResponse *HTTPURLResponse = (NSHTTPURLResponse *)response; if (HTTPURLResponse.statusCode == 200 || HTTPURLResponse.statusCode == 304) { NSLog(@"二進制的XML數據 %@",data); } else { NSLog(@"服務器內部錯誤"); return; } }]; }2.拿到二進制的XML數據之後,創建XML解析器,設置代理,啟動解析器.
// 創建XML解析器 NSXMLParser *XMLParser = [[NSXMLParser alloc] initWithData:data]; // 設置解析器代理協議 XMLParser.delegate = self; // 開始解析 [XMLParser parse];3.實現代理方法
// 1.開始解析文檔 - (void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"1.開始解析文檔 %@",[NSThread currentThread]); } // 2.找開始節點 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary*)attributeDict { // elementName : 開始節點 // attributeDict : 節點屬性 NSLog(@"2.找開始節點 %@--%@",elementName,attributeDict); } // 3.找節點之間的內容 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // string : 節點之間的內容. NSLog(@"3.找節點之間的內容 %@",string); } // 4.找結束節點 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"4.找結束節點 %@",elementName); } // 5.結束解析文檔 - (void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"5.結束解析文檔"); } // 6.監聽解析是否出錯 - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"6.監聽解析是否出錯 %@",parseError); }
@interface VideoModel : NSObject /// 視頻編號 @property (nonatomic,copy) NSString *videoId; /// 視頻名稱 @property (nonatomic,copy) NSString *name; /// 視頻長度 @property (nonatomic,copy) NSString *length; /// 視頻鏈接 @property (nonatomic,copy) NSString *videoURL; /// 視頻圖標 @property (nonatomic,copy) NSString *imageURL; /// 視頻標題 @property (nonatomic,copy) NSString *desc; /// 視頻作者 @property (nonatomic,copy) NSString *teacher; /// 字典轉模型 : 解析XML的時候,沒有字典,所以這個不需要 //+ (instancetype)videoWithDict:(NSDictionary *)dict; @end /**/
@implementation VideoModel /// 無用處 + (instancetype)videoWithDict:(NSDictionary *)dict { // 創建模型對象 VideoModel *v = [[VideoModel alloc] init]; // KVC 字典轉模型 [v setValuesForKeysWithDictionary:dict]; // 返回模型對象 return v; } /// 打印模型的詳細內容 - (NSString *)description { return [NSString stringWithFormat:@"<%@ : %p> { videoId : %@, name : %@, length : %@, videoURL : %@, imageURL : %@, desc : %@, teacher : %@}", [self class], self, self.videoId, self.name, self.length, self.videoURL, self.imageURL, self.desc, self.teacher]; } @end
XML數據轉模型數據的准備工作將XML文件中的數據讀取出來,轉換成可以直接使用的模型數據.
@interface ViewController ()/// video對應的模型對象 @property (nonatomic,strong) VideoModel *currentVideo; /// 拼接節點之間內容的字符串 @property (nonatomic,copy) NSMutableString *stringM; /// 模型數組 @property (nonatomic,strong) NSMutableArray *videoM; @end @implementation ViewController - (NSMutableString *)stringM { if (_stringM == nil) { _stringM = [NSMutableString string]; } return _stringM; } - (NSMutableArray *)videoM { if (_videoM == nil) { _videoM = [NSMutableArray array]; } return _videoM; }
- (void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"1.開始解析文檔 %@",[NSThread currentThread]); }2.找開始節點
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary3.找節點之間的內容*)attributeDict { // elementName : 開始節點 // attributeDict : 節點屬性 NSLog(@"2.找開始節點 %@--%@",elementName,attributeDict); // 每找到一個video節點(標簽),就創建一個對應的模型對象 if ([elementName isEqualToString:@"video"]) { // 創建video標簽對應的模型對象 self.currentVideo = [[VideoModel alloc] init]; // 拿到標簽的屬性,可以給模型的videoId屬性賦值 self.currentVideo.videoId = attributeDict[@"videoId"]; // 將模型對象添加到模型數組中 [self.videoM addObject:self.currentVideo]; } }
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // string : 節點之間的內容.(內容不會一次性找全) NSLog(@"3.找節點之間的內容 %@",string); // 拼接節點之間的字符串 [self.stringM appendString:string]; }
4.找結束節點
注意 :在KVC給模型的屬性賦值的過程中,一定要排除videos和video兩個節點.因為這兩個節點不需要轉模型,且在模型類中沒有對應的屬性值.不排除掉,KVC在賦值過程中程序會崩潰.
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"4.找結束節點 %@",elementName); // 找到了結束節點,說明節點之間的內容已經獲取到了,就可以給模型的屬性賦值了 // 如果要在這個方法裡面獲取到模型,那麼模型需要定義成全局的 // 一定要排除`videos`和`video`兩個節點,這兩個節點不需要轉模型 if (![elementName isEqualToString:@"videos"]&&![elementName isEqualToString:@"video"]) { [self.currentVideo setValue:self.stringM forKey:elementName]; } }5.結束解析文檔
- (void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"5.結束解析文檔"); // 打印全部模型 NSLog(@"%@",self.videoM); }6.監聽解析是否出錯
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"6.監聽解析是否出錯 %@",parseError); }
不能按照字典轉模型的邏輯來處理XML轉模型.解析XML數據的過程中沒有字典.
每個video標簽就是描述一個視頻的.每個模型對象也是用來描述一個視頻的.所以每找到一個video標簽就要創建一個對應的模型對象.模型對象屬性賦值會在多個代理方法中進行賦值.所以需要定義成全局的模型對象.
節點之間的內容有時候不會一次性就找全,所以需要多次拼接字符串,而且要在找結束節點代理方法中使用,所以也要定義成全局的可變字符串.
// 4.找結束節點 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"4.找結束節點 %@",elementName); // 找到了結束節點,說明節點之間的內容已經獲取到了,就可以給模型的屬性賦值了 // 如果要在這個方法裡面獲取到模型,那麼模型需要定義成全局的 // 一定要排除`videos`和`video`兩個節點,這兩個節點不需要轉模型 if (![elementName isEqualToString:@"videos"]&&![elementName isEqualToString:@"video"]) { [self.currentVideo setValue:self.stringM forKey:elementName]; } // 給模型屬性賦值完成之後,需要清空字符串. [self.stringM setString:@""]; }
集成GData框架
1.獲取XML文檔. 2.獲取XML文檔的根標簽. 3.遍歷根標簽,獲取根標簽的子標簽(video標簽),創建video標簽對應的模型對象. 4.遍歷video標簽,獲取video標簽的子標簽,給模型對象的屬性賦值. 5.遍歷video標簽,獲取video標簽的屬性,給模型對象的videoId屬性賦值.
-(void)DOM:(NSData*)data { //1.獲取XML文檔 GDataXMLDocument*XMLDocument=[[GDataXMLDocumentalloc]initWithData:dataerror:NULL]; //2.獲取XML文檔的根標簽 GDataXMLElement*rootElement=XMLDocument.rootElement; //創建模型數組,將模型對象添加到模型數組中 NSMutableArray*videoM=[NSMutableArrayarray]; //3.遍歷根標簽,獲取根標簽的子標簽(video標簽),創建video標簽對應的模型對象 for(GDataXMLElement*videoElementinrootElement.children){ //創建video標簽對應的模型對象 VideoModel*video=[[VideoModelalloc]init]; //將模型對象添加到模型數組中 [videoMaddObject:video]; //4.遍歷video標簽,獲取video標簽的子標簽,給模型對象的屬性賦值 for(GDataXMLElement*subElementinvideoElement.children){ //KVC給模型的屬性賦值 [videosetValue:subElement.stringValueforKey:subElement.name]; } //5.遍歷video標簽,獲取video標簽的屬性,給模型對象的videoId屬性賦值 NSLog(@"%@",[videoElement.attributesclass]); for(GDataXMLNode*attrinvideoElement.attributes){ //KVC給模型的videoId屬性賦值 [videosetValue:attr.stringValueforKey:attr.name]; } } NSLog(@"%@",videoM); }