ios-XML文档解析之SAX解析
2016-03-21 14:48
267 查看
首先SAX解析xml
*xml文档的格式特点是节点,大体思路是把每个最小的子节点作为对象的属性,每个最小子节点的'父'节点作为对象,将节点转化为对象,输出.
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321141105511-656616001.png)
每个节点都是成对存在的,有开始有结束.有始有终
搭建本地服务器,并创建异步请求访问本地服务器中的数据video.xml
currentVideo每次寻找到节点名字为video的时候创建一个video对象,并添加到数组videos中.
mString是开始与结束节点之间的内容用mString来存储.在找到结束节点之后把mString通过setvalue...forkey...的方式(kvc)赋值给video对应的属性.
通过SAX(NSXMLParser)方式解析xml文件要遵守协议NSXMLParserDelegate,设置代理.=self
创建video分类
.m文件
重写- (NSString *)description 为了在解析结束后打印出来看结果是否正确
开始写代理方法
开始查找节点,如果节点名称==video则创建对象self.currentVideo = [[Video alloc] init];并且加入可变数组videos中.
将开始于结束节点之间的内容用可变字符串mString保存起来.当找到结束节点名字后,利用结束节点名通过setvalue...forkey...方式把mString的内容赋值给对应的video(或者说self.currentVideo)的属性.
每次用完mString都要清空,不然前面的节点内容都会拼接到正在解析的节点的内容上.
文档解析完成.思路--->找最小子节点--->把最小子节点的父节点作为一个对象,最小子节点作为属性.通过读取到节点的名称,用kvc方式对对象的属性进行赋值.
文档输出由于汉字编码是Unicode方式需要对其转换.
下面演示不管是数组还是字典只要整体输出都会有编码问题
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321144131308-1275455945.png)
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321144219214-121492349.png)
解决方法:重写数组与字典的- (NSString *)descriptionWithLocale:(id)locale,写完不用导入头文件.
创建NSObject 分类Log
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321144541401-398169613.png)
用block循环逐个输出解决汉字问题
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321144636792-501335717.png)
小结:XML和json解析的区别
XML:
* 优点:1>所有的语言中格式统一,数据共享比较方便
* 缺点: 1>XML格式文件庞大,格式复杂,解析起来比较麻烦!压缩比例小。
JOSN:
* 优点:
* 1>数据结构简单,易于读写,易于解析,压缩比例大。
* 2>支持多种语言,java,ios,javascript,php等语言。
* 3>前端和后台维护简单方便。
* 缺点:1>JSON出现的时间比XML晚。移动端开发推荐使用json!!!
*xml文档的格式特点是节点,大体思路是把每个最小的子节点作为对象的属性,每个最小子节点的'父'节点作为对象,将节点转化为对象,输出.
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321141105511-656616001.png)
每个节点都是成对存在的,有开始有结束.有始有终
搭建本地服务器,并创建异步请求访问本地服务器中的数据video.xml
#import "ViewController.h" #import "Video.h" @interface ViewController () <NSXMLParserDelegate> //vidios用来保存video对象的数组 @property (nonatomic, strong) NSMutableArray *videos; //当前创建的video对象 @property (nonatomic, strong) Video *currentVideo; //存储当前节点的内容 @property (nonatomic, copy) NSMutableString *mString; @end
currentVideo每次寻找到节点名字为video的时候创建一个video对象,并添加到数组videos中.
mString是开始与结束节点之间的内容用mString来存储.在找到结束节点之后把mString通过setvalue...forkey...的方式(kvc)赋值给video对应的属性.
通过SAX(NSXMLParser)方式解析xml文件要遵守协议NSXMLParserDelegate,设置代理.=self
@implementation ViewController //懒加载--->初始化videos - (NSMutableArray *)videos { if (_videos == nil) { _videos = [NSMutableArray arrayWithCapacity:10]; } return _videos; } //初始化mString - (NSMutableString *)mString { if (_mString == nil) { _mString = [NSMutableString string]; } return _mString; } - (void)viewDidLoad { [super viewDidLoad]; [self loadXML]; } //异步请求xml - (void)loadXML { //异步请求服务器的xml文件 NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { if (connectionError) { NSLog(@"连接错误 %@",connectionError); return; } NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == 200 || httpResponse.statusCode == 304) { //解析数据 NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; //设置代理 parser.delegate = self; //开始执行代理的方法,代理的方法中开始解析的 [parser parse]; }else{ NSLog(@"服务器内部错误"); } }]; }
创建video分类
#import <Foundation/Foundation.h> @interface Video : NSObject @property (nonatomic, copy) NSNumber *videoId; @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSNumber *length; @property (nonatomic, copy) NSString *videoURL; @property (nonatomic, copy) NSString *imageURL; @property (nonatomic, copy) NSString *desc; @property (nonatomic, copy) NSString *teacher; @property (nonatomic, readonly) NSString *time; - (instancetype)initWithDict:(NSDictionary *)dict; + (instancetype)videoWithDict:(NSDictionary *)dict; @end
.m文件
#import "Video.h" @implementation Video - (instancetype)initWithDict:(NSDictionary *)dict { self = [super init]; if (self) { [self setValuesForKeysWithDictionary:dict]; } return self; } + (instancetype)videoWithDict:(NSDictionary *)dict { return [[self alloc] initWithDict:dict]; } - (NSString *)time { int len = self.length.intValue; return [NSString stringWithFormat:@"%02d:%02d:%02d", len / 3600, (len % 3600) / 60, (len % 60)]; } - (NSString *)description { return [NSString stringWithFormat:@"<%@ : %p> { videoId : %@, name : %@, length : %@, videoURL : %@, imageURL : %@, desc : %@, teacher : %@}", [self class], self, self.videoId, self.name, self.length, self.videoURL, self.imageURL, self.desc, self.teacher]; } @end
重写- (NSString *)description 为了在解析结束后打印出来看结果是否正确
开始写代理方法
//1 开始解析文档 - (void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"1 开始解析文档 %@",[NSThread currentThread]); } //2 找开始节点 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict { //elementName 节点的名称 //attributeDict 标签的属性 NSLog(@"2 找开始节点 %@--%@",elementName,attributeDict); //如果是video标签,创建video对象 if ([elementName isEqualToString:@"video"]) { self.currentVideo = [[Video alloc] init]; self.currentVideo.videoId = @([attributeDict[@"videoId"] intValue]); //添加到数组中 [self.videos addObject:self.currentVideo]; } }
开始查找节点,如果节点名称==video则创建对象self.currentVideo = [[Video alloc] init];并且加入可变数组videos中.
//3 找节点之间的内容 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // NSLog(@"3 找节点之间的内容 %@",string); //拼接字符串 [self.mString appendString:string]; }
将开始于结束节点之间的内容用可变字符串mString保存起来.当找到结束节点名字后,利用结束节点名通过setvalue...forkey...方式把mString的内容赋值给对应的video(或者说self.currentVideo)的属性.
//4 找结束节点 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { //elementName 节点名称 NSLog(@"4 找结束节点 %@",elementName); //判断标签是否是对应的属性 if (![elementName isEqualToString:@"video"] && ![elementName isEqualToString:@"videos"]) { //kvc 赋值的过程就是地址指向的过程,不会做类型转换 [self.currentVideo setValue:self.mString forKey:elementName]; } //清空可变字符串 [self.mString setString:@""]; }
每次用完mString都要清空,不然前面的节点内容都会拼接到正在解析的节点的内容上.
//5 结束解析文档 - (void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"5 结束解析文档"); NSLog(@"%@",self.videos); } //6 解析出错 - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"出错"); }
文档解析完成.思路--->找最小子节点--->把最小子节点的父节点作为一个对象,最小子节点作为属性.通过读取到节点的名称,用kvc方式对对象的属性进行赋值.
文档输出由于汉字编码是Unicode方式需要对其转换.
下面演示不管是数组还是字典只要整体输出都会有编码问题
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321144131308-1275455945.png)
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321144219214-121492349.png)
解决方法:重写数组与字典的- (NSString *)descriptionWithLocale:(id)locale,写完不用导入头文件.
创建NSObject 分类Log
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321144541401-398169613.png)
用block循环逐个输出解决汉字问题
![](https://images2015.cnblogs.com/blog/831196/201603/831196-20160321144636792-501335717.png)
小结:XML和json解析的区别
XML:
* 优点:1>所有的语言中格式统一,数据共享比较方便
* 缺点: 1>XML格式文件庞大,格式复杂,解析起来比较麻烦!压缩比例小。
JOSN:
* 优点:
* 1>数据结构简单,易于读写,易于解析,压缩比例大。
* 2>支持多种语言,java,ios,javascript,php等语言。
* 3>前端和后台维护简单方便。
* 缺点:1>JSON出现的时间比XML晚。移动端开发推荐使用json!!!
相关文章推荐
- iOS边练边学--通知机制和键盘处理小练习
- iOS事件处理---响应者链
- iOS 开发--动画
- 重识iOS
- iOS 警告收录及科学快速的消除方法
- iOS下运行CNN(深度学习)
- iOS_SN_LLDB常用命令
- iOS和我,开启编程人生
- iOS 视图控制器转场详解
- iOS边练边学--通知机制和键盘处理
- iOS本地项目依赖项(CocoaPods管理本地库)--csdn
- ios 获取屏幕的属性
- iOS 开发官方文档链接收集
- iOS 中使用token机制来验证用户的安全性
- 二维码 iOS
- iOS 第三方框架-MBProgressHUD
- iOS-时间戳转化成时间
- iOS中的滤镜
- iOS 把图片从Mac本地添加到iOS Simulator中
- ios二维码识别失败及解决方法