• iOS IM开发准备工作(一)XML解析


      关于XML解析的blog有很多,我本来不想写的;不过我发现有一些细节他们都没有说,我这里就多说一些细节。

      我们在哪些地方用XML:现在json用的这么多,使用XML通讯的已经不多了。我遇到的场景是,我们的服务器有很多个,需要用户去选择。那么我们就需要定期维护一个服务器列表,这个服务器列表的配置文件我需要每次下载。自然我就需要解析这一个文件。

      XML解析有两种模式SAXDOM。我用的是系统的 NSXMLParser 它是SAX解析。

      我写了一个工具类,先贴一下代码,下面会有一些说明

    .h

     1 #import <Foundation/Foundation.h>
     2 
     3 typedef NS_ENUM(NSInteger,xmlModelName){// 这里我对我的XML文件做了区别 因为要解析表情和服务器列表两种
     4     xmlModelNameFace,
     5     xmlModelNameServer,
     6 };
     7 @interface XMLParser : NSObject<NSXMLParserDelegate>
     8 // 这个是回调的Block
     9 @property(nonatomic,copy)void (^returnParseArray)(NSArray * returnArray);
    10 @property(nonatomic,readonly)xmlModelName currentModelName;
    11 
    12 - (instancetype)initWithFilePath:(NSString *)path fileType:(NSString *)fileType modelName:(xmlModelName)modelName;
    13 
    14 - (void)startWithFilePath:(NSString *)path fileType:(NSString *)fileType;
    15 @end

    .m

     1 #import "XMLParser.h"
     2 #import "FaceModel.h"
     3 #import "ToolClient.h"
     4 #import "ServerModel.h"
     5 @implementation XMLParser{
     6     NSMutableArray * faceArray;
     7     NSMutableArray * serverArray;
     8 }
     9 
    10 @synthesize currentModelName;
    11 - (instancetype)initWithFilePath:(NSString *)path fileType:(NSString *)fileType modelName:(xmlModelName)modelName{
    12     self = [super init];
    13     if(self){
    14         currentModelName = modelName;
    15     }
    16     return self;
    17 }
    18 
    19 - (void)startWithFilePath:(NSString *)path fileType:(NSString *)fileType {
    20     [self parseWithPath:path type:fileType];
    21 }
    22 //
    23 - (void)parseWithPath:(NSString *)filePath type:(NSString *)fileType{
    24     if (currentModelName == xmlModelNameFace) {
    25         faceArray = [[NSMutableArray alloc]init];
    26     }else if(currentModelName == xmlModelNameServer){
    27         serverArray = [[NSMutableArray alloc]init];
    28     }
    29     NSData *xmlData = [[NSData alloc] initWithContentsOfFile:filePath];
    30     if(xmlData && xmlData.length > 10){
    31         NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
    32         [parser setShouldProcessNamespaces:NO];
    33         [parser setShouldReportNamespacePrefixes:NO];
    34         [parser setShouldResolveExternalEntities:NO];
    35         [parser setDelegate:self];
    36         BOOL success = [parser parse];
    37         if(success) {
    38             [self parseSuccess];
    39         }else {
    40             [ToolClient activityShowMessage:@"XML解析失败" inView:[UIApplication sharedApplication].windows[0]];
    41         }
    42     }else {
    43         [ToolClient activityShowMessage:@"XML解析失败" inView:[UIApplication sharedApplication].windows[0]];
    44     }
    45 }
    46 // 成功后的回调
    47 - (void)parseSuccess {
    48     if(self.returnParseArray){
    49         if (currentModelName == xmlModelNameFace) {
    50             self.returnParseArray(faceArray);
    51         }else if(currentModelName == xmlModelNameServer){
    52             self.returnParseArray(serverArray);
    53         }
    54     }
    55 }
    56 #pragma mark - NSXMLParserDelegate
    57 
    58 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
    59   namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
    60     attributes:(NSDictionary *)attributeDict {
    61     //    NSLog(@"Name:%@",elementName);
    62     
    63     if([elementName isEqualToString:@"face"] && currentModelName == xmlModelNameFace) {
    64         FaceModel * faceModel = [[FaceModel alloc]init];
    65         faceModel.kID = [attributeDict[@"id"]intValue];
    66         faceModel.kName = attributeDict[@"name"];
    67         faceModel.kImage = attributeDict[@"file"];
    68         [faceArray  addObject:faceModel];
    69         faceModel = nil;
    70     }else if([elementName isEqualToString:@"Server"] && currentModelName == xmlModelNameServer){
    71         ServerModel * sModel = [[ServerModel alloc]init];
    72         sModel.serverName = attributeDict[@"name"];
    73         sModel.serverIP = attributeDict[@"ChatServerIP"];
    74         sModel.chatPort = attributeDict[@"chatPort"];
    75         sModel.fileServerIP = attributeDict[@"fileServerIP"];
    76         sModel.filePort = attributeDict[@"filePort"];
    77         [serverArray addObject:sModel];
    78         sModel = nil;
    79     }
    80 }
    81 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string  {
    82     //    NSLog(@"value:%@",string);
    83 }
    84 - (void)parserDidEndDocument:(NSXMLParser *)parser {
    85     //86     //    NSLog(@"%@",faceArray);
    87     
    88 }
    89 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    90     //    NSLog(@"elementName:%@",elementName);
    91     //    NSLog(@"qualifiedName:%@",qName);
    92     //
    93     //    NSLog(@"NSXMLParserDone");
    94     //    NSLog(@"%@",faceArray);
    95     //    NSLog(@"%i",(int)faceArray.count);
    96     
    97 }
    98 @end

    现在我来说一下XML解析的设置里面那3个设置为NO的参数是什么作用

     1 [parser setShouldProcessNamespaces:NO]; 2 [parser setShouldReportNamespacePrefixes:NO]; 3 [parser setShouldResolveExternalEntities:NO]; 

      第一个 setShouldProcessNamespaces 这个属性设置为YES的话,这两个方法会有值输出:parser:didStartElement:namespaceURI:qualifiedName:attributes: 和 parser:didEndElement:namespaceURI:qualifiedName: 这两个在解析过程中都是都是可以看到里面的节点或字段的名字的。我觉得调试的时候可以用一下。

      第二个 setShouldReportNamespacePrefixes 这个属性设置为YES的话,这两个方法会有值输出:parser:didStartMappingPrefix:toURI: 和 parser:didEndMappingPrefix: 这个我觉得完全没有必要用它

      第三个 setShouldResolveExternalEntities 这个属性设置为YES的话,这个方法会有值输出:parser:foundExternalEntityDeclarationWithName:publicID:systemID: 其中publicID 和systemID 都是XML文档的特有的标识。官方文档对这个两个的变量都是这么说的:

    You may access this property once a parsing operation has begun or after an error occurs.

    也就是当XML解析已经开始或者出现错误的时候,再去看它。也就是说如果你的XML写的够好 你就忽略它吧。

      上面的代码是工具类,下面这段会告诉你这段代码怎么用:

     1 // 解析文件 
     2 - (void)parseFile:(NSString *)filepath{
     3     NSLog(@"filepath%@",filepath);// 文件的路径
     4     if(data.length>10){// 简单的长度检测
     5         __weak SelectServerViewController * ws = self;// 弱引用
     6         // do parse
     7         XMLParser * xp = [[XMLParser alloc]initWithFilePath:filepath fileType:@"xml" modelName:xmlModelNameServer];
     8         // 先设置回调
     9         xp.returnParseArray = ^(NSArray * array){
    10             // 回调的结果 去给tableView 展示
    11             [ws gotDataArray:array];
    12         };
    13         // 再开始解析
    14         [xp startWithFilePath:filepath fileType:@"xml"];
    15     }
    16    
    17 }
    18 
    19 - (void)gotDataArray:(NSArray *)array {
    20     if(array){
    21 //        NSLog(@"array:%@",array);
    22         dataArray = [array mutableCopy];
    23         [myTableView reloadData];
    24     }
    25 }

    XML解析我就写这么多了,给一个建议 解析的时候用一个Model来存储数据,后续的使用会很方便。

  • 相关阅读:
    14-6 XShell连接远程服务器
    14-5 XManager工具安装
    14-4 本地私有化部署方案介绍
    14-3 阿里云域名购买及备案流程
    14-2 阿里云ECS服务器购买介绍
    13-7 Docker基本使用总结
    初识Redux-Saga
    React Native填坑之旅 -- FlatList
    React Native填坑之旅 -- 使用react-navigation代替Navigator
    React Native填坑之旅 -- 回归小插曲
  • 原文地址:https://www.cnblogs.com/akforsure/p/5189370.html
Copyright © 2020-2023  润新知