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来存储数据,后续的使用会很方便。

posted @ 2016-02-14 17:36  akforsure  阅读(1392)  评论(1编辑  收藏  举报