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];
}