OC学习04:JSON和XML数据解析

张建 lol

前言

  • iOS 开发中,常见的 数据传输 格式有两种:JSON和XML

  • 服务器返回客户端的数据,一般都是 JSON格式或XML格式(文件下载除外)

  • JSON 由于 体积小、传输快速 等优点,逐渐成为了 主流的数据传输格式

JSON

iOS 中,常见解析方案有以下几种:

  • 性能最好的是使用 苹果原生的框架NSJSONSerialization

  • 第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越来越差)

  • JSON格式很像OC中的数组和字典,key必须用双引号

1
{"name":"张三","age":22}、[{"name":"张三","age":22},{"name":"李四","age":22}]

JSON格式

JSON 转 OC

一般从网络请求返回的数据格式是JSON

  • 第一个参数:要解析的JSON数据,是NSData类型也就是二进制数据
  • 第二个参数:解析JSON的可选配置参数
    • NSJSONReadingMutableContainers 解析出来的字典和数组是可变的
    • NSJSONReadingFragmentsAllowed 解析出来的对象中的字符串是可变的
    • NSJSONReadingMutableLeaves 被解析的数据如果既不是字典也不是数组,那么就使用这个
  • 第三个参数:错误信息
1
NSDictionary * dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];

OC 转 JSON

  • 第一个参数:要转换成JSON数据的OC对象,这里是一个字典
  • 第二个参数:NSJSONWritingPrettyPrinted 对转换之后的JSON对象进行排版,无意义
  • 第三个参数:错误信息
1
NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&error];

XML

  • XML 可扩展标记语言,是一种数据交互格式,也叫XML文档
  • XML 被设计用来 传输和存储数据

构成

常见的XML文档由三部分组成

  • 文档声明

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

1
2
3
4
5
// 最简单的声明
<?xml version="1.0" ?>

// 用encoding属性说明文档的字符编码
<?xml version="1.0" encoding="UTF-8" ?>
  • 元素

    • 一个元素包括了 开始标签和结束标签
    • 有内容的元素 <name>Tom</name>;没内容的元素 <from></from>,可简写成 <from/>
    • 元素可嵌套其他元素,不可出现交叉嵌套
  • 属性

一个元素最多可以拥有多个属性,属性值必须用双引号 " " 或 单引号 ' ' 括住

  • 示例
1
2
3
4
5
6
<root>
<person id="p1">
<name>Tom</name>
<age>24</age>
</person>
</root>

XML 解析的方法

要想从XML中提取信息,就得解析XML,目前针对XML的解析有两种方式:

  • SAX:从根元素开始,按照顺序一个元素一个元素的往下解析,可用于解析大、小文件
  • DOM:一次性将整个XML文档加载到内存中,适合较小的文件

iOS 中解析 XML 有两种:

  • 苹果原生:使用 NSXMLParse,SAX方式解析,使用简答

  • 第三方框架:libxml2、GDataXML

    • libxml2c 语音,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
    • GDataXMLDOM 解析,由 google 基于 libxml2 开发

解析XML大文件建议用:NSXMLParse、libxml2
解析XML小文件上述三种都可以

NSXMLParse 使用

  • 添加 NSXMLParserDelegate 协议

  • 获取XML文件,初始化 NSXMLParser,并开启解析

  • 实现协议中的方法

创建本地xml文件

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<clientOauthReturn>
<returnCode>RZ001100</returnCode>
<returnMessage>会话失效,请重新登录</returnMessage>
<authorizationCode></authorizationCode>
<tokenId>be9b425801aa4d7e89de79a7d9c10e31</tokenId>
</clientOauthReturn>

ViewController.m中解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#import "ViewController.h"

@interface ViewController ()<NSXMLParserDelegate>
@property (nonatomic,strong)NSMutableDictionary * mdic;
@property (nonatomic,copy)NSString * currentElementName;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

NSString * path = [[NSBundle mainBundle] pathForResource:@"auth" ofType:@"xml"];
NSData * data = [[NSData alloc] initWithContentsOfFile:path options:(NSDataReadingMappedIfSafe) error:nil];
NSXMLParser * parser=[[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
}

// 开始解析XML文档的时候调用
- (void)parserDidStartDocument:(NSXMLParser *)parser {
NSLog(@"开始解析XML文档");
}

// 开始解析某个元素的时候调用 该方法会调用多次
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
NSLog(@"开始解析单个元素:%@", elementName);
self.currentElementName = elementName;
if ([self.currentElementName isEqualToString:@"returnCode"]) {
[self.mdic setObject:@"" forKey:@"returnCode"];
}
if ([self.currentElementName isEqualToString:@"returnMessage"]) {
[self.mdic setObject:@"" forKey:@"returnMessage"];
}
if ([self.currentElementName isEqualToString:@"authorizationCode"]) {
[self.mdic setObject:@"" forKey:@"authorizationCode"];
}
if ([self.currentElementName isEqualToString:@"tokenId"]) {
[self.mdic setObject:@"" forKey:@"tokenId"];
}
}

// 解析发现字符串
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSLog(@"");
// 剔除获取的文本中空格和换行
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([self.currentElementName isEqualToString:@"returnCode"] &&
string.length > 0) {
[self.mdic setObject:string forKey:@"returnCode"];
}
if ([self.currentElementName isEqualToString:@"returnMessage"] &&
string.length > 0) {
[self.mdic setObject:string forKey:@"returnMessage"];
}
if ([self.currentElementName isEqualToString:@"authorizationCode"] &&
string.length > 0) {
[self.mdic setObject:string forKey:@"authorizationCode"];
}
if ([self.currentElementName isEqualToString:@"tokenId"] &&
string.length > 0) {
[self.mdic setObject:string forKey:@"tokenId"];
}
}


// 某个元素解析完毕的时候调用 该方法会调用多次
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
NSLog(@"单个元素解析完毕");
}

// 整个XML文档解析完毕的时候调用
-(void)parserDidEndDocument:(NSXMLParser *)parser{
NSLog(@"整个XML文档解析完毕");

// 主线程
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"mdic:%@",self.mdic);
});
}

#pragma mark -懒加载
- (NSMutableDictionary *)mdic{
if (!_mdic) {
_mdic = @{}.mutableCopy;
}
return _mdic;
}
@end

GDataXML 使用

  • GDataXMLDocument:xml解析入口
  • GdataXMLElement:保存查找的数据
  • GdataXMLNode:保存解析的数据

第一步:集成 GDataXML-HTML

1
2
3
4
5
6
7
8
9
target 'XML文件解析' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!

pod 'GDataXML-HTML', '~> 1.4.1'

# Pods for XML文件解析

end

第二步:项目中配置

  • pod 安装 GDataXML

  • 选中target -> Build Settings -> Link Binary With Libraried,搜索添加 libxml2

  • Header Search Paths 添加 /usr/include/libxml2

  • Other Linker Flags 添加 -lxml2

  • 引入头文件使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)GDataParserXML{
// 加载xmlwen文件
NSString *path = [[NSBundle mainBundle]pathForResource:@"xmlText" ofType:@"xml"];
NSURL *url = [NSURL fileURLWithPath:path];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error= nil;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data error:&error];
// 拿到根元素,得到根元素下所有子孙元素
NSArray * elementList =[doc.rootElement elementsForName:@"book"];
for (GDataXMLElement *element in elementList) {
NSString *title=((GDataXMLElement *)[[element elementsForName:@"title"] firstObject]).stringValue;
NSString *author=((GDataXMLElement *)[[element elementsForName:@"author"] firstObject]).stringValue;
NSString *year=((GDataXMLElement *)[[element elementsForName:@"year"] firstObject]).stringValue;
NSString *price=((GDataXMLElement *)[[element elementsForName:@"price"] firstObject]).stringValue;
NSLog(@"title = %@ author = %@ year = %@ price = %@",title,author,year,price);
}
}

  • Post title:OC学习04:JSON和XML数据解析
  • Post author:张建
  • Create time:2023-03-06 14:09:53
  • Post link:https://redefine.ohevan.com/2023/03/06/OC/OC学习04:JSON和XML数据解析/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.