XML数据结构
1.解析:就是按照约定好(假象)的格式提取数据的过程解析
提供数据方(后台):工作就是把数据按照一定的格式存储起来
提取数据方(前台):工作就是把数据按照一定得格式读取出来
主流的格式:XML格式 JSON格式 此两种格式无论前台还是后台都必须熟悉
2.XML的数据以标签的形式存在,标签有开始标签和结束标签,管这一对标签叫做节点
没有父节点的节点叫做根节点,没有子节点的节点叫做叶子节点,而我们使用的数据都存在叶子节点中存储
3.XML解析的两种工作原理
(1)SAX 基于事件回调(找代理)的解析方式,逐行解析,效率低,适合大数据解析,是系统提供的
(2)DOM 把要解析的数据一下子全部读取到内存中,把数据初始化成树状结构,逐层进行解析,效率高,只适合小数据解析(谷歌提供的第三方解析方式)
SAX解析 利用storyboard布局 在建一个Model类
(1)@interface
SAXViewController
()<NSXMLParserDelegate>
//存储从xml文件中解析出来的学生对象
@property (nonatomic,retain)NSMutableArray *dataSource;
@property (nonatomic,retain)Student *student;//使用学生对象存储读取到的信息
@property (nonatomic,retain)NSMutableString *string;//存储读取到节点中的数据
@end
@implementation SAXViewController
(2)- (void)dealloc
{
self.dataSource = nil;
self.student = nil;
self.string = nil;
[super dealloc];
}
(3)懒加载
- (NSMutableArray *)dataSource
{
if (_dataSource == nil) {
self.dataSource = [NSMutableArray arrayWithArray:0];
}
return [[_dataSource retain]autorelease];
}
(4) - (IBAction)handleParser:(UIBarButtonItem *)sender {
// NSLog(@"解析");
// 系统提供的解析XML文件的类NSXMLParser
// 1.获取文件路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Students.xml" ofType:nil];
// 2.创建NSData对象
NSDatT a *data = [NSData dataWithContentsOfFile:filePath];
//3.创建解析对象
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
// 4.指定代理
parser.delegate = self;
// 5.开始解析
[parser parse];
// 6.释放
[parser release];
}
(5) #pragma mark XMLparser的代理方法
//开始解析的时候触发这个方法
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
// NSLog(@"开始解析了");
// 开始解析的时候清空数值中的内容
[self.dataSource removeAllObjects];
}
//读取到开始标签的时候触发
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// NSLog( @"%@",attributeDict);
// NSLog(@"%@",elementName);
// 当读取到student开始标签的时候创建学生对象
if ([elementName isEqualToString:@"student"]) {
self.student = [[Student alloc]init];
self.student.position = attributeDict[@"position"];
}
// #####21读取到开始标签就初始化字符串self.string
self.string = [NSMutableString stringWithCapacity:0];
}
//当读取到开始标签后的数据时触发
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string//string就是存储的读取得到的数据
{
// NSLog(@"%@",string);
//使用属性保存节点中间的数据
// #####21由于系统的解析能力是有限的如果节点中的内容过长不能够一次性全部读取,此时,要把每次读取的内容拼接到一起
[self.string appendString:string];
}
//读取到结束标签的时候触发
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// NSLog(@"==%@",elementName);
if ([elementName isEqualToString:@"name"]) {
self.student.name = self.string;
}else if ([elementName isEqualToString:@"age"]){
self.student.age = self.string;
}else if ([elementName isEqualToString:@"gender"]){
self.student.gender = self.string;
}else if ([elementName isEqualToString:@"says"]){
self.student.says = self.string;
}else if ([elementName isEqualToString:@"student"]){
[self.dataSource addObject:self.student];//把学生对象添加到数组中
[self.student release];//释放
}
}
//结束解析的时候触发
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
// NSLog(@"%@",self.dataSource);
// NSLog(@"解析结束了");
// 在这里让tableView重新刷新一次UI,重新走一遍数据源代理方法
[self.tableView reloadData];
}
(6) - (NSInteger)numberOfSectionsInTableView:(UITableView
*)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataSource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"sax" forIndexPath:indexPath];
Student *s = self.dataSource[indexPath.row];//根据cell的下标取出对应的学生
cell.textLabel.text = s.name;
return cell;
}
@end
DOM解析 利用storyboard布局
GDataXMLNode是有Google提供的开源的基于C语言的libxml2.dylib动态链接类库封装的OC解析类,效率比较高
使用GDataxmlNade的步骤:
1.target - Build Phases-link Binary 添加libxml2.dylib
2.target - Build setting header search Pach 添加 /usr/include/libxml2
libxml2.dylib 和libxml2.2dylib的区别:前一个是快捷方式,永远指向最新的实体类库,而后一个才是真正的实体类库,使用前一个的好处,当系统的实体类库更新的时候,老版本的项目就无需再重新导入实体类库
(1)
@interfaceDOMViewController ()
@property (nonatomic,retain)NSMutableArray *dataSource;
@end
(2)
@implementation DOMViewController
- (void)dealloc
{
self.dataSource = nil;
[super dealloc];
}
(3)懒加载
- (NSMutableArray *)dataSource
{
if (_dataSource ==nil) {
self.dataSource = [NSMutableArray arrayWithCapacity:0];
}
return [[_dataSource retain]autorelease];
}
(4) - (IBAction)handleRootParser:(UIBarButtonItem
*)sender {
// 解析开始之前把数组中的元素清空
self.dataSource = nil;
// 1.读取文件的路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Students.xml" ofType:nil];
// 2.将文件内容存储到字符串中
NSString *xmlStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
// 3.将要解析的内容写入到GDataxmlDocument内容
// / 第二个参数是一个预留参数,就是这个方法的作者,在写着方法时预留一个参数的位置,留待以后对方的扩充
GDataXMLDocument *document = [[GDataXMLDocument alloc]initWithXMLString:xmlStr options:0 error:nil];
// GDataXMLElement节点类
// GDataXMLNode 它里面存的是属性对象 是个属性类
// 4. 获取document中所有的根节点
GDataXMLElement *rootElement = [document rootElement];
// NSLog(@"%@",rootElement);
// 5. 获取根节点下的所有student节点
NSArray *stuElements = [rootElement elementsForName:@"student"];
// NSLog(@"%@",stuElements);
// 6. 遍历数组,获取每一个student节点
for (GDataXMLElement *stuElement in stuElements) {
// 7. 获取student节点下的name/age/gnder/says节点
GDataXMLElement *nameElement = [[stuElement elementsForName:@"name"]lastObject];
GDataXMLElement *ageElement = [[stuElement elementsForName:@"age"]lastObject];
GDataXMLElement *genderElement = [[stuElement elementsForName:@"gender"]lastObject];
GDataXMLElement *saysElement = [[stuElement elementsForName:@"says"]lastObject];
/*
// 打印每个节点对象中的数据 stringvalue方法可以返回节点对象中的数据
NSLog(@"%@",[nameElement stringValue]);
NSLog(@"%@",[ageElement stringValue]);
NSLog(@"%@",[genderElement stringValue]);
NSLog(@"%@",[saysElement stringValue]);
NSLog(@"==================================");
*/
// 8.创建学生对象,存储节点对象中的数据
Student *stu = [[Student alloc]init];
stu.name = [nameElement stringValue];
stu.age = [ageElement stringValue];
stu.gender = [genderElement stringValue];
stu.says = [saysElement stringValue];
// 10. 取出学生节点对象中的属性
GDataXMLNode *node = [stuElement attributeForName:@"position"];
stu.position = [node stringValue];
// 9. 将学生对象添加到数组中
[self.dataSource addObject:stu];
[stu
release];
}
[self.tableView reloadData];//更新UI
NSLog(@"%@",self.dataSource);
// 释放掉xml文本对象
[document release];
}
(5) - (NSInteger)numberOfSectionsInTableView:(UITableView
*)tableView {
return
1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return
self.dataSource.count;
}
- (UITableViewCell
*)tableView:(UITableView
*)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"dom" forIndexPath:indexPath];
Student *s = self.dataSource[indexPath.row];
cell.textLabel.text = s.position;
return cell;
}
@end
JSON数据结构解析
(1)
#import "JSONViewController.h"
#import "Student.h"
#import "JSONKit.h"
@interface JSONViewController ()
@property (nonatomic,retain)NSMutableArray *dataSource;
@end
(2) @implementation JSONViewController
- (void)dealloc
{
self.dataSource = nil;
[super dealloc];
}
(3)懒加载
- (NSMutableArray *)dataSource
{
if (_dataSource == nil) {
self.dataSource = [NSMutableArray arrayWithCapacity:0];
}
return [[_dataSource retain]autorelease];
}
(4) - (IBAction)handleSystem:(UIBarButtonItem
*)sender {
self.dataSource = nil;
NSLog(@"系统");
// 1.获取文件路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Student.json" ofType:nil];
// 2.将json文件读取到NSDate对象中
NSData *data = [NSData dataWithContentsOfFile:filePath];
// NSJSONReadingMutableContainers返回的容器是可变的容器
// NSJSONReadingMutableLeaves返回的找到的数据时可不的数据
// 3.json文件的最外层是数组,所有用数组接收
NSMutableArray *dataSource = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
// NSLog(@"%@",dataSource);
// 3. 数组中都是字典对象,所以遍历字典
for (NSDictionary *dic in dataSource) {
Student *stu = [[Student alloc]init];
[stu setValuesForKeysWithDictionary:dic];
[self.dataSource addObject:stu];
[stu release];
}
// 刷新UI
[self.tableView reloadData];
}
(5) - (IBAction)handleThird:(UIBarButtonItem
*)sender {
self.dataSource = nil;
// NSLog(@"第三方");
// 1.获取文件路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Student.json" ofType:nil];
{
NSString *jsonStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
// 2. 第一种解析 通过JSON格式字符串解析JSON数据 objectFromJSONString返回的数据可以使用可变容器接收也可以使用不可变容器接收
NSArray *dataArray =[jsonStr objectFromJSONString];
// NSLog(@"%@",dataArray);
}
// 2. 第二种解析 通过NSData对象完成解析
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSArray *dataArray2 = [data objectFromJSONData];
NSLog(@"%@",dataArray2);
for (NSDictionary *dic in dataArray2) {
Student *stu = [[Student alloc]init];
[stu setValuesForKeysWithDictionary:dic];
[self.dataSource addObject:stu];
[stu release];
}
[self.tableView reloadData];
}
(6) - (NSInteger)numberOfSectionsInTableView:(UITableView
*)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataSource.count;
}
- (UITableViewCell
*)tableView:(UITableView
*)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"json" forIndexPath:indexPath];
Student *stu = self.dataSource[indexPath.row];
cell.textLabel.text = stu.age;
return
cell;
}
@end
1.解析:就是按照约定好(假象)的格式提取数据的过程解析
提供数据方(后台):工作就是把数据按照一定的格式存储起来
提取数据方(前台):工作就是把数据按照一定得格式读取出来
主流的格式:XML格式 JSON格式 此两种格式无论前台还是后台都必须熟悉
没有父节点的节点叫做根节点,没有子节点的节点叫做叶子节点,而我们使用的数据都存在叶子节点中存储
(1)SAX 基于事件回调(找代理)的解析方式,逐行解析,效率低,适合大数据解析,是系统提供的
(2)DOM 把要解析的数据一下子全部读取到内存中,把数据初始化成树状结构,逐层进行解析,效率高,只适合小数据解析(谷歌提供的第三方解析方式)
//存储从xml文件中解析出来的学生对象
@property (nonatomic,retain)NSMutableArray *dataSource;
@property (nonatomic,retain)Student *student;//使用学生对象存储读取到的信息
@property (nonatomic,retain)NSMutableString *string;//存储读取到节点中的数据
@end
@implementation SAXViewController
(2)- (void)dealloc
{
self.dataSource = nil;
self.student = nil;
self.string = nil;
[super dealloc];
}
(3)懒加载
- (NSMutableArray *)dataSource
{
if (_dataSource == nil) {
self.dataSource = [NSMutableArray arrayWithArray:0];
}
return [[_dataSource retain]autorelease];
}
(4) - (IBAction)handleParser:(UIBarButtonItem *)sender {
// NSLog(@"解析");
// 系统提供的解析XML文件的类NSXMLParser
// 1.获取文件路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Students.xml" ofType:nil];
// 2.创建NSData对象
NSDatT a *data = [NSData dataWithContentsOfFile:filePath];
//3.创建解析对象
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
// 4.指定代理
parser.delegate = self;
// 5.开始解析
[parser parse];
// 6.释放
[parser release];
}
//开始解析的时候触发这个方法
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
// NSLog(@"开始解析了");
// 开始解析的时候清空数值中的内容
[self.dataSource removeAllObjects];
}
//读取到开始标签的时候触发
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// NSLog( @"%@",attributeDict);
// NSLog(@"%@",elementName);
// 当读取到student开始标签的时候创建学生对象
if ([elementName isEqualToString:@"student"]) {
self.student = [[Student alloc]init];
self.student.position = attributeDict[@"position"];
}
// #####21读取到开始标签就初始化字符串self.string
self.string = [NSMutableString stringWithCapacity:0];
}
//当读取到开始标签后的数据时触发
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string//string就是存储的读取得到的数据
{
// NSLog(@"%@",string);
//使用属性保存节点中间的数据
// #####21由于系统的解析能力是有限的如果节点中的内容过长不能够一次性全部读取,此时,要把每次读取的内容拼接到一起
[self.string appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// NSLog(@"==%@",elementName);
if ([elementName isEqualToString:@"name"]) {
self.student.name = self.string;
}else if ([elementName isEqualToString:@"age"]){
self.student.age = self.string;
}else if ([elementName isEqualToString:@"gender"]){
self.student.gender = self.string;
}else if ([elementName isEqualToString:@"says"]){
self.student.says = self.string;
}else if ([elementName isEqualToString:@"student"]){
[self.dataSource addObject:self.student];//把学生对象添加到数组中
[self.student release];//释放
}
}
//结束解析的时候触发
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
// NSLog(@"%@",self.dataSource);
// NSLog(@"解析结束了");
// 在这里让tableView重新刷新一次UI,重新走一遍数据源代理方法
[self.tableView reloadData];
}
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataSource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"sax" forIndexPath:indexPath];
Student *s = self.dataSource[indexPath.row];//根据cell的下标取出对应的学生
cell.textLabel.text = s.name;
return cell;
}
@end
DOM解析 利用storyboard布局
使用GDataxmlNade的步骤:
1.target - Build Phases-link Binary 添加libxml2.dylib
2.target - Build setting header search Pach 添加 /usr/include/libxml2
libxml2.dylib 和libxml2.2dylib的区别:前一个是快捷方式,永远指向最新的实体类库,而后一个才是真正的实体类库,使用前一个的好处,当系统的实体类库更新的时候,老版本的项目就无需再重新导入实体类库
@interfaceDOMViewController ()
@property (nonatomic,retain)NSMutableArray *dataSource;
@end
(2)
@implementation DOMViewController
- (void)dealloc
{
self.dataSource = nil;
[super dealloc];
}
- (NSMutableArray *)dataSource
{
if (_dataSource ==nil) {
self.dataSource = [NSMutableArray arrayWithCapacity:0];
}
return [[_dataSource retain]autorelease];
}
// 解析开始之前把数组中的元素清空
self.dataSource = nil;
// 1.读取文件的路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Students.xml" ofType:nil];
// 2.将文件内容存储到字符串中
NSString *xmlStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
// 3.将要解析的内容写入到GDataxmlDocument内容
// / 第二个参数是一个预留参数,就是这个方法的作者,在写着方法时预留一个参数的位置,留待以后对方的扩充
GDataXMLDocument *document = [[GDataXMLDocument alloc]initWithXMLString:xmlStr options:0 error:nil];
// GDataXMLElement节点类
// GDataXMLNode 它里面存的是属性对象 是个属性类
// 4. 获取document中所有的根节点
GDataXMLElement *rootElement = [document rootElement];
// NSLog(@"%@",rootElement);
// 5. 获取根节点下的所有student节点
NSArray *stuElements = [rootElement elementsForName:@"student"];
// NSLog(@"%@",stuElements);
// 6. 遍历数组,获取每一个student节点
for (GDataXMLElement *stuElement in stuElements) {
// 7. 获取student节点下的name/age/gnder/says节点
GDataXMLElement *nameElement = [[stuElement elementsForName:@"name"]lastObject];
GDataXMLElement *ageElement = [[stuElement elementsForName:@"age"]lastObject];
GDataXMLElement *genderElement = [[stuElement elementsForName:@"gender"]lastObject];
GDataXMLElement *saysElement = [[stuElement elementsForName:@"says"]lastObject];
/*
// 打印每个节点对象中的数据 stringvalue方法可以返回节点对象中的数据
NSLog(@"%@",[nameElement stringValue]);
NSLog(@"%@",[ageElement stringValue]);
NSLog(@"%@",[genderElement stringValue]);
NSLog(@"%@",[saysElement stringValue]);
NSLog(@"==================================");
*/
// 8.创建学生对象,存储节点对象中的数据
Student *stu = [[Student alloc]init];
stu.name = [nameElement stringValue];
stu.age = [ageElement stringValue];
stu.gender = [genderElement stringValue];
stu.says = [saysElement stringValue];
// 10. 取出学生节点对象中的属性
GDataXMLNode *node = [stuElement attributeForName:@"position"];
stu.position = [node stringValue];
// 9. 将学生对象添加到数组中
[self.dataSource addObject:stu];
}
[self.tableView reloadData];//更新UI
NSLog(@"%@",self.dataSource);
// 释放掉xml文本对象
[document release];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"dom" forIndexPath:indexPath];
Student *s = self.dataSource[indexPath.row];
cell.textLabel.text = s.position;
return cell;
}
@end
(1)
#import "JSONViewController.h"
#import "Student.h"
#import "JSONKit.h"
@interface JSONViewController ()
@property (nonatomic,retain)NSMutableArray *dataSource;
@end
(2) @implementation JSONViewController
- (void)dealloc
{
self.dataSource = nil;
[super dealloc];
}
(3)懒加载
- (NSMutableArray *)dataSource
{
if (_dataSource == nil) {
self.dataSource = [NSMutableArray arrayWithCapacity:0];
}
return [[_dataSource retain]autorelease];
}
self.dataSource = nil;
NSLog(@"系统");
// 1.获取文件路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Student.json" ofType:nil];
// 2.将json文件读取到NSDate对象中
NSData *data = [NSData dataWithContentsOfFile:filePath];
// NSJSONReadingMutableContainers返回的容器是可变的容器
// NSJSONReadingMutableLeaves返回的找到的数据时可不的数据
// 3.json文件的最外层是数组,所有用数组接收
NSMutableArray *dataSource = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
// NSLog(@"%@",dataSource);
// 3. 数组中都是字典对象,所以遍历字典
for (NSDictionary *dic in dataSource) {
Student *stu = [[Student alloc]init];
[stu setValuesForKeysWithDictionary:dic];
[self.dataSource addObject:stu];
[stu release];
}
// 刷新UI
[self.tableView reloadData];
self.dataSource = nil;
// NSLog(@"第三方");
// 1.获取文件路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Student.json" ofType:nil];
NSString *jsonStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
// 2. 第一种解析 通过JSON格式字符串解析JSON数据 objectFromJSONString返回的数据可以使用可变容器接收也可以使用不可变容器接收
NSArray *dataArray =[jsonStr objectFromJSONString];
// NSLog(@"%@",dataArray);
}
// 2. 第二种解析 通过NSData对象完成解析
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSArray *dataArray2 = [data objectFromJSONData];
NSLog(@"%@",dataArray2);
for (NSDictionary *dic in dataArray2) {
Student *stu = [[Student alloc]init];
[stu setValuesForKeysWithDictionary:dic];
[self.dataSource addObject:stu];
[stu release];
}
[self.tableView reloadData];
}
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataSource.count;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"json" forIndexPath:indexPath];
Student *stu = self.dataSource[indexPath.row];
cell.textLabel.text = stu.age;
}
@end