iOS JSON、XML解析技巧
序言:
以下实验效果会采用简单的方式呈现,读者可根据自身情况修改实验代码
如果数据复杂需要自己调试,可看我另一篇文章搭建本地Apache服务器,道理是相通的! Mac 本地搭建Apache服务器
一、JSON解析
这里,我们需要先分析数据再做解析操作!
1.准备的数据:在Safari浏览器访问https://www.crios.cn/test.json
json数据.png
2.效果图如下
打开xcode->新建项目->新建Person模型装载json数据
// 代码如下
// 以下代码意义是根据数据来创建变量的
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (copy, nonatomic) NSString *username;
@property (strong, nonatomic) NSNumber *age;
@property (strong, nonatomic) NSNumber *id;
@end
回到ViewContorller.m文件,添加以下代码
/* 在头部导入Person类
// Model
#import "Person.h"
*/
// 1.创建url
NSURL *url = [NSURL URLWithString:@"https://www.crios.cn/test.json"];
// 2.创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:10.0];
// 3.创建NSURLSession
NSURLSession *session = [NSURLSession sharedSession];
// 4.创建NSURLSessionDataTask
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
NSArray *jsons = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSMutableArray *results = [NSMutableArray array];
for (NSDictionary *dic in jsons) {
Person *person = [[Person alloc] init];
[person setValuesForKeysWithDictionary:dic];
[results addObject:person];
}
NSLog(@"结果:%@", results);
} else {
NSLog(@"错误提示:%@",error);
}
}];
// 5.开启任务(如果任务在挂起状态,这里会重新开启任务)
[dataTask resume];
setValuesForKeysWithDictionary意义:
dic中的key会找Person类中的变量,一一对应,再将key对应的value赋值过去
打印效果:
上面无法打印模型的变量值,我们可在Person.m文件中添加以下代码:
- (NSString *)description {
return [NSString stringWithFormat:@"<%@:%p>{id:%@,name:%@,age:%@}",self.class,self,_id, _username, _age];
}
输出效果
第一问,我们已设定好Person类中的变量,但我们定义好的Person类与服务器返回的数据不一致会出现何种情况,此时怎么办?
image.png
程序直接奔溃
莫慌,直接在Person.m文件中添加如下代码
// 代码块暂时不需要其他操作,可空着
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
}
程序正常跑起来了。
接着来,第二问,服务器返回的数据,有我们OC语言的关键字,赋值操作会出现一些无法预测的问题,这可咋办呢?
解决这个问题首先先在Person.h文件中修改代码
@property (copy, nonatomic) NSString *username;
//@property (strong, nonatomic) NSNumber *age;
// 将关键字修改成我们想要的模样
@property (strong, nonatomic) NSNumber *ID;
其次在Person.m文件中添加如下代码
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
if ([key isEqualToString:@"id"]) {
self.ID = value;
}
}
实验效果跟预期一样。成功了。🤡
第三问,我们打印的数组中,出现的中文为乱码,这可咋办呢?
新建NSArray Category
在NSArray+Log.m文件中添加以下代码
// 实际代码看这里,以下代码意义不解释,相信大家都看得懂
- (NSString *)descriptionWithLocale:(id)locale {
NSMutableString *resultStr = [NSMutableString stringWithString:@"🇨🇳(\n"];
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[resultStr appendFormat:@"\t%@\n",obj];
}];
[resultStr appendFormat:@")\n"];
return resultStr;
}
结果输出:
二、XML解析
XML:
XML是一种可扩展"标记"语言,特点是阅读方便,美观大方。
解析方式:
方式 | 介绍 | 特点 |
---|---|---|
DOM | MAC提供的解析方法,iOS中无法直接使用 | 1.内存开销大 2.可读可写 3.将数据以树形结构加载到内存 |
SAX | 适用于iOS的解析方式 | 1.内存开销小 2.只读 3.速度快 4.从上到下,顺序解析的过程 |
行,我们来做实验。
1)同样的,我们也需要分析数据再做解析操作!
1.准备的数据:在谷歌浏览器访问http://www.crios.cn/persons.xml (数据也可从其他地方来,道理是一样的)
xml数据
2.效果图如下
2)新建Person类,来装载数据,看了前面的json解析之后,这里会更容易明白。
Person.h文件
@property (strong, nonatomic)NSNumber *personId;
@property (copy, nonatomic)NSString *height;
@property (copy, nonatomic)NSString *age;
@property (copy, nonatomic)NSString *name;
@property (copy, nonatomic)NSString *sex;
@property (copy, nonatomic)NSString *desc;
Person.m文件
- (NSString *)description {
return [NSString stringWithFormat:@"<%@:%p>{videoID:%@,name:%@,age:%@,height:%@,sex:%@,desc:%@}",[self class],self,self.personId,self.name,self.age,self.height,self.sex,self.desc];
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
// 这里代码可空着,主要意义是防止服务器返回的数据与我们创建的Model类对应不上
}
4)ViewController.m文件
// 1.导入Person 类
#import "Person.h"
// 2.遵守代理协议
@interface ViewController ()<NSXMLParserDelegate>
// 3.创建可变数组
@property (strong, nonatomic) NSMutableArray *persons;
// 4.创建可变字符串
@property (strong , nonatomic) NSMutableString *elementStr;
// 5.当前解析的节点模型
@property (strong, nonatomic) Person *currentPerson;
@end
@implementation ViewController
// MARK: 懒加载
- (NSMutableArray *)persons {
if (!_ persons) {
_ persons = [[NSMutableArray alloc] init];
}
return _ persons;
}
- (NSMutableString *)elementStr {
if (!_elementStr) {
_elementStr = [[NSMutableString alloc] init];
}
return _elementStr;
}
@end
- 请求数据
//1.url
NSURL *url = [NSURL URLWithString:@"http://www.crios.cn/persons.xml"];
// 2.创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:10.0];
// 3.创建NSURLSession
NSURLSession *session = [NSURLSession sharedSession];
// 4.创建NSURLSessionDataTask
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
// XML解析
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:data];
// 设置代理
xmlParser.delegate = self;
//解析器解析
[xmlParser parse];
}
}];
// 5.开启任务(如果任务在挂起状态,这里会重新开启任务)
[dataTask resume];
3)补充说明这里采用苹果原生NSXMLParser类来进行解析,主要通过6种代理方法来进行操作
// 1.打开文档
- (void)parserDidStartDocument:(NSXMLParser *)parser {
NSLog(@"1.开始文档");
//1.清空数组
[self.persons removeAllObjects];
}
// 2.开始节点
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
if ([elementName isEqualToString:@"person"]) {
//1.新建模型
self.currentPerson = [[Person alloc] init];
//2设置personID的属性
self.currentPerson.personId = @([attributeDict[@"personId"] intValue]);
}
}
// 3.发现节点内容
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
[self.elementStr appendString:string];
}
// 4.结束节点
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:@"person"]) {
[self.persons addObject:self.currentPerson];
} else if (![elementName isEqualToString:@"persons"]) {
[self.currentPerson setValue:self.elementStr forKey:elementName];
}
//清空字符串
[self.elementStr setString:@""];
}
// 5.结束解析
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(@"结果:%@",self.persons);
}
// 6.错误处理
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSLog(@"错误描述:%@",parseError.description);
}