iOS 开发 网络编程与通信之XML解析

    xiaoxiao2021-12-14  19

    XML文件解析方式

    SAX方式解析XML 苹果官方提供的原生的解析XML文件的方式 在iOS上解析XML文件的方式. 速度快,内存占用小. 是只读的,只能读取XML文件数据不能做修改操作.

    DOM方式解析XML 是在MAC使用的解析方式. 注意 : 内存消耗极大,不适用于手机. 可以读写XML文件. iPhone无法直接使用DOM方式解析XML. 如果要在iPhone上使用DOM方式解析XML文件,可以使用第三方框架.

    解析XML过程

    //发送请求 1.获取URL–>创建请求–>发送请求–>响应处理–>XML解析 //xml解析器 2>创建XML解析器–>设置解析器代理–>开启解析器 //代理方法 3>开启–>开始节点–>节点内容–>结束节点–>结束–>监听错误信息 //模型(开始节点–节点内容–结束节点) 4>判断开始节点–创建模型–标签属性赋值给模型–模型添加到数组 //可遍数组 5>保存节点内容的可变字符串 //可变字符串 6>每次取出属性数组的模型–判断对应节点–给模型属性赋值–可变字符串置为@”“

    NSXMLParser–parse–DidStartDocument–didStartElement–foundCharacters–didEndElement–DidEndDocument–parseErrorOccurred

    实例XML解析

    // // ViewController.m // XML解析之SAX // // Created by Apple on 14/7/5. // Copyright © 2014年 mac. All rights reserved. // #import "ViewController.h" #import "VideoModel.h" @interface ViewController () <NSXMLParserDelegate> @property (nonatomic, strong) NSMutableArray *videoM; @property (nonatomic, copy) NSMutableString *stringM; @property (nonatomic, strong) VideoModel *currentModel; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self loadXML]; } - (void)loadXML { // URL NSURL *URL= [NSURL URLWithString:@"http://localhost/videos.xml"]; // 请求 NSURLRequest *request = [NSURLRequest requestWithURL:URL]; // 发送请求 [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { // 处理响应 if (connectionError == nil && data != nil) { // 反序列化 : 解析XML文件的二进制 // 1.创建XML解析器 NSXMLParser *XMLParser = [[NSXMLParser alloc] initWithData:data]; // 2.设置xml解析器的代理 XMLParser.delegate = self; // 3.启动解析器 [XMLParser parse]; } else { NSLog(@"%@",connectionError); } }]; } #pragma mark - NSXMLParserDelegate /* 1.VideoModel 什么时候创建? 2.模型对象的videoId属性什么时候赋值? 3.什么时候把创建的所有的模型对象添加到数组中? 4.什么时候给模型对象的其他属性赋值? 5.模型对象属性赋值的值在哪里? */ // 1.开始解析XML文档 - (void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"1.开始解析XML文档"); } // 2.找开始节点/标签/元素 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(NSDictionary<NSString *, NSString *> *)attributeDict { // elementName : 开始节点 // attributeDict : 节点的属性 // NSLog(@"2.找开始节点 = %@--%@",elementName,attributeDict); // 一旦找到video节点就需要建立一个模型对象 if ([elementName isEqualToString:@"video"]) { // 创建video节点对应的模型对象 VideoModel *model = [[VideoModel alloc] init]; // 给模型对象的videoId属性赋值 : 因为只有在这里可以拿到videoId(节点属性) model.videoId = attributeDict[@"videoId"]; // 把创建好的模型对象添加到模型数组 : 简单,在哪里创建的就在哪里添加 [self.videoM addObject:model]; } } // 3.找节点之间的类容 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // string : 节点之间的内容 // NSLog(@"3.找节点之间的类容 = %@",string); // 循环拼接节点之间的内容 [self.stringM appendString:string]; } // 4.找结束节点 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName { // elementName : 结束节点 // NSLog(@"4.找结束节点 = %@",elementName); // 在找到结束节点之后,给模型对象的其他属性赋值 // 从数组里面取最后一个元素(模型对象) VideoModel *model = [self.videoM lastObject]; // 给模型对象的其他属性赋值,但是videos节点和video节点是不需要赋值的 if ([elementName isEqualToString:@"videos"] || [elementName isEqualToString:@"video"]) { return; } // 只有排除了videos节点和video节点,才需要赋值 [model setValue:self.stringM forKey:elementName]; // 使用完了之后要把可变字符串清空,以免再次拼接时,把前面的内容也拼接进去了 // 这是把不可变字符串赋值给可变字符串,不被允许的 // self.stringM = @""; // 清空之后,stringM下次再用的时候,又要懒加载创建,性能差了一点 // self.stringM = nil; [self.stringM setString:@""]; } // 5.结束解析文档 - (void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"5.结束解析文档"); NSLog(@"%@",self.videoM); } // 6.监听XML文件是否解析出错 - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"6.监听XML文件是否解析出错 = %@",parseError); } - (NSMutableArray *)videoM { if (_videoM == nil) { _videoM = [NSMutableArray array]; } return _videoM; } - (NSMutableString *)stringM { if (_stringM == nil) { _stringM = [NSMutableString string]; } return _stringM; } /* 全局的模型对象不能懒加载,如果懒加载之后,当前类有且只有一个model */ //- (VideoModel *)currentModel //{ // if (_currentModel == nil) { // _currentModel = [[VideoModel alloc] init]; // } // return _currentModel; //} @end

    通过代理方法中的NSLog,可以了解到解析XML文件中数据的过程.以上步骤,2—>3—>4,会不断循环,一直到所有数据解析完成.节点之间的内容并不是一次就能找全的,有时候需要循环多次才能找全.

    如果解析数据量非常大的XML文件是很耗时的.当在哪个线程设置了代理协议,就在哪个线程中解析.

    不能按照字典转模型的逻辑来处理XML转模型.解析XML数据的过程中没有字典.

    每个video标签就是描述一个视频的.每个模型对象也是用来描述一个视频的.所以每找到一个video标签就要创建一个对应的模型对象.模型对象属性赋值会在多个代理方法中进行赋值.所以需要定义成全局的模型对象.

    节点之间的内容有时候不会一次性就找全,所以需要多次拼接字符串,而且要在找结束节点代理方法中使用,所以也要定义成全局的可变字符串.

    为了能够打印出所有的模型对象,需要将模型对象添加到数组中.

    在拼接下一个节点之间的内容之前,给模型属性付完值之后,将供拼接的可变字符串清空.

    注意 : 多次拼接完节点之间的内容,且在找结束节点代理方法中,给模型属性赋值完成之后,需要清空这个用于拼接的可变字符串.否则,会c重复拼接字符串,即将上一个节点之间的内容继续拼接到下一个节点之间的内容前面.

    转载请注明原文地址: https://ju.6miu.com/read-972224.html

    最新回复(0)