你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS & XML淺談

iOS & XML淺談

編輯:IOS開發綜合

XML簡介

  • XML出身名門,W3C制定,微軟和IBM曾經共同大力推薦過的數據格式.
  • XML指可擴展標記語言(Extensible Markup Language).
  • 被設計用來傳輸和存儲數據.在以前是常用的數據格式.
  • 對比 :HTML超文本標記語言,是設計用來顯示網頁的.並不是保存數據和傳輸的方式.

XML格式

  • XML由標記組成,xml的標記是可擴展的,沒有預定義.
  • 這就是標記.有開始標記和結束標記.例如表示開始標記,表示結束標記.是成對出現的.
  • 注意 :一個XML文件有且只有一個節點(標簽).

XML演練

新建一個empty空文件,取名demo.xml




    
        卡特琳娜
        21
    

    
        牛頭
        22
    


    
    


    



XML文件解析方式

  • 如果想獲取到XML文件中保存的數據,需要將XML文件中的數據解析出來.
  • SAX方式解析和DOM方式解析

SAX方式解析XML

  • 蘋果官方提供的原生的解析XML文件的方式
  • 在iOS上解析XML文件的方式.
  • 速度快,內存占用小.
  • 是只讀的,只能讀取XML文件數據不能做修改操作.

DOM方式解析XML

  • 是在MAC使用的解析方式.
  • 注意 :內存消耗極大,不適用於手機.
  • 可以讀寫XML文件.
  • iPhone無法直接使用DOM方式解析XML.
  • 如果要在iPhone上使用DOM方式解析XML文件,可以使用第三方框架.
 

XML解析之SAX解析

SAX方式解析XML步驟

  • 創建XML文件解析器.
  • 遵守解析器的代理協議.
  • 啟動解析器,開始解析.

XML文件的解析是在代理方法中完成的.需要實現以下代理方法.

1.開始解析`XML`文件.
2.找開始節點(標簽).
3.找節點之間的內容.
4.找結束節點.
5.結束解析`XML`文件.
6.監聽`XML`文件是否解析出錯.

SAX方式解析XML實現

1.發送網絡請求,獲取二進制的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);
}

結論

  • 通過代理方法中的NSLog,可以了解到解析XML文件中數據的過程.
  • 以上步驟,2--->3--->4,會不斷循環,一直到所有數據解析完成.
  • 節點之間的內容並不是一次就能找全的,有時候需要循環多次才能找全.
  • 如果解析數據量非常大的XML文件是很耗時的.當在哪個線程設置了代理協議,就在哪個線程中解析.
 

XML解析之轉模型

准備模型類

.h文件中的聲明
@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

/*
 
*/
.m文件中的實現
@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文件中的數據讀取出來,轉換成可以直接使用的模型數據.

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;
}

實現代理方法

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);

    // 每找到一個video節點(標簽),就創建一個對應的模型對象
    if ([elementName isEqualToString:@"video"]) {
        // 創建video標簽對應的模型對象
        self.currentVideo = [[VideoModel alloc] init];
        // 拿到標簽的屬性,可以給模型的videoId屬性賦值
        self.currentVideo.videoId = attributeDict[@"videoId"];
        // 將模型對象添加到模型數組中
        [self.videoM addObject:self.currentVideo];
    }
}

3.找節點之間的內容
- (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:@""];
}

 

 

XML解析之DOM解析

  • 僅做了解.

DOM簡介

  • DOM: Document Object Model
  • DOM: 文檔對象模型 (文檔樹模型)
  • 一次性把XML文件全部加載到內存,內存消耗大,適合讀寫比較小的XML文件.
  • 之前的SAX方式只能讀取XML文件,但是DOM方式可以修改XML文件,包括添加刪除修改節點.
  • iOS系統默認不支持DOM解析,在iOS系統下解析DOM的話需要第三方框架.
  • 第三方框架 : GData/KissXML(XMPP中使用此框架)

GData中類的關系分析

集成GData框架

  • 導入GDataXMLNode第三方文件.
  • 解決GData的報錯.

 

GData解析XML的步驟

1.獲取XML文檔.
2.獲取XML文檔的根標簽.
3.遍歷根標簽,獲取根標簽的子標簽(video標簽),創建video標簽對應的模型對象.
4.遍歷video標簽,獲取video標簽的子標簽,給模型對象的屬性賦值.
5.遍歷video標簽,獲取video標簽的屬性,給模型對象的videoId屬性賦值.

GData解析XML的實現

  • 模型類沒有變化,還是SAX方式解析的那個模型類.
  • 從網絡中獲取到XML文件的二進制數據.
  • 代碼實現 :
///DOM方式解析XML
-(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);
}

 


  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved