XML
xml解析的方式有2种:
- DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
- SAX:从根元素开始,按顺序一个元素一个元素的往下解析,比较适合解析大文件
在iOS中,解析XML的手段很多
- 苹果原生的 NSXMLParser:SAX方式解析,使用简单
第三方框架:
- libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
- GDataXML:DOM方式解析,由Google开发,基于libxml2
XML解析方式选择建议:
- 大文件:NSXMLParser,libxml2
- 小文件:GDataXML,NSXMLParser,libxml2
NSXMLParser
假如要解析如下一个XML:
<videos>
<video id="1" name="小黄人 第01部" length="10" image="resources/images/minion_01.png" url="resources/videos/minion_01.mp4"/>
<video id="2" name="小黄人 第02部" length="12" image="resources/images/minion_02.png" url="resources/videos/minion_02.mp4"/>
<video id="3" name="小黄人 第03部" length="14" image="resources/images/minion_03.png" url="resources/videos/minion_03.mp4"/>
<video id="4" name="小黄人 第04部" length="16" image="resources/images/minion_04.png" url="resources/videos/minion_04.mp4"/>
<video id="5" name="小黄人 第05部" length="18" image="resources/images/minion_05.png" url="resources/videos/minion_05.mp4"/>
<video id="6" name="小黄人 第06部" length="20" image="resources/images/minion_06.png" url="resources/videos/minion_06.mp4"/>
<video id="7" name="小黄人 第07部" length="22" image="resources/images/minion_07.png" url="resources/videos/minion_07.mp4"/>
<video id="8" name="小黄人 第08部" length="24" image="resources/images/minion_08.png" url="resources/videos/minion_08.mp4"/>
<video id="9" name="小黄人 第09部" length="26" image="resources/images/minion_09.png" url="resources/videos/minion_09.mp4"/>
<video id="10" name="小黄人 第10部" length="28" image="resources/images/minion_10.png" url="resources/videos/minion_10.mp4"/>
<video id="11" name="小黄人 第11部" length="30" image="resources/images/minion_11.png" url="resources/videos/minion_11.mp4"/>
<video id="12" name="小黄人 第12部" length="32" image="resources/images/minion_12.png" url="resources/videos/minion_12.mp4"/>
<video id="13" name="小黄人 第13部" length="34" image="resources/images/minion_13.png" url="resources/videos/minion_13.mp4"/>
<video id="14" name="小黄人 第14部" length="36" image="resources/images/minion_14.png" url="resources/videos/minion_14.mp4"/>
<video id="15" name="小黄人 第15部" length="38" image="resources/images/minion_15.png" url="resources/videos/minion_15.mp4"/>
<video id="16" name="小黄人 第16部" length="40" image="resources/images/minion_16.png" url="resources/videos/minion_16.mp4"/>
</videos>
解析代码:
#import "ViewController.h"
@interface ViewController ()<NSXMLParserDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
//NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
//NSLog(@"%@",str);
//创建XML解析器
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
//设置代理
parser.delegate = self;
//开始解析,这个方法是个阻塞的方法,在解析完成之前代码是不会继续往下执行的
[parser parse];
}];
}
#pragma mark---------------------------
#pragma mark NSXMLParserDelegate
//开始解析时调用,会将XML的元素逐行扫描
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
NSLog(@"%s",__func__);
}
//开始解析某个元素
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict
{
NSLog(@"%s",__func__);
NSLog(@"开始解析:%@-----%@",elementName,attributeDict);
}
//某个元素解析完毕
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
NSLog(@"%s",__func__);
NSLog(@"结束解析:%@",elementName);
}
//结束解析时调用
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(@"%s",__func__);
}
@end
以上输出结果:
2016-12-13 02:26:36.294 XMLTest[10283:435095] -[ViewController parserDidStartDocument:]
2016-12-13 02:26:36.304 XMLTest[10283:435095] -[ViewController parser:didStartElement:namespaceURI:qualifiedName:attributes:]
2016-12-13 02:26:36.305 XMLTest[10283:435095] 开始解析:videos-----{
}
2016-12-13 02:26:36.310 XMLTest[10283:435095] -[ViewController parser:didStartElement:namespaceURI:qualifiedName:attributes:]
2016-12-13 02:26:36.322 XMLTest[10283:435095] 开始解析:video-----{
id = 1;
image = "resources/images/minion_01.png";
length = 10;
name = "\U5c0f\U9ec4\U4eba \U7b2c01\U90e8";
url = "resources/videos/minion_01.mp4";
}
2016-12-13 02:26:36.326 XMLTest[10283:435095] -[ViewController parser:didEndElement:namespaceURI:qualifiedName:]
2016-12-13 02:26:36.345 XMLTest[10283:435095] 结束解析:video
...
2016-12-13 02:26:36.482 XMLTest[10283:435095] -[ViewController parser:didEndElement:namespaceURI:qualifiedName:]
2016-12-13 02:26:36.482 XMLTest[10283:435095] 结束解析:video
2016-12-13 02:26:36.482 XMLTest[10283:435095] -[ViewController parser:didEndElement:namespaceURI:qualifiedName:]
2016-12-13 02:26:36.483 XMLTest[10283:435095] 结束解析:videos
2016-12-13 02:26:36.483 XMLTest[10283:435095] -[ViewController parserDidEndDocument:]
使用第三方库解析
GDataXML
导入第三方库到项目中,会报错,解决方案如下:
打开项目的TARGETS,选择Build Settings,按照如下步骤填入参数
// libxml includes require that the target Header Search Paths contain
//
// /usr/include/libxml2
//
// and Other Linker Flags contain
//
// -lxml2
然后会报一大堆错误,表示该库是非ARC机制的,那么做如下设置:
TARGETS -> Build Phases -> Compile Sources -> GDataXML 将参数设置为 -fno-objc-arc
#import "GDataXML/GDataXMLNode.h"
...
- (void)parserXMLWithGDataXMLWithData:(NSData*)data
{
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:kNilOptions error:nil];
//得到根元素,得到元素内部所有的名称为@"video"的子孙元素
NSArray *elements = [doc.rootElement elementsForName:@"video"];
//遍历
for(GDataXMLElement *element in elements)
{
//元素内部所有的属性都转换成模型
NSLog(@"-----------------");
NSLog(@"%@",[element attributeForName:@"id"].stringValue);
NSLog(@"%@",[element attributeForName:@"name"].stringValue);
NSLog(@"%@",[element attributeForName:@"length"].stringValue);
NSLog(@"%@",[element attributeForName:@"image"].stringValue);
NSLog(@"%@",[element attributeForName:@"url"].stringValue);
}
}
输出结果:
2016-12-13 03:17:02.604 XMLTest[11599:489926] -----------------
2016-12-13 03:17:02.606 XMLTest[11599:489926] 1
2016-12-13 03:17:02.607 XMLTest[11599:489926] 小黄人 第01部
2016-12-13 03:17:02.608 XMLTest[11599:489926] 10
2016-12-13 03:17:02.609 XMLTest[11599:489926] resources/images/minion_01.png
2016-12-13 03:17:02.610 XMLTest[11599:489926] resources/videos/minion_01.mp4
2016-12-13 03:17:02.610 XMLTest[11599:489926] -----------------
2016-12-13 03:17:02.614 XMLTest[11599:489926] 2
2016-12-13 03:17:02.615 XMLTest[11599:489926] 小黄人 第02部
2016-12-13 03:17:02.616 XMLTest[11599:489926] 12
2016-12-13 03:17:02.616 XMLTest[11599:489926] resources/images/minion_02.png
2016-12-13 03:17:02.617 XMLTest[11599:489926] resources/videos/minion_02.mp4
2016-12-13 03:17:02.618 XMLTest[11599:489926] -----------------
2016-12-13 03:17:02.618 XMLTest[11599:489926] 3
...