XML 数据解析方式

XML 全称是 Extensible Markup Language,译作“可扩展标记语言”, 是常用的一种用于交互的数据格式, 一般也叫XML文档(XML Document).

XML 举例:

<videos>
    <video name="X战警 第一战" length="120" />
    <video name="X战警 逆转未来" length="150" />
    <video name="X战警 天启" length="118" />
</videos>

XML语法

一个常见的XML文档一般由以下部分组成
(1) 文档声明
(2) 元素(Element)
(3) 属性(Attribute)

XML语法 – 文档声明

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

<?xml version="1.0" ?>

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

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

XML语法 – 元素(Element)

一个元素包括了开始标签和结束标签
拥有元素内容:<video>X战警</video>
没有元素内容:<video></video>(简写:<video/> )
一个元素可以嵌套若干个子元素(不能出现交叉嵌套)

<videos>
    <video>
        <name>X战警 第一战</name>
             <length>120</length>
    </video>
</videos>

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

XML语法 –元素的注意

XML中的所有空格和换行,都会当做具体内容处理
下面两个元素的内容是不一样的
第1个

<video>X战警</video>

第2个

<video>
    X战警
</video>

XML语法 – 属性(Attribute)

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

video元素拥有name和length两个属性
属性值必须用 双引号”” 或者 单引号” 括住
实际上,属性表示的信息也可以用子元素来表示,比如

<video>
    <name>X战警 第一战</name>
        <length>120</length>
</video>

XML解析

(1) DOM:一次性将整个 XML 文档加载进内存,比较适合解析小文件
(2) SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件

iOS中的XML解析

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

XML解析方式的选择建议
大文件:NSXMLParser、libxml2
小文件:GDataXML

NSXMLParser
使用步骤

// 传入XML数据,创建解析器
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
// 设置代理,监听解析过程
parser.delegate = self;
// 开始解析
[parser parse];

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

//当扫描到文档(Document)的开始与结束
//当扫描到元素(Element)的开始与结束
//当扫描到文档的开始时调用(开始解析)
- (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

XML示例:

{"videos":[{"id":1,"image":"resources/images/01.png","length":10,"name":"第01部","url":"resources/videos/01.mp4"},{"id":2,"image":"resources/images/02.png","length":12,"name":"第02部","url":"resources/videos/02.mp4"},{"id":3,"image":"resources/images/03.png","length":14,"name":"第03部","url":"resources/videos/03.mp4"},{"id":4,"image":"resources/images/04.png","length":16,"name":"第04部","url":"resources/videos/04.mp4"},{"id":5,"image":"resources/images/05.png","length":18,"name":"第05部","url":"resources/videos/05.mp4"},{"id":6,"image":"resources/images/06.png","length":20,"name":"第06部","url":"resources/videos/06.mp4"},{"id":7,"image":"resources/images/07.png","length":22,"name":"第07部","url":"resources/videos/07.mp4"},{"id":8,"image":"resources/images/08.png","length":24,"name":"第08部","url":"resources/videos/08.mp4"},{"id":9,"image":"resources/images/09.png","length":26,"name":"第09部","url":"resources/videos/09.mp4"},{"id":10,"image":"resources/images/10.png","length":28,"name":"第10部","url":"resources/videos/10.mp4"},{"id":11,"image":"resources/images/11.png","length":30,"name":"小黄人 第11部","url":"resources/videos/11.mp4"},{"id":12,"image":"resources/images/12.png","length":32,"name":"第12部","url":"resources/videos/12.mp4"},{"id":13,"image":"resources/images/13.png","length":34,"name":"第13部","url":"resources/videos/13.mp4"},{"id":14,"image":"resources/images/14.png","length":36,"name":"第14部","url":"resources/videos/14.mp4"},{"id":15,"image":"resources/images/15.png","length":38,"name":"第15部","url":"resources/videos/15.mp4"},{"id":16,"image":"resources/images/16.png","length":40,"name":"第16部","url":"resources/videos/16.mp4"}]}

//模型为:
//.h文件
#import <Foundation/Foundation.h>
@interface XMLModel : NSObject

@property (nonatomic, copy) NSString *ID;
@property (nonatomic, copy) NSString *image;
@property (nonatomic, assign) int length;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *url;

- (instancetype)initWithDic:(NSDictionary *)dict;
+ (instancetype)xmlModelInitDic:(NSDictionary *)dict;
@end

//.m文件
#import "XMLModel.h"
@implementation XMLModel

- (instancetype)initWithDic:(NSDictionary *)dict{
    self = [super init];
    if (self) {
        //KVC
        [self setValue:dict[@"id"] forKeyPath:@"ID"];
        [self setValue:dict[@"image"] forKeyPath:@"image"];
        [self setValue:dict[@"name"] forKeyPath:@"name"];
        [self setValue:dict[@"url"] forKeyPath:@"url"];
        [self setValue:dict[@"length"] forKeyPath:@"length"];
        //[self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

+ (instancetype)xmlModelInitDic:(NSDictionary *)dict{
    return [[self alloc] initWithDic:dict];
}
@end

XML 解析代码示例:

/**
 *  SAX 方式解析 XML
 */
- (void)saxXML{
    NSURL *url = [NSURL URLWithString:@"http://localhost:8080/Server/video?type=XML"];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (data == nil || error ) {
            NSLog(@"网络错误--%@", error);
        }
        //SAX 方式解析 XML
        NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
        //成为自己的代理
        parser.delegate = self;
        //开始解析
        [parser parse]; 
    }];
    [task resume];
}

#pragma mark - NSXMLParserDelegate 代理方法
/** 解析到开头调用 */
- (void)parserDidStartDocument:(NSXMLParser *)parser{
    NSLog(@"parserDidStartDocument");
}
/**
 *  解析到第一个元素调用
 *
 *  @param elementName   元素名称
 *  @param attributeDict 属性字典
 */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
    //NSLog(@"didStartElement -- %@", attributeDict);

    if ([@"videos" isEqualToString:elementName]) return;
    //模型数据
    XMLModel *xml = [XMLModel xmlModelInitDic:attributeDict];
}

/** 解析到最后一个元素调用 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    NSLog(@"didEndElement");
}

/** 解析到结尾调用 */
- (void)parserDidEndDocument:(NSXMLParser *)parser{
    NSLog(@"parserDidEndDocument");
}

GDataXML配置

GDataXML基于libxml2库,得做以下配置
(1) 导入libxml2库
(2) 设置libxml2的头文件搜索路径(为了能找到libxml2库的所有头文件)
在PROJECT -> build setting -> ALL -> Head Search Path中加入/usr/include/libxml2
(3) 设置链接参数(自动链接libxml2库)
在Other Linker Flags中加入-lxml2
(4) 在 Build Phases 中的GDataXMLNode.m加入 -fno-objc-arc

示例代码

/**
 *  DOM 方式解析 XML
 */
- (void)domXML{
    NSURL *url = [NSURL URLWithString:@"http://localhost:8080/Server/video?type=XML"];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (data == nil || error ) {
            NSLog(@"网络错误--%@", error);
        }
        //DOM方式解析XML
        GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
        //获取根元素
        GDataXMLElement *root = doc.rootElement;

        //获取根元素里面所有的的video元素
        NSArray *array = [root elementsForName:@"video"];
        //遍历void元素
        for (GDataXMLElement *videoElement in array){
    //模型数据
            XMLModel *xmlModel = [[XMLModel alloc] init];
            xmlModel.ID = [videoElement attributeForName:@"id"].stringValue;
            xmlModel.name = [videoElement attributeForName:@"name"].stringValue;
            xmlModel.url = [videoElement attributeForName:@"url"].stringValue;
            xmlModel.length = [videoElement attributeForName:@"length"].stringValue.intValue;
            xmlModel.image = [videoElement attributeForName:@"image"].stringValue;
    }];
    [task resume];
}
posted @ 2016-07-05 19:30  zsper  阅读(235)  评论(0编辑  收藏  举报