卡特琳娜 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);
}