网络篇 - 05.网络数据解析(XML)

1.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>

2.XML语法概述

  • 一个常见的XML文档一般由以下部分组成
    • 文档声明
    • 元素(Element)
    • 属性(Attribute)
  • XML语法 – 文档声明
    • 在XML文档的最前面,必须编写一个文档声明,用来声明XML文档的类型
//最简单的声明,声明版本信息
<?xml version="1.0" ?>
//用encoding属性说明文档的字符编码信息
<?xml version="1.0" encoding="UTF-8" ?>
  • XML语法 – 元素(Element)
    • 一个元素包括了开始标签和结束标签
      • 拥有内容的元素:小黄人
      • 没有内容的元素:
      • 没有内容的元素简写:
    • 一个元素可以嵌套若干个子元素(不能出现交叉嵌套)
    • 规范的XML文档最多只有1个根元素,其他元素都是根元素的子孙元素
<videos>
    <video>
        <name>小黄人 第01部</name>
          <length>30</length>
    </video>
</videos>
  • XML语法 –元素的注意
    • XML中的所有空格和换行,都会当做具体内容处理
    • 下面两个元素的内容是不一样的
      • 第1个<video>小黄人</video>
      • 第2个
        <video>
        小黄人
        </video>
  • XML语法 – 属性(Attribute)
    • 一个元素可以拥有多个属性
    • video元素拥有name和length两个属性
    • 属性值必须用 双引号”” 或者 单引号” 括住
<video name="小黄人 第01部" length="30" />
//实际上,属性表示的信息也可以用子元素来表示,比如
<video>
    <name>小黄人 第01部</name>
        <length>30</length>
</video>

3.XML解析

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

    • 提取name元素里面的内容
      <name>小黄人 第01部</name>
    • 提取video元素中name和length属性的值
      <video name="小黄人 第01部" length="30" />
  • XML的解析方式有2种

    • DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
    • SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件
  • 在iOS中,解析XML的手段有很多

    • 苹果原生NSXMLParser:SAX方式解析,使用简单
    • 第三方框架libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
    • GDataXML:DOM方式解析,由Google开发,基于libxml2的封装
  • XML解析方式选择

    • 大文件:NSXMLParser
    • 小文件:GDataXML、NSXMLParser

4.SAX解析-NSXMLParser

  • NSXMLParser
    • 1.传入XML数据,创建解析器
    • 2.设置代理,监听解析过程
    • 3.开始解析
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
  • NSXMLParser采取的是SAX方式解析,特点是事件驱动,下面情况都会通知代理
    • 当扫描到文档(Document)的开始与结束
    • 当扫描到元素(Element)的开始与结束
  • 常见代理方法(NSXMLParserDelegate)
//当扫描到文档的开始时调用(开始解析)
- (void)parserDidStartDocument:(NSXMLParser *)parser

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

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

// 当扫描到元素的结束时调用
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
  • 解析实例
    这里写图片描述
    这里写图片描述
#import "ViewController.h"
#import "NSString+SandboxPath.h"
#import <SDWebImage/UIImageView+WebCache.h>
#import <MediaPlayer/MPMoviePlayerViewController.h>

@interface ViewController ()<NSXMLParserDelegate>
@property (nonatomic, strong) NSMutableArray *videos;// 视频信息
@end

@implementation ViewController

#pragma mark - 懒加载
-(NSMutableArray *)videos{
    if (!_videos) {
        _videos = [NSMutableArray array];
    }
    return _videos;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.rowHeight = 150;

    // 1.获取网络数据
    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 *response, NSData *data, NSError *connectionError) {
        // 2.解析XML数据
        // 2.1创建解析器
        NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
        // 2.2设置代理
        parser.delegate = self;
        // 2.3开始解析
        [parser parse];
    }];
}

#pragma mark - NSXMLParserDelegate
// 只要开始解析XML文档就会调用
-(void)parserDidStartDocument:(NSXMLParser *)parser{
    NSLog(@"%s",__func__);
}
// 只要解析完毕XML文档就会调用
-(void)parserDidEndDocument:(NSXMLParser *)parser{
    NSLog(@"%s",__func__);
    // 刷新UI
    [self.tableView reloadData];
}

// 当扫描到元素的开始时调用
/* 参数解释:
 elementName:元素名称
 attributeDict:元素中的属性
 namespaceURI和qualifiedName是XML DOM的属性,基本用不上
 */
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
    NSLog(@"%s",__func__);
    if ([elementName isEqualToString:@"videos"]) return;
    [self.videos addObject:attributeDict];
    NSLog(@"%@",attributeDict);
}

// 当扫描到元素的结束时调用
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
        NSLog(@"%s",__func__);
}

// 解析发生错误时调用
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
    NSLog(@"%s",__func__);
}

#pragma mark - UITableViewDataSource
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return self.videos.count;   
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    //    1.创建cell
    static NSString *identifier = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    //    2.设置cell的数据
    NSDictionary *dict = self.videos[indexPath.row];
    cell.textLabel.text = dict[@"name"];
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%@",dict[@"length"]];
    NSString *urlStr =[NSString stringWithFormat:@"http://120.25.226.186:32812/%@", dict[@"image"]];
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    [cell.imageView sd_setImageWithURL:url placeholderImage:nil];

    //    3.返回cell
    return cell;
}

#pragma mark - UITableViewDelegate
// 选中某一行后播放视频
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    // 获取视频URL
    NSDictionary *dict = self.videos[indexPath.row];
    NSString *urlStr =[NSString stringWithFormat:@"http://120.25.226.186:32812/%@", dict[@"url"]];
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    // 加载视频播放控制器
    MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
    // 显示控制器
    [self presentViewController:vc animated:YES completion:nil];
}

5.DOM解析-NSXMLParser

  • 由于GDataXML基于libxml2库的,而且是MRC的,所以需要在使用GDataXML的项目中做以下配置
  • 导入libxml2库
    这里写图片描述
  • 设置libxml2的头文件搜索路径
    这里写图片描述
  • 设置链接参数(自动链接libxml2库)
    这里写图片描述
  • 由于GDataXML是非ARC的,因此得设置编译参数
    这里写图片描述
  • DOM解析实例(以此前SAX解析的例子)
    // 1.获取网络数据
    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 *response, NSData *data, NSError *connectionError) {
        // 2.解析XML数据(DOM)
        // 2.1创建解析器
        GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:kNilOptions error:nil];
        // 2.2 获取根元素
        GDataXMLElement *rootElement = [doc rootElement];
        // 2.3从根元素中获取所以子元素
        NSArray *elementArr = [rootElement elementsForName:@"video"];
        // 2.4遍历数组将数组中的根元素转换为字典(模型)
        for (GDataXMLElement *element in elementArr) {
            NSMutableDictionary *video = [NSMutableDictionary dictionary];
            video[@"id"] = @([element attributeForName:@"id"].stringValue.integerValue);
            video[@"image"] = [element attributeForName:@"image"].stringValue;
            video[@"url"] = [element attributeForName:@"url"].stringValue;
            video[@"name"] = [element attributeForName:@"name"].stringValue;
            video[@"length"] = @([element attributeForName:@"length"].stringValue.integerValue);
            [self.videos addObject:video];
        }
        // 2.5 刷新数据
        [self.tableView reloadData];
    }];
}

6.XML和JSON对比

  • 同一份数据,既可以用JSON来表示,也可以用XML来表示
  • 相比之下,JSON的体积小于XML,所以服务器返回给移动端的数据格式以JSON居多
  • 目前市面上80%以上的网络数据都是JSON格式的,但是我们最终还是要看公司后台返回的是哪种格式的数据,根据接口文件解析对应数据即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值