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

...

results matching ""

    No results matching ""