XML解析
可扩展标记语言
XML的特点,出身名门,W3C制定,微软和IBM曾经共同大力推荐过的数据格式
XML 指可扩展标记语言(eXtensible Markup Language)
被设计用来传输和存储数据
HTML 是设计用来表示页面的
SAX解析
SAX是iOS默认的解析XML的方式,
simple API for XML
. 是一种占用内存非常低,但是只能读取不能写入的解析方式.因为他是一行一行的解析的.
准备一个模型以及两个属性接收解析出来的数据.
#import "ViewController.h"//导入模型类#import "VideoModel.h"//遵守代理协议@interface ViewController ()<NSXMLParserDelegate>//用于保存模型的数组@property(nonatomic,strong)NSMutableArray <VideoModel *>*modelArr;//用于临时保存解析出来的数据.@property(nonatomic,strong)NSMutableString *mStr;@end
NSXMLParse
类进行解析. 主要通过实现对象代理方法来解析.比较复杂.
@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; //URL 加载本地Apache服务器的数据解析 NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"]; //通过Session自动开启线程进行异步任务. [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //创建xml解析器 NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data]; //设置代理 parser.delegate = self; //解析开始 [parser parse]; }] resume]; }//初始化可变数组- (NSMutableArray *)modelArr { if (_modelArr == nil) { _modelArr = [NSMutableArray array]; } return _modelArr; }//初始化可变字符串- (NSMutableString *)mStr { if (_mStr == nil) { _mStr = [NSMutableString string]; } return _mStr; }
真正用于解析的代理方法 只用这5个,前后两对方法,加上中间一个获取数据的方法.
/** 开始解析 */- (void)parserDidStartDocument:(NSXMLParser *)parser; { //这里只是开始,貌似不用做什么}/** 开始一个新标签,这个时候应该创建对应的模型对象或者准备为模型的属性赋值. @param parser 解析器 @param elementName 标签元素名字 @param attributeDict 标签的属性 */- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(NSDictionary<NSString *, NSString *> *)attributeDict; { //看一下xml的结构,决定这里是干什么.对应当前的xml应该是判断后创建模型对象 /* <videos> <video videoId="1"> <name>01.C语言-语法预览</name> <length>320</length> <videoURL>/itcast/videos/01.C语言-语法预览.mp4</videoURL> <imageURL>/itcast/images/head1.png</imageURL> <desc>C语言-语法预览</desc> <teacher>李雷</teacher> </video> */ if ([elementName isEqualToString:@"video"]) { //创建新的模型对象 VideoModel *model = [VideoModel new]; //取出属性,为videoId赋值 model.videoId = @(attributeDict[@"videoId"].intValue); //将模型保存到数组 [self.modelArr addObject:model]; } }/** 解析到标签中间的文字 标签中的文字不是一次性能读完的,可能会分几次调用这个方法,所以创建一个可变字符串保存起来. @param parser 解析器 @param string 文字 */- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string; { [self.mStr appendString:string]; }/** 解析到一个元素结束的地方. @param parser 解析器 @param elementName 元素名字 */- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName; { //进行判断,外层标签不进行KVC,否则崩溃.如果标签过多也可以重写model的方法 里面什么都不做就可以避免KVC报错 //- (void)setValue:(id)value forUndefinedKey:(NSString *)key if (![elementName isEqualToString:@"video"] && ![elementName isEqualToString:@"videos"]) { //获取当前model VideoModel *model = self.modelArr.lastObject; //属性的值就是解析出来的string,key则是标签的名字 [model setValue:self.mStr forKey:elementName]; } //最后对mStr进行清空,准备进行下一个标签的解析 self.mStr.string = @""; }/** 结束解析 */- (void)parserDidEndDocument:(NSXMLParser *)parser; { //所有标签解析完毕,打印数组看看是否转换成功. NSLog(@"%@",self.modelArr); }@end
当然写完以后一定记得封装到对应的模型中,创建模型方法.那么在控制器中一句代码就搞定了.
- (NSArray *)parserXML:(NSString *)URLString; { //URL NSURL *url = [NSURL URLWithString:URLString]; //通过Session自动开启线程进行异步任务. [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //创建xml解析器 NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data]; //设置代理 parser.delegate = self; //解析开始 [parser parse]; }] resume]; return self.modelArr; }
控制器一句话搞定加载
DOM解析
因为iOS不能直接使用MAC的解析方式,所以DOM解析使用第三方框架.
GDataXMLNode
它有增加删除等方法,头文件里面有对应的方法,这里我们仅使用它来进行XML的反序列化. 也就是解析
如果你不是通过控制台中pod
加载的框架
pod init
pod
GDataXML-HTML
pod install
那么你可能会碰到引入框架后#import <libxml/tree.h>
报错的问题.
按照注释,在project->build Settings ->
Header Search Paths
和Other Linker Flags
中分别添加两个地址
/usr/include/libxml2
-lxml2
原文注释
// libxml includes require that the target Header Search Paths contain//// /usr/include/libxml2//// and Other Linker Flags contain//// -lxml2
使用pod install 导入框架会自动进行配置,非常方便
DOM的解析有点类似于字典转模型的过程.根据解析的XML的结构不同嵌套层次也不同.
由于整个解析过程比较连贯,所以直接复制粘贴整段代码
下面是全部代码,注释非常详细.
#import "VideoModel.h"#import <GDataXMLNode.h>@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; //1. 通过URL获取XML的Data数据. NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/videos.xml"]; [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //2. 获取到Data数据,创建GData对象 这里创建方法接收的是一个XML的string,所以先转换Data成String NSString *xmlString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; //这个方法可以进去看看实现,默认是用UTF-8编码 GDataXMLDocument *GD = [[GDataXMLDocument alloc]initWithXMLString:xmlString error:nil]; //3. 创建对象以后,取出根元素的子元素.返回的数组中都是GDataXMLElement NSArray *rootArr = GD.rootElement.children; //4. 那么现在要做的就是遍历这个数组,对每一个元素进行操作,转换成模型了,这个过程类似于字典转模型. //创建一个可变数组保存转换好的模型 NSMutableArray *modelArrM = [NSMutableArray array]; for (GDataXMLElement *element in rootArr) { // 1. 取出数组中的每一个元素后,先将这一组的video标签的属性videoId取出来 /* 1. 属性返回的是一个数组,我们的属性只有一个,所以取出第一个.元素类型是GDataXMLNode 2. 通过这个结构我们不难发现,elment对应的是一个树枝节点,它包含attributes数组,`属性`一定是到头了,是叶子节点.所以这个数组中存的是多个GDataXMLNode类型的元素. 3. GDataXMLNode是GDataXMLElement的父类.node有对应的方法name,stringValue.返回键值对. */ GDataXMLNode *node = element.attributes.firstObject; //NSLog(@"name = %@ value = %@",node.name,node.stringValue); //2. 创建一个模型将video标签的属性保存 KVC VideoModel *model = [VideoModel new]; [model setValue:node.stringValue forKey:node.name]; //3. 取出video标签的子标签,数组,每个子元素依然是GDataXMLElement 代表着一个一个的标签. //NSLog(@"element.children = %@",[element.children.firstObject class]); //循环遍历数组 for (GDataXMLElement *elementTag in element.children) { //4. 这里的每一个tag就是最后的叶子借点了. name 是 key xml是value //NSLog(@"%@",elementTag); [model setValue:elementTag.XMLString forKey:elementTag.name]; } //5. 将添加完元素的模型保存到数组 [modelArrM addObject:model]; } //转换完毕,看看结果 NSLog(@"%@",modelArrM); }] resume]; }@end
转换完毕.看看结果
作者:Aaronn
链接:https://www.jianshu.com/p/fb34ae5c3177