XML简介和使用AFNetworking解析XML案例

01-XML简介

曾经最流行的出身名门, W3C主推,IBM & 微软 可扩展"标记"语言

XML键值对  阅读方便,美观大方

<标记>

<标记>标记内容

<标记 属性1="属性"属性2="属性2">标记内容

02-XML解析方法 

-1.DOM  在Mac推荐使用。不推荐iOS中使用

- 原因:内存开销巨大!

     - 将数据已树形结构加载到内存- 可读写

   -Dom解析一次性将整个xml文档加载到内存,比较适合解析小文件

-2.SAX   推荐在iOS上解析

- 内存开销小

- 只读

- 速度快

- 从上到下,顺序解析的过程

-----------SAX解析的过程-事件驱动、扫描——不需要解析全部的信息、只获取自己需要的——

1.打开文档(准备)

2.开始节点

3.发现节点内容(一个节点内容,可能会读取很多次!)

4.结束节点

   (最后一个节点)

判断文档是否解析结束,如果没有就继续

5.文档解析完成 NSXMLParser 通过5个代理方法来循环解析!

 

A:苹果原生 NSXMLParser

B:第三方框架:

libxml2:纯C语言的框架,默认包容iOS SDK ,同时支持DOM,SAX方法解析。

GDataXML:DOM解析;基于libxml2;

案例一

用AFNetWorking请求XML返回格式

     //url
    NSString * url = @"https://127.0.0.1:8080/GetCallList";
    //设置请求头
    NSString *apiName = @"AtfSevice/GetCallList";
    NSString *sessionId = MyUUID;
    NSString *timeStamp = [XBTool getMiGuTimeStamp];
    NSString *accessCode = @"161107016888";//161107015550
    NSString *channel = @"3";
    NSString *accessCodeKey = @"3A4B04_6C7@F1D01";//秘钥
    NSString * mdn = @"15959285442";//18367151969
    NSString *md5PhoneNum = [mdn hd_base64Encode];//Mid手机号码,base64编码
    NSString * signature  = [NSString stringWithFormat:@"%@%@%@%@%@%@%@",apiName,sessionId,timeStamp,channel,accessCode,accessCodeKey,md5PhoneNum];//@"Signature"
    NSString * md5String = [signature hd_md5UpperString];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    manager.requestSerializer.timeoutInterval = 5;
    manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/xml", @"text/xml", nil];
    // 2.设置非校验证书模式
    manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
    manager.securityPolicy.allowInvalidCertificates = YES;
    [manager.securityPolicy setValidatesDomainName:NO];
    
    [manager.requestSerializer setValue:@"text/plain;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [manager.requestSerializer setValue:@"1.0" forHTTPHeaderField:@"Version"];
    [manager.requestSerializer setValue:sessionId forHTTPHeaderField:@"SessionId"];
    [manager.requestSerializer setValue:timeStamp forHTTPHeaderField:@"TimeStamp"];
    [manager.requestSerializer setValue:md5String forHTTPHeaderField:@"Signature"];
    [manager.requestSerializer setValue:channel forHTTPHeaderField:@"Channel"];
    [manager.requestSerializer setValue:accessCode forHTTPHeaderField:@"AccessCode"];
    [manager.requestSerializer setValue:@"1" forHTTPHeaderField:@"NetStandard"];
    [manager.requestSerializer setValue:@"1" forHTTPHeaderField:@"NetAccessType"];
    [manager.requestSerializer setValue:md5PhoneNum forHTTPHeaderField:@"Mid"];
    [manager POST:url parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"好的");
        //XML解析是一个耗时操作!
        HKXMLParser* parser = [[HKXMLParser alloc] initWithModelClassName:@"XBCallTagListModel" withElementName:@"CallRecord" modelFromBlock:^(NSDictionary *dataDic, id model) {
            // 第一种字典转模型:KVC
            // [model setValuesForKeysWithDictionary:dataDic];
            // 第二种字典转模型:MJExtension
            [model mj_setKeyValues:dataDic];
        }];
        //NSData -> NSMutableArray of models
        NSMutableArray* models = [parser modelsArrayFromParser:(NSXMLParser*)responseObject];
        self.dataArr = models;
        [self.tableView reloadData];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
    }];

 

案例二

用自定义封装HKXMLParser解析XML文件

XML格式如下

 

"1.0" encoding="UTF-8"?>

    0</ResultCode>
    成功</ResultDesc>
    
        "126574817923" Type="1" CallTime="下午4:40" ContactName="周小菊" Location="郑州" TypeStatus="0" TypeId="12" TypeName="诈骗" Count="100" TeleSpName="移动" />
        "186685864" Type="0" CallTime="下午4:40" ContactName="寇大胆" Location="洛阳" TypeStatus="0" TypeId="14" TypeName="外卖" Count="120" TeleSpName="联通" />
        "15727538134" Type="0" CallTime="下午2:40" ContactName="无英雄" Location="洛阳" TypeStatus="0" TypeId="14" TypeName="外卖" Count="120" TeleSpName="电信" />
    </CallList>
</Response>

1.HKXMLParser 封装

//
//  HKXMLParser.h
//  CallShow
//
//  Created by HuJinTao on 2018/7/24.
//  Copyright © 2018年 HuJinTao. All rights reserved.
//

#import 
// 定义一个Block,用来存储字典转模型的过程
typedef void(^ModelFromDictionaryBlock)(NSDictionary* dataDic,id model);
@interface HKXMLParser : NSObject
#pragma mark - Create a object
/**
 参数:
 1、模型对象的类名
 2、需要解析的XML节点名
 3、字典转模型的方式,例如:KVC或者是MJExtension
 */
/** 初始化方法,通过传入模型对象的类名,创建这个XML解析对象,字典转模型的方法 */
- (instancetype)initWithModelClassName:(NSString*)modelClassName withElementName:(NSString*)elementName  modelFromBlock:(ModelFromDictionaryBlock)modelFromDictionary;
/** 便利构造器类方法,通过传入模型对象的类名,创建这个XML解析对象,字典转模型的方法 */
+(instancetype)hkXMLParseWithModelClassName:(NSString*)modelClassName withElementName:(NSString*)elementName modelFromBlock:(ModelFromDictionaryBlock)modelFromDictionary;

#pragma mark - parser xml data
/** 通过NSData解析XML数据,返回模型数组 */
-(NSMutableArray*)modelsArrayFromData:(NSData*)data;
/** 通过NSXMLParser解析XML数据,返回模型数组 */
-(NSMutableArray*)modelsArrayFromParser:(NSXMLParser*)parser;
@end
//
//  HKXMLParser.m
//  CallShow
//
//  Created by HuJinTao on 2018/7/24.
//  Copyright © 2018年 HuJinTao. All rights reserved.
//

#import "HKXMLParser.h"
@interface HKXMLParser () 

/** NSMutableArray */
@property (nonatomic,strong)NSMutableArray *datas;
/** model name */
@property (nonatomic,strong)NSString *modelName;
/** element name */
@property (nonatomic,strong)NSString *elementName;
/** Block存储字典转模型的方法 */
@property (nonatomic,copy) ModelFromDictionaryBlock modelFromDictionary;

@end
@implementation HKXMLParser
#pragma mark - Create a object
- (instancetype)initWithModelClassName:(NSString*)modelClassName withElementName:(NSString*)elementName modelFromBlock:(ModelFromDictionaryBlock)modelFromDictionary
{
    self = [self init];
    if (self) {
        self.modelName = modelClassName;
        self.elementName = elementName;
        self.modelFromDictionary = modelFromDictionary;
    }
    return self;
}

+(instancetype)hkXMLParseWithModelClassName:(NSString*)modelClassName withElementName:(NSString*)elementName modelFromBlock:(ModelFromDictionaryBlock)modelFromDictionary{
    return [[HKXMLParser alloc] initWithModelClassName:modelClassName withElementName:elementName modelFromBlock:modelFromDictionary];
}

//别忘了重写datas的懒加载方法
-(NSMutableArray *)datas{
    if (_datas == nil) {
        _datas = [NSMutableArray array];
    }
    return _datas;
}

#pragma mark - parser xml data
/*
 * XML的SAX解析过程:
 * 1、传入XML格式的数据:NSData 2、创建NSXMLParser对象 3、设置代理,并实现代理的相关方法
 * 4、开始解析,从根元素开始,按顺序一个元素一个元素往下解析 5、返回解析XML后获取的数据对象
 */
-(NSMutableArray*)modelsArrayFromData:(NSData*)data{
    NSXMLParser *parse = [[NSXMLParser alloc] initWithData:data];
    parse.delegate = self;
    [parse parse];
    return self.datas;
}
/** 通过NSXMLParser解析XML数据,返回模型数组 */
-(NSMutableArray*)modelsArrayFromParser:(NSXMLParser*)parser {
    NSXMLParser *parse = parser;
    parse.delegate = self;
    [parse parse];
    return self.datas;
}
-(void)parserDidStartDocument:(NSXMLParser *)parser
{
    
}

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:self.elementName]) {
        
        //通过Objective-C的反射机制,直接用类名来创建模型对象
        id model = [[NSClassFromString(self.modelName) alloc] init];
        //将这个字典转为模型,然后赋值给模型数组
        self.modelFromDictionary(attributeDict,model);
        [self.datas addObject:model];
    }
    return;
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    
}
-(void)parserDidEndDocument:(NSXMLParser *)parser
{
    
}
@end

 

2.数据模型建立

#import "XBBaseModel.h"

@interface XBCallTagListModel : XBBaseModel
@property (nonatomic, strong) NSString * Mobile ;//呼叫号码
@property (nonatomic, strong) NSString * Type ;//呼叫类型
@property (nonatomic, strong) NSString * CallTime ;//拨打时间
@property (nonatomic, strong) NSString *ContactName;//通话号码 若为空时,由手机客户端再次匹配本地联系人名称,若存在就显示
@property (nonatomic, strong) NSString *Location;//号码归属地
@property (nonatomic, strong) NSString *TypeStatus;//是否为自标记号码 0:未标记
@property (nonatomic, strong) NSString *TypeId;//标记号码类型
@property (nonatomic, strong) NSString *TypeName;//标记类型名称
@property (nonatomic, strong) NSString *Count;//备注  描述被多少人标记信息
@property (nonatomic, strong) NSString *TeleSpName;//运营商名称

- (instancetype)initWithDict:(NSDictionary*)dict;
@end
#import "XBCallTagListModel.h"

@implementation XBCallTagListModel
-(instancetype)initWithDict:(NSDictionary *)dict {
    self = [super init];
    if (self) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self ;
}
@end

3.在ViewController中使用

    NSString* dataXmlPath = [[NSBundle mainBundle] pathForResource:@"videos.xml" ofType:nil];
    NSData* data = [NSData dataWithContentsOfFile: dataXmlPath];
    //1、创建HKXMLParse对象
    //参数:1、Model Class Name
    //     2、XML 需要解析的节点的名 CallRecord
    //     3、通过block传递字典转模型的方法 ---> 根据实际需求,可以用KVC也可以用MJExtension
    HKXMLParser* parser = [[HKXMLParser alloc] initWithModelClassName:@"XBCallTagListModel" withElementName:@"CallRecord" modelFromBlock:^(NSDictionary *dataDic, id model) {
        // 第一种字典转模型:KVC
        // [model setValuesForKeysWithDictionary:dataDic];
        // 第二种字典转模型:MJExtension
        [model mj_setKeyValues:dataDic];
    }];
    //NSData -> NSMutableArray of models
    NSMutableArray* models = [parser modelsArrayFromData:data];
    NSLog(@"models=====%@",models);

输出结果:

       0x1c02a6e40> ,
    0x1c02a7f20> ,
    0x1c02a7da0> 

 

转载于:https://www.cnblogs.com/StevenHuSir/p/HKXMLParser.html

你可能感兴趣的:(XML简介和使用AFNetworking解析XML案例)