iOS开发网络篇—XML数据的解析

iOS开发网络篇—XML数据的解析

iOS开发网络篇—XML介绍

一、XML简单介绍

XML:全称是Extensible Markup Language,译作“可扩展标记语言”

跟JSON一样,也是常用的一种用于交互的数据格式,一般也叫XML文档(XML Document)

XML举例

<videos>

<video name="小黄人 第01部" length="30" />

<video name="小黄人 第02部" length="19" />

<video name="小黄人 第03部" length="33" />

</videos>

二、XML的语法

1.简单说明

一个常见的XML文档一般由以下部分组成

文档声明

元素(Element)

属性(Attribute)

2.文档声明

在XML文档的最前面,必须编写一个文档声明,用来声明XML文档的类型

最简单的声明

<?xml version="1.0" ?>

用encoding属性说明文档的字符编码

<?xml version="1.0" encoding="UTF-8" ?>

3.XML语法 – 元素(Element)

一个元素包括了开始标签和结束标签

拥有元素内容:<video>小黄人</video>

没有元素内容:<video></video>

没有元素内容的简写:<video/>

一个元素可以嵌套若干个子元素(不能出现交叉嵌套)

<videos>

<video>

<name>小黄人 第01部</name>

<length>30</length>

</video>

</videos>

注意:

(1)规范的XML文档最多只有1个根元素,其他元素都是根元素的子孙元素

(2)XML中的所有空格和换行,都会当做具体内容处理

下面两个元素的内容是不一样的

第1个

<video>小黄人</video>

第2个

<video>

小黄人

</video>

4.XML语法 – 属性(Attribute)

一个元素可以拥有多个属性

<video name="小黄人 第01部" length="30" />            ====》video元素拥有name和length两个属性

注意:属性值必须用 双引号"" 或者 单引号‘‘ 括住

实际上,属性表示的信息也可以用子元素来表示,比如

<video>

<name>小黄人 第01部</name>

<length>30</length>

</video>

三、XML的解析

1.简单说明

要想从XML中提取有用的信息,必须得学会解析XML

提取name元素里面的内容

<name>小黄人 第01部</name>

提取video元素中name和length属性的值

<video name="小黄人 第01部" length="30" />

XML的解析方式有2种

(1)DOM:一次性将整个XML文档加载进内存,比较适合解析小文件

(3)SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件

2.IOS开发中XML的解析

在iOS中,解析XML的手段有很多

(1)苹果原生   NSXMLParser:SAX方式解析,使用简单

(2)第三方框架

1)libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析

2)GDataXML:DOM方式解析,由Google开发,基于libxml2

XML解析方式的选择建议:

大文件:NSXMLParser、libxml2

小文件:GDataXML

3.NSXMLParser

(1)使用步骤

// 1.传入XML数据,创建解析器

NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

// 2.设置代理,监听解析过程

parser.delegate = self;

// 3.开始解析

[parser parse];

(2)说明

NSXMLParser采取的是SAX方式解析,特点是事件驱动,下面情况都会通知代理

当扫描到文档(Document)的开始与结束

当扫描到元素(Element)的开始与结束

(3)NSXMLParserDelegate

1)当扫描到文档的开始时调用(开始解析)- (void)parserDidStartDocument:(NSXMLParser *)parser

2)当扫描到文档的结束时调用(解析完毕)- (void)parserDidEndDocument:(NSXMLParser *)parser

3)当扫描到元素的开始时调用(attributeDict存放着元素的属性)- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict

4)当扫描到元素的结束时调用  - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName

(4)代码示例

  1 //
  2 //  YYViewController.m
  3 //  01-文顶顶客户端
  4 //
  5 //  Created by apple on 14-6-29.
  6 //  Copyright (c) 2014年 itcase. All rights reserved.
  7 //
  8
  9 #import "YYViewController.h"
 10 #import "MBProgressHUD+MJ.h"
 11 #import "YYviodesModel.h"
 12 #import "YYCell.h"
 13 #import <MediaPlayer/MediaPlayer.h>
 14 #import "YYMoviePlayerViewController.h"
 15
 16 @interface YYViewController ()<NSXMLParserDelegate>
 17 @property(nonatomic,strong)NSArray *videos;
 18
 19 @end
 20
 21 @implementation YYViewController
 22
 23 - (void)viewDidLoad
 24 {
 25     [super viewDidLoad];
 26     //去掉下划线
 27     self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;
 28
 29     [MBProgressHUD showMessage:@"正在努力加载中"];
 30
 31     //创建路径
 32
 33     NSString  *[email protected]"http://192.168.1.53:8080/MJServer/video?type=XML";
 34     NSURL *url=[NSURL URLWithString:urlStr];
 35
 36     //创建请求
 37     NSMutableURLRequest  *request=[NSMutableURLRequest requestWithURL:url];//默认为get请求
 38     //设置最大的网络等待时间
 39     request.timeoutInterval=20.0;
 40
 41     //获取主队列
 42     NSOperationQueue *queue=[NSOperationQueue mainQueue];
 43     //发起请求
 44    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
 45        //隐藏HUD
 46         [MBProgressHUD hideHUD];
 47        if (data) {//如果请求成功,拿到服务器返回的数据
 48            [self parseXMLData:data];
 49
 50 //           //解析拿到的数据(JSON方式)
 51 //           NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
 52 ////           NSArray *array=dict[@"video"];
 53 //           NSArray *array=dict[@"videos"];
 54 //
 55 //           NSMutableArray *videos=[NSMutableArray array];
 56 //           for (NSDictionary *dict in array) {
 57 //               YYviodesModel *model=[YYviodesModel viodesModelWithDict:dict];
 58 //               [videos addObject:model];
 59 //           }
 60 //           self.videos=videos;
 61
 62            //刷新表格
 63            [self.tableView reloadData];
 64
 65        }else//如果请求失败,没有拿到数据
 66        {
 67            [MBProgressHUD showError:@"网络繁忙,等稍后再试!"];
 68        }
 69    }];
 70 }
 71
 72 /**
 73  *  解析XML数据
 74  */
 75 -(void)parseXMLData:(NSData *)data
 76 {
 77     //1.创建解析器
 78     NSXMLParser *parser=[[NSXMLParser alloc]initWithData:data];
 79     //2.设置代理
 80     parser.delegate=self;
 81
 82     //3.开始解析
 83     [parser parse];
 84 }
 85
 86 #pragma mark-NSXMLParserDelegate
 87 /**
 88  *开始解析文档时调用
 89  */
 90 -(void)parserDidStartDocument:(NSXMLParser *)parser
 91 {
 92     NSLog(@"开始解析文档");
 93 }
 94 /**
 95  *结束解析文档时调用(解析完毕)
 96  */
 97 -(void)parserDidEndDocument:(NSXMLParser *)parser
 98 {
 99     NSLog(@"结束解析文档");
100 }
101 /**
102  *解析到一个元素的开头时调用
103  */
104 -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
105 {
106     NSLog(@"解析到一个元素的开头---%@",elementName);
107 }
108 /**
109  *解析到一个元素的结尾时调用
110  */
111 -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
112 {
113     NSLog(@"解析到一个元素的结尾---%@",elementName);
114 }
115 #pragma mark-数据源方法
116 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
117 {
118     return 1;
119 }
120 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
121 {
122     return self.videos.count;
123 }
124 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
125 {
126     YYCell *cell=[YYCell cellWithTableView:tableView];
127     //获取数据模型
128     cell.model=self.videos[indexPath.row];
129     return cell;
130 }
131
132 //设置cell的行高
133 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
134 {
135     return 70;
136 }
137
138 //播放视频
139 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
140 {
141     //取出数据模型
142     YYviodesModel *model=self.videos[indexPath.row];
143
144     //创建视屏播放器
145  //   MPMoviePlayerController 可以随意控制播放器的尺寸
146     //MPMoviePlayerViewController只能全屏播放
147
148         NSString *url = [NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/%@", model.url];
149     NSURL *videoUrl=[NSURL URLWithString:url];
150     YYMoviePlayerViewController *movieVc=[[YYMoviePlayerViewController alloc]initWithContentURL:videoUrl];
151     //弹出播放器
152     [self presentMoviePlayerViewControllerAnimated:movieVc];
153 //    UIApplicationDidEnterBackgroundNotification
154 }
155
156
157 @end

打印查看

(5)完成完整的功能

  1 //
  2 //  YYViewController.m
  3 //  01-文顶顶客户端
  4 //
  5 //  Created by apple on 14-6-29.
  6 //  Copyright (c) 2014年 itcase. All rights reserved.
  7 //
  8
  9 #import "YYViewController.h"
 10 #import "MBProgressHUD+MJ.h"
 11 #import "YYviodesModel.h"
 12 #import "YYCell.h"
 13 #import <MediaPlayer/MediaPlayer.h>
 14 #import "YYMoviePlayerViewController.h"
 15
 16 @interface YYViewController ()<NSXMLParserDelegate>
 17 @property(nonatomic,strong)NSMutableArray *videos;
 18
 19 @end
 20
 21 @implementation YYViewController
 22
 23 - (void)viewDidLoad
 24 {
 25     [super viewDidLoad];
 26     //去掉下划线
 27     self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;
 28
 29     [MBProgressHUD showMessage:@"正在努力加载中"];
 30
 31     //创建路径
 32
 33     NSString  *[email protected]"http://192.168.1.53:8080/MJServer/video?type=XML";
 34     NSURL *url=[NSURL URLWithString:urlStr];
 35
 36     //创建请求
 37     NSMutableURLRequest  *request=[NSMutableURLRequest requestWithURL:url];//默认为get请求
 38     //设置最大的网络等待时间
 39     request.timeoutInterval=20.0;
 40
 41     //获取主队列
 42     NSOperationQueue *queue=[NSOperationQueue mainQueue];
 43     //发起请求
 44    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
 45        //隐藏HUD
 46         [MBProgressHUD hideHUD];
 47        if (data) {//如果请求成功,拿到服务器返回的数据
 48            //解析XML数据
 49            [self parseXMLData:data];
 50        }else//如果请求失败,没有拿到数据
 51        {
 52            [MBProgressHUD showError:@"网络繁忙,等稍后再试!"];
 53        }
 54    }];
 55 }
 56
 57 /**
 58  *  解析XML数据
 59  */
 60 -(void)parseXMLData:(NSData *)data
 61 {
 62     //1.创建解析器
 63     NSXMLParser *parser=[[NSXMLParser alloc]initWithData:data];
 64     //2.设置代理
 65     parser.delegate=self;
 66
 67     //3.开始解析
 68     [parser parse];  //这个方法会卡住(同步解析,解析完毕后才会返回)
 69
 70     //4.刷新表格
 71     [self.tableView reloadData];
 72 }
 73
 74 #pragma mark-NSXMLParserDelegate
 75 /**
 76  *开始解析文档时调用
 77  */
 78 -(void)parserDidStartDocument:(NSXMLParser *)parser
 79 {
 80     NSLog(@"开始解析文档");
 81 }
 82 /**
 83  *结束解析文档时调用(解析完毕)
 84  */
 85 -(void)parserDidEndDocument:(NSXMLParser *)parser
 86 {
 87     NSLog(@"结束解析文档");
 88     //也可以在这里刷新表格
 89 //    [self.tableView reloadData];
 90 }
 91 /**
 92  *解析到一个元素的开头时调用
 93  */
 94 -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
 95 {
 96 //    NSLog(@"解析到一个元素的开头---%@",elementName);
 97     if ([@"videos" isEqualToString:elementName]) {//解析到一个videos标签
 98         self.videos=[NSMutableArray array];
 99     }else if ([@"video" isEqualToString:elementName])
100     {//解析到一个video标签,创建一个模型
101         YYviodesModel *model=[YYviodesModel viodesModelWithDict:attributeDict];
102         [self.videos addObject:model];
103     }
104 }
105 /**
106  *解析到一个元素的结尾时调用
107  */
108 -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
109 {
110     NSLog(@"解析到一个元素的结尾---%@",elementName);
111 }
112 #pragma mark-数据源方法
113 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
114 {
115     return 1;
116 }
117 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
118 {
119     return self.videos.count;
120 }
121 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
122 {
123     YYCell *cell=[YYCell cellWithTableView:tableView];
124     //获取数据模型
125     cell.model=self.videos[indexPath.row];
126     return cell;
127 }
128
129 //设置cell的行高
130 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
131 {
132     return 70;
133 }
134
135 //播放视频
136 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
137 {
138     //取出数据模型
139     YYviodesModel *model=self.videos[indexPath.row];
140
141     //创建视屏播放器
142  //   MPMoviePlayerController 可以随意控制播放器的尺寸
143     //MPMoviePlayerViewController只能全屏播放
144
145         NSString *url = [NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/%@", model.url];
146     NSURL *videoUrl=[NSURL URLWithString:url];
147     YYMoviePlayerViewController *movieVc=[[YYMoviePlayerViewController alloc]initWithContentURL:videoUrl];
148     //弹出播放器
149     [self presentMoviePlayerViewControllerAnimated:movieVc];
150 //    UIApplicationDidEnterBackgroundNotification
151 }
152
153
154 @end

注意:注意刷新代码的操作,在进行解析的时候,需要对标签进行判断。

四、基于NSXMLParser(SAX)封装解析数据的代码(包括JSON和XML的解析)

封装后的主控制器代码:

  1 //
  2 //  YYViewController.m
  3 //  01-文顶顶客户端
  4 //
  5 //  Created by apple on 14-6-29.
  6 //  Copyright (c) 2014年 itcase. All rights reserved.
  7 //
  8
  9 #import "YYViewController.h"
 10 #import "MBProgressHUD+MJ.h"
 11 #import "YYviodesModel.h"
 12 #import "YYCell.h"
 13 #import <MediaPlayer/MediaPlayer.h>
 14 #import "YYMoviePlayerViewController.h"
 15 #import "YYtool.h"
 16
 17 @interface YYViewController ()
 18 @property(nonatomic,strong)NSArray *videos;
 19 @end
 20
 21 @implementation YYViewController
 22
 23 -(NSArray *)videos
 24 {
 25     if (_videos==nil) {
 26         _videos=[NSArray array];
 27     }
 28     return _videos;
 29 }
 30 - (void)viewDidLoad
 31 {
 32     [super viewDidLoad];
 33     //去掉下划线
 34     self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;
 35
 36     [MBProgressHUD showMessage:@"正在努力加载中"];
 37
 38     //创建路径
 39
 40     NSString  *[email protected]"http://192.168.1.53:8080/MJServer/video?type=JSON";
 41     NSURL *url=[NSURL URLWithString:urlStr];
 42
 43     //创建请求
 44     NSMutableURLRequest  *request=[NSMutableURLRequest requestWithURL:url];//默认为get请求
 45     //设置最大的网络等待时间
 46     request.timeoutInterval=20.0;
 47
 48     //获取主队列
 49     NSOperationQueue *queue=[NSOperationQueue mainQueue];
 50     //发起请求
 51    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
 52        //隐藏HUD
 53         [MBProgressHUD hideHUD];
 54        if (data) {//如果请求成功,拿到服务器返回的数据
 55            //解析XML数据
 56            YYtool *tool=[[YYtool alloc]init];
 57 //           [tool parseXMLData:data];
 58            self.videos=[tool parseJSONData:data];
 59            //刷新表格
 60            [self.tableView reloadData];
 61        }else//如果请求失败,没有拿到数据
 62        {
 63            [MBProgressHUD showError:@"网络繁忙,等稍后再试!"];
 64        }
 65    }];
 66 }
 67
 68
 69 #pragma mark-数据源方法
 70 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 71 {
 72     return 1;
 73 }
 74 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 75 {
 76     return self.videos.count;
 77 }
 78 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 79 {
 80     YYCell *cell=[YYCell cellWithTableView:tableView];
 81     //获取数据模型
 82     cell.model=self.videos[indexPath.row];
 83     return cell;
 84 }
 85
 86 //设置cell的行高
 87 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 88 {
 89     return 70;
 90 }
 91
 92 //播放视频
 93 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 94 {
 95     //取出数据模型
 96     YYviodesModel *model=self.videos[indexPath.row];
 97
 98     //创建视屏播放器
 99  //   MPMoviePlayerController 可以随意控制播放器的尺寸
100     //MPMoviePlayerViewController只能全屏播放
101
102         NSString *url = [NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/%@", model.url];
103     NSURL *videoUrl=[NSURL URLWithString:url];
104     YYMoviePlayerViewController *movieVc=[[YYMoviePlayerViewController alloc]initWithContentURL:videoUrl];
105     //弹出播放器
106     [self presentMoviePlayerViewControllerAnimated:movieVc];
107 //    UIApplicationDidEnterBackgroundNotification
108 }
109 @end

封装的解析类的头文件

 1 //
 2 //  YYtool.h
 3 //  01-文顶顶客户端
 4 //
 5 //  Created by apple on 14-6-29.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface YYtool : NSObject
12 -(NSArray *)parseXMLData:(NSData *)data;
13 -(NSArray *)parseJSONData:(NSData *)data;
14
15 @end

封装的解析类的内部实现:

 1 //
 2 //  YYtool.m
 3 //  01-文顶顶客户端
 4 //
 5 //  Created by apple on 14-6-29.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8
 9 #import "YYtool.h"
10 #import "YYviodesModel.h"
11
12 @interface YYtool ()<NSXMLParserDelegate>
13 @property(nonatomic,strong)NSMutableArray *videos;
14 @end
15 @implementation YYtool
16
17 -(NSArray *)parseJSONData:(NSData *)data
18 {
19     NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
20     //           NSArray *array=dict[@"video"];
21     NSArray *array=dict[@"videos"];
22
23     NSMutableArray *videos=[NSMutableArray array];
24     for (NSDictionary *dict in array) {
25         YYviodesModel *model=[YYviodesModel viodesModelWithDict:dict];
26         [videos addObject:model];
27     }
28     return videos;
29 }
30
31 -(NSArray *)parseXMLData:(NSData *)data
32 {
33     //1.创建解析器
34     NSXMLParser *parser=[[NSXMLParser alloc]initWithData:data];
35     //2.设置代理
36     parser.delegate=self;
37
38     //3.开始解析
39     [parser parse];  //这个方法会卡住(同步解析,解析完毕后才会返回)
40
41     return self.videos;
42 }
43
44 #pragma mark-NSXMLParserDelegate
45 /**
46  *开始解析文档时调用
47  */
48 -(void)parserDidStartDocument:(NSXMLParser *)parser
49 {
50     NSLog(@"开始解析文档");
51 }
52 /**
53  *结束解析文档时调用(解析完毕)
54  */
55 -(void)parserDidEndDocument:(NSXMLParser *)parser
56 {
57     NSLog(@"结束解析文档");
58     //也可以在这里刷新表格
59     //    [self.tableView reloadData];
60 }
61 /**
62  *解析到一个元素的开头时调用
63  */
64 -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
65 {
66     if ([@"videos" isEqualToString:elementName]) {//解析到一个videos标签
67         self.videos=[NSMutableArray array];
68     }else if ([@"video" isEqualToString:elementName])
69     {//解析到一个video标签,创建一个模型
70         YYviodesModel *model=[YYviodesModel viodesModelWithDict:attributeDict];
71         [self.videos addObject:model];
72     }
73 }
74 /**
75  *解析到一个元素的结尾时调用
76  */
77 -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
78 {
79     NSLog(@"解析到一个元素的结尾---%@",elementName);
80 }
81
82 @end

五、GDataXML

1.配置

GDataXML基于libxml2库,得做以下配置

导入libxml2库

该动态库内部没有头文件,所以还需要设置libxml2的头文件搜索路径(为了能找到libxml2库的所有头文件)

Head Search Path中加入/usr/include/libxml2

该库是2008年的,未使用ARC进行内存管理,所以还需要告诉编译器,对它进行非ARC处理。

设置链接参数(自动链接libxml2库)

Other Linker Flags中加入-lxml2

2.GDataXML使用

GDataXML中常用的类

GDataXMLDocument:代表整个XML文档

GDataXMLElement

代表文档中的每个元素

使用attributeForName:方法可以获得属性值

代码示例:

  1 //
  2 //  YYViewController.m
  3 //  01-文顶顶客户端
  4 //
  5 //  Created by apple on 14-6-29.
  6 //  Copyright (c) 2014年 itcase. All rights reserved.
  7 //
  8
  9 #import "YYViewController.h"
 10 #import "MBProgressHUD+MJ.h"
 11 #import "YYviodesModel.h"
 12 #import "YYCell.h"
 13 #import <MediaPlayer/MediaPlayer.h>
 14 #import "YYMoviePlayerViewController.h"
 15 #import "GDataXMLNode.h"
 16
 17 @interface YYViewController ()<NSXMLParserDelegate>
 18 @property(nonatomic,strong)NSMutableArray *videos;
 19
 20 @end
 21
 22 @implementation YYViewController
 23
 24 - (void)viewDidLoad
 25 {
 26     [super viewDidLoad];
 27     //去掉下划线
 28     self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;
 29
 30     [MBProgressHUD showMessage:@"正在努力加载中"];
 31
 32     //创建路径
 33
 34     NSString  *[email protected]"http://192.168.1.53:8080/MJServer/video?type=XML";
 35     NSURL *url=[NSURL URLWithString:urlStr];
 36
 37     //创建请求
 38     NSMutableURLRequest  *request=[NSMutableURLRequest requestWithURL:url];//默认为get请求
 39     //设置最大的网络等待时间
 40     request.timeoutInterval=20.0;
 41
 42     //获取主队列
 43     NSOperationQueue *queue=[NSOperationQueue mainQueue];
 44     //发起请求
 45    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
 46        //隐藏HUD
 47         [MBProgressHUD hideHUD];
 48        if (data) {//如果请求成功,拿到服务器返回的数据
 49            //解析XML数据
 50            [self parseXMLData:data];
 51        }else//如果请求失败,没有拿到数据
 52        {
 53            [MBProgressHUD showError:@"网络繁忙,等稍后再试!"];
 54        }
 55    }];
 56 }
 57
 58 /**
 59  *  DOM方式解析XML数据
 60  */
 61 -(void)parseXMLData:(NSData *)data
 62 {
 63     //1.加载文档
 64     GDataXMLDocument *doc=[[GDataXMLDocument alloc]initWithData:data options:0 error:nil];
 65     //2.获得根元素
 66     GDataXMLElement *root=doc.rootElement;
 67     //3.获得所有的video元素
 68     NSArray *elements=[root elementsForName:@"video"];
 69     //4.将GDataXMLElement对象转换成模型
 70     NSMutableArray *videos=[NSMutableArray array];
 71     for (GDataXMLElement *ele in elements) {
 72         YYviodesModel *model=[[YYviodesModel alloc]init];
 73         model.ID=[ele attributeForName:@"id"].stringValue.intValue;
 74         model.length=[ele attributeForName:@"length"].stringValue.intValue;
 75         model.name=[ele attributeForName:@"name"].stringValue;
 76         model.image=[ele attributeForName:@"image"].stringValue;
 77         model.url=[ele attributeForName:@"url"].stringValue;
 78         [videos addObject:model];
 79     }
 80     self.videos=videos;
 81     //4.刷新表格
 82     [self.tableView reloadData];
 83 }
 84
 85 #pragma mark-数据源方法
 86 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 87 {
 88     return 1;
 89 }
 90 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 91 {
 92     return self.videos.count;
 93 }
 94 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 95 {
 96     YYCell *cell=[YYCell cellWithTableView:tableView];
 97     //获取数据模型
 98     cell.model=self.videos[indexPath.row];
 99     return cell;
100 }
101
102 //设置cell的行高
103 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
104 {
105     return 70;
106 }
107
108 //播放视频
109 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
110 {
111     //取出数据模型
112     YYviodesModel *model=self.videos[indexPath.row];
113
114     //创建视屏播放器
115  //   MPMoviePlayerController 可以随意控制播放器的尺寸
116     //MPMoviePlayerViewController只能全屏播放
117
118         NSString *url = [NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/%@", model.url];
119     NSURL *videoUrl=[NSURL URLWithString:url];
120     YYMoviePlayerViewController *movieVc=[[YYMoviePlayerViewController alloc]initWithContentURL:videoUrl];
121     //弹出播放器
122     [self presentMoviePlayerViewControllerAnimated:movieVc];
123 //    UIApplicationDidEnterBackgroundNotification
124 }
125 @end

执行:

标签: IOS开发网络篇

绿色通道: 好文要顶 关注我 收藏该文与我联系 

IOS学习之十六:网络数据的XML解析

网络应用中的数据解析,因为最近的应用,无论是Android的和ios平台的,一直用也是建议用的都是Json解析,

xml解析都有点被遗忘了。

然后最近自己在做着玩一个ios的小应用,涉及网络数据的抓取,一些网站可能都提供了自己api平台,这些一般都是支持

我们对于数据协议格式的设定的。但是后来我在找寻到一些Rss资源时,发现返回的数据都是xml格式的,

因此,那就只好用xml解析了。

XML解析其实这个概念出现了算够久了,以前javaweb什么到处都在用。这边我们主要大致介绍下,然后在在ios编程如何使用。

XML解析一般分两种模式SAX和DOM,事件和文档。具体解析google去吧,有详细。不过看了下面的两个例子,一般就了解了。

一:XML解析之SAX解析,以及对NSXMLParser的应用。

sax解析说白了,就是一个事物模型解析,从头开始读取文档然后根据读取到的头标签标签时要怎么处理,读完头标签后,理论上是读取标签值了,

然后读取后遇到结束标签等

简单举个例子

<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"> 头标签,里面的xmlns,可以看成是属性
<channel>
<title>呵呵呵呵</title>结束标签,中间的“呵呵呵呵”是首尾标签标签值空间

.......

好了,那么在ios开发中如何使用。

SDK本身是提供了NSXMLParser解析器。

[cpp] view plaincopy

  1. -(BOOL)parser:(NSString*)string
  2. {
  3. //系统自带的
  4. NSXMLParser *par = [[[NSXMLParser alloc] initWithData:[string dataUsingEncoding:NSUTF8StringEncoding]]autorelease];
  5. [par setDelegate:self];//设置NSXMLParser对象的解析方法代理
  6. return [par parse];//调用代理解析NSXMLParser对象,看解析是否成功   }
  7. }
  8. #pragma mark xmlparser
  9. //step 1 :准备解析
  10. - (void)parserDidStartDocument:(NSXMLParser *)parser
  11. {
  12. //    NSLog(@"%@",NSStringFromSelector(_cmd) );
  13. }
  14. //step 2:准备解析节点
  15. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
  16. {
  17. //    NSLog(@"%@",NSStringFromSelector(_cmd) );
  18. }
  19. //step 3:获取首尾节点间内容
  20. - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
  21. {
  22. NSLog(@"%@",NSStringFromSelector(_cmd) );
  23. }
  24. //step 4 :解析完当前节点
  25. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
  26. {
  27. NSLog(@"%@",NSStringFromSelector(_cmd) );
  28. }
  29. //step 5;解析结束
  30. - (void)parserDidEndDocument:(NSXMLParser *)parser
  31. {
  32. //    NSLog(@"%@",NSStringFromSelector(_cmd) );
  33. }
  34. //获取cdata块数据
  35. - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
  36. {
  37. //    NSLog(@"%@",NSStringFromSelector(_cmd) );
  38. }

1.初始化解析器,传入你要解析的数据。

2.parse,启动解析,返回一个是否解析成功Bool值。

3.基本你要处理的就在下面实现的1-5个代理方法了。

其实代理方法和详细,就是一个事物进行流程:

step1是准备解析,然后没意外就是执行到了——>

step2读取到第一个头节点了,然后如果内部有属性值,你可以获取出来,读完头节点,我们会进去值域——》

step3对于简单的节点,可能直接就是一个string值了,但是看例子我们会知道,很多情况下,该节点的值域包含的于是一个节点——》

这步其实分两种,如果是值,那么就是执行step4,获取值的字窜,如果是子节点呢,我们一看就知道,它又是进行了step2,

即读取到头标签了,其实你是很人读一片文章流程一样,只不过我们脑中有个印象<xxx>是头标签了,我们要做什么,独到 头标签的最后一个符号">"

下面进去值域,独到了字窜的话就调用了foundCharacters:(NSString *)string,如果又读到<xxx>这样的,那就又是头标签了。——》

step5就是读到开始尾标签符号了。

最后一个方法

foundCDATA:(NSData *)CDATABlock,其实也是一个格式

[html] view plaincopy

  1. <content:encoded>
  2. <![CDATA[
  3. <img src="http://img1.douban.com/mpic/s10489201.jpg" style="float:right;margin-left:16px"/><a href="http://www.douban.com/people/maldini/">减卐肥™</a>评论: <a href="http://movie.douban.com/subject/6799191//">搜索</a><br/> <br/>评价: 力荐<br/><br/>
  4. ]]>
  5. </content:encoded>

好了,方法和流程大致了解了,拿一个我最近遇到的例子,好多时候,我们会遇到这样读取一组类似于json中数组形式的数据

[html] view plaincopy

  1. <channel>
  2. <title>我是标题</title>
  3. <link>http://write.blog.csdn.net/postedit</link>
  4. <description>...</description>
  5. <language>zh-cn</language>
  6. <pubDate>Fri, 03 Aug 2012 06:20:31 GMT</pubDate>
  7. <item>...</item>
  8. <item>...</item>
  9. <item>...</item>
  10. <item>...</item>
  11. <item>...</item>
  12. <item>...</item>
  13. <item>...</item>
  14. <item>...</item>
  15. <item>...</item>
  16. <item>...</item>
  17. <item>...</item>
  18. <item>...</item>
  19. <item>...</item>
  20. <item>...</item>
  21. <item>...</item>
  22. <item>...</item>
  23. <item>...</item>
  24. <item>...</item>
  25. <item>...</item>
  26. <item>...</item>
  27. </channel>

一般来说,我们要的数据其实都是这20个item,对吧,每个item下都是相同的3个标签,title,author,time。形式上

其实一种数组形式

那么要怎么解析呢

1,首先我们可能先申明一个array数组容器用来存放这个20个对象,然后每个item对象中又有3个元素,那么我们可以

考虑用一个字典数据结构来表示每个item。

2.需要至少申请两个空间来作为类似于“哨兵”存储当前执行到的节点名,以及节点的值。

3.然后每次执行到读取到item时,初始化我们上面说道的一个字典数据结构。

4.在foundCharacters:方法中一直保存当前最新的值(当然,这里面其实会有个小瑕疵,下面会说到)。

5.在标签结束的方法,我们把标签名和值已键值对存入上面初始化的字典容器中。

[cpp] view plaincopy

  1. #pragma mark xmlparser
  2. //step 1 :准备解析
  3. - (void)parserDidStartDocument:(NSXMLParser *)parser
  4. {
  5. //    NSLog(@"%@",NSStringFromSelector(_cmd) );
  6. parserObjects = [[NSMutableArray alloc]init];
  7. }
  8. //step 2:准备解析节点
  9. - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
  10. {
  11. //    NSLog(@"%@",NSStringFromSelector(_cmd) );
  12. self.currentText = [[NSMutableString alloc]init];
  13. [currentText release];
  14. if ([elementName isEqualToString:@"item"]) {
  15. NSMutableDictionary *newNode = [[ NSMutableDictionary alloc ] initWithCapacity : 0 ];
  16. twitterDic = newNode;
  17. [parserObjects addObject :newNode];
  18. [newNode release];
  19. }
  20. else if(twitterDic) {
  21. NSMutableString *string = [[ NSMutableString alloc ] initWithCapacity : 0 ];
  22. [twitterDic setObject :string forKey :elementName];
  23. [string release ];
  24. currentElementName = elementName;
  25. }
  26. }
  27. //step 3:获取首尾节点间内容
  28. - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
  29. {
  30. NSLog(@"%@",NSStringFromSelector(_cmd) );
  31. [currentText appendString:string];
  32. }
  33. //step 4 :解析完当前节点
  34. - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
  35. {
  36. if ([elementName isEqualToString:@"item"]) {
  37. twitterDic = nil;
  38. }else
  39. if ([elementName isEqualToString:currentElementName]) {
  40. if ([elementName isEqualToString:@"description"]
  41. ||[elementName isEqualToString:@"content:encoded"]) {
  42. [twitterDic setObject:Cdata forKey:currentElementName];
  43. }else {
  44. [twitterDic setObject:currentText forKey:currentElementName];
  45. }
  46. }
  47. }
  48. //step 5;解析结束
  49. - (void)parserDidEndDocument:(NSXMLParser *)parser
  50. {
  51. }
  52. //获取cdata块数据
  53. - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
  54. {
  55. Cdata =[[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
  56. }

对于上面代码说几点

1.我次奥,有几处内存泄露~~~

2.在获取值为什么不直接currentString = string

这是实践发现的问题

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
 注意这个代理方法的注释
   // This returns the string of the characters encountered thus far. You may not necessarily get the longest character run. The parser reserves the right to hand these to the delegate as potentially many calls in a row to -parser:foundCharacters:
下面是google翻译。
这将返回迄今为止遇到的字符的字符串。你不一定得到的最长字符运行。解析器有权交行解析器可能多次呼吁这些委托:foundCharacters:
这个说明,在获取一个标签首尾间的字符数据时,这个方法可能被调用多次。
举个我碰到的最简单的列子
<copyright>&copy; 2012, douban.com.</copyright>
我在解析这个节点时,上面方法就调用了两次,
第一次只返回&,紧接着第二次返回copy; 2012, douban.com.
因此你如果要获取完整的的,应该用string的append方法来获取完整的一条记录。

3.解析速度的优化,比如我们只需要item中数据,那么在独到非这个域内的标签,我们的哨兵不需要追中的保存key和value值。

因此我做了一处字典的释放和判断,在found中想减少string的赋值,当然你也可以在全局添加个标记位来控制

但是总体来说,这种优化基本微乎其微,而且造成我内存莫名其妙的泄露了~~

4.以上思路可以参考,代码因为写的太冲忙,有写内存上的问题,就不要参考了,呵呵,过几天我子在改改,

可以做一个很好rss解析的模板。

二:Dom文档解析模型,TBXML第三方包应用。

dom解析模型就像一个树结构,节点,子节点,兄弟节点等等。

这个其实最后被我抛弃了,这个解析器太简化了,太简洁的东西导致控制的入口点太少,就比如一个一键优化的软件的概念是一样的,

一键清楚缓存,优化配置,文件归类等等。人为控制就少了,导致我解析上面那个模型时,只知道遍历存储~。但是这个解析期对部分要求不高的xml解析其实挺好分,真的很简洁。

[cpp] view plaincopy

  1. //- (void)recurrence:(TBXMLElement *)element {
  2. //
  3. //    NSString *eleName = [TBXML elementName:element];
  4. //    NSString *eleText = [TBXML textForElement:element];
  5. //    if ([eleName isEqualToString:@"item"]) {
  6. //        self recurrence:element
  7. //    }
  8. //
  9. //
  10. //
  11. //
  12. //    do {
  13. //
  14. //        NSString *eleName = [TBXML elementName:element];
  15. //        NSString *eleText = [TBXML textForElement:element];
  16. //
  17. //        //递归处理子树
  18. //        if (element->firstChild) {
  19. //            NSLog(@"<%@>:",eleName);// Display the name of the element
  20. //
  21. //            [self recurrence:element->firstChild];
  22. //        }else {
  23. //            NSLog(@"<%@>:%@",eleName,eleText);// Display the name of the element
  24. //
  25. //            TBXMLElement *parent = element->parentElement;
  26. //            if ([[TBXML elementName:parent] isEqualToString:@"item"]) {
  27. //                NLRssInfo *info = [[[NLRssInfo alloc]init] autorelease];
  28. //
  29. //                if ([eleName isEqualToString:@"title"]) {
  30. //                    info.title = eleText;
  31. //                }
  32. //
  33. //
  34. //                [dataArr addObject:info];
  35. //            }
  36. //
  37. //        }
  38. //
  39. //
  40. //        //迭代处理兄弟树
  41. //    } while ((element = element->nextSibling));
  42. //}

递归遍历,常规的树操作,具体内容可以网上搜搜,很多。

并且开源库的好处就是有源代码,也就3个类,6个文件,有兴趣可以研究研究,貌似大部分代码是用C写的。

时间: 2024-12-24 22:49:58

iOS开发网络篇—XML数据的解析的相关文章

iOS开发网络篇—JSON数据的解析

iOS开发网络篇—JSON数据的解析 iOS开发网络篇—JSON介绍 一.什么是JSON JSON是一种轻量级的数据格式,一般用于数据交互 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外) JSON的格式很像OC中的字典和数组 {"name" : "jack", "age" : 10} {"names" : ["jack", "rose", "jim

IOS开发网络篇—XML介绍

iOS开发网络篇—XML介绍 一.XML简单介绍 XML:全称是Extensible Markup Language,译作“可扩展标记语言” 跟JSON一样,也是常用的一种用于交互的数据格式,一般也叫XML文档(XML Document) XML举例 <videos> <video name="小黄人 第01部" length="30" /> <video name="小黄人 第02部" length="1

IOS开发网络篇-JSON文件的解析

一.什么是JSON数据 1.JSON的简单介绍 JSON:是一种轻量级的传输数据的格式,用于数据的交互 JSON是javascript语言的一个子集.javascript是个脚本语言(不需要编译),用来给HTML增加动态功能. javascript和java没有半毛钱的关系! 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外). 2.JSON的语法规则 <1> 数据以键值的方式保存; 键(key)必须用双引号("key"),与键值之间以':'分隔;

iOS开发网络篇—数据缓存

iOS开发网络篇—数据缓存 一.关于同一个URL的多次请求 有时候,对同一个URL请求多次,返回的数据可能都是一样的,比如服务器上的某张图片,无论下载多少次,返回的数据都是一样的. 上面的情况会造成以下问题 (1)用户流量的浪费 (2)程序响应速度不够快 解决上面的问题,一般考虑对数据进行缓存. 二.缓存 为了提高程序的响应速度,可以考虑使用缓存(内存缓存\硬盘缓存) 第一次请求数据时,内存缓存中没有数据,硬盘缓存中没有数据. 缓存数据的过程 当服务器返回数据时,需要做以下步骤 (1)使用服务器

iOS开发网络篇—发送json数据给服务器以及多值参数

iOS开发网络篇—发送json数据给服务器以及多值参数 一.发送JSON数据给服务器 发送JSON数据给服务器的步骤: (1)一定要使用POST请求 (2)设置请求头 (3)设置JSON数据为请求体 代码示例: 1 #import "YYViewController.h" 2 3 @interface YYViewController () 4 5 @end 6 7 @implementation YYViewController 8 9 - (void)viewDidLoad 10

iOS开发网络篇—发送GET和POST请求(使用NSURLSession)

iOS开发网络篇—发送GET和POST请求(使用NSURLSession) 说明: 1)该文主要介绍如何使用NSURLSession来发送GET请求和POST请求 2)本文将不再讲解NSURLConnection的使用,如有需要了解NSURLConnection如何发送请求. 详细信息,请参考:http://www.cnblogs.com/wendingding/p/3813706.html 3)本文示例代码发送的请求均为http请求,已经对info.plist文件进行配置. 如何配置,请参考:

iOS开发网络篇—文件的上传

iOS开发网络篇—文件的上传 说明:文件上传使用的时POST请求,通常把要上传的数据保存在请求体中.本文介绍如何不借助第三方框架实现iOS开发中得文件上传. 由于过程较为复杂,因此本文只贴出部分关键代码. 主控制器的关键代码: YYViewController.m 1 #import "YYViewController.h" 2 3 #define YYEncode(str) [str dataUsingEncoding:NSUTF8StringEncoding] 4 5 @inter

iOS开发网络篇—NSURLConnection基本使用

iOS开发网络篇—NSURLConnection基本使用 一.NSURLConnection的常用类 (1)NSURL:请求地址 (2)NSURLRequest:封装一个请求,保存发给服务器的全部数据,包括一个NSURL对象,请求方法.请求头.请求体.... (3)NSMutableURLRequest:NSURLRequest的子类 (4)NSURLConnection:负责发送请求,建立客户端和服务器的连接.发送NSURLRequest的数据给服务器,并收集来自服务器的响应数据 二.NSUR

iOS开发网络篇—简单介绍ASI框架的使用

iOS开发网络篇—简单介绍ASI框架的使用 说明:本文主要介绍网络编程中常用框架ASI的简单使用. 一.ASI简单介绍 ASI:全称是ASIHTTPRequest,外号“HTTP终结者”,功能十分强大. ASI的实现基于底层的CFNetwork框架,因此运行效率很高.可惜作者早已停止更新,有一些潜在的BUG无人去解决 ASI的github地址 https://github.com/pokeb/asi-http-request ASI的使用参考 http://www.cnblogs.com/dot