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>