前一篇文章已经介绍了如何通过URL从网络上获取xml数据。下面介绍如何将获取到的数据进行解析。
下面先看看xml的数据格式吧!
<?xml version="1.0" encoding="UTF-8"?> <Books> <Book id="1"> <title>Circumference</title> <author>Nicholas Nicastro</author> <summary>Eratosthenes and the Ancient</summary> </Book> <Book id="2"> <title>Copernicus Secret</title> <author>Jack Repcheck</author> <summary>How the scientific revolution began</summary> </Book> <Book id="3"> <title>Angels and Demons</title> <author>Dan Brown</author> <summary>Robert Langdon is summoned to a Swiss</summary> </Book> </Books>显然在这个xml中包括三本书的一些基本数据:id title author summary 解析的过程就是将这些数据提取出来。
先简单介绍一下xml数据解析吧。xml数据的解析一般有两种方式:SAX(Simple API for XML)和DOM (Document Object Model),事件和文档。
NSXMLParser 实现的是sax方法解析xml文件。
下面进入主题介绍如何对xml进行解析:
一、将上面的xml数据保存为Books.xml作为本地xml数据,并导入项目中。
二、由于book中含有几个属性,所以这里第一个book类。
Book.h文件:
#import <Foundation/Foundation.h> @interface Book : NSObject @property (nonatomic, readwrite) NSInteger bookID; @property (nonatomic, retain) NSString *title; @property (nonatomic, retain) NSString *author; @property (nonatomic, retain) NSString *summary; @end
#import "Book.h" @implementation Book @synthesize bookID; @synthesize title; @synthesize author; @synthesize summary; @end
三、要实现对xml数据的解析实际上是通过实现NSXMLParserDelegate委托中的几个方法。
#pragma mark xmlparser //step 1 :准备解析 - (void)parserDidStartDocument:(NSXMLParser *)parser { } //step 2:准备解析节点 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { } //step 3:获取首尾节点间内容 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { } //step 4 :解析完当前节点 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { } //step 5:解析结束 - (void)parserDidEndDocument:(NSXMLParser *)parser { } //step 6:获取cdata块数据 - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock { }
下面分别介绍:
Step 1: 在开始解析之前的一些准备工作,例如初始化一些存储变量。在我的这个例子中,使用了一个Book实例变量来存储一本书(也即是一组信息),一个可变数组来存储这三本书(即每一组信息都当成这个数组中的一个元素),(此次要注意理解数据变量之间的关系),其他变量就暂不介绍啦(待会看源代码就可以了)。
Step 2: 当解析器遇到xml的根标签和一组信息的开始标签时就开始调用这个方法,在这个xml文件中,遇到Books(xml文件的根标签),Book(一组信息的开始标签)时就会调用这个方法。那么也就可以知道这个方法在程序运行过程中被调用了多次。那么就可以用 if 语句判断遇到的是Books还是Book,然后做一些相应的操作(具体的话待会看源代码)。
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { }注意其中的参数:elementName表示遇到的标签,在这个程序中会遇到的是Books和Book; 解析到一个标签时,开始的 标签可能会有一些属性,例如在这里<Book id="1">
那么id就是属性啦,在这个方法中他是用一个字典来保存的即(NSDictionary *)attributeDict,那么对这个字典操作就可以得到你要的value和key啦。
Step 3:当解析器找到开始标签和结束标签之间的字符时,就调用这个方法,读取其中的内容。 注意:这里读取到的string在这个函数里面我们并不知道是那个属性的内容,意思就是假如string的内容是Circumference(Book 的title),但是我们不知道这个是title的内容;那么在哪里才知道,然后对它进行存储操作呢,不要着急,就是Step4啦!
Step 4:当解析器读到结束标签时,就会调用这个方法。例如读到Books,Book,title等。那么对读到的标签进行判断后就可以进行存储操作啦!
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { }这里标签参数就是elementName。
Step 5:对整个xml文件解析结束后的一些操作。
Step 6:这个暂不解释(我还没有用到)。
四、下面就是上代码的时候啦
.h文件
#import <UIKit/UIKit.h> @class AppDelegate,Book; @interface ViewController : UIViewController <NSXMLParserDelegate> { NSMutableString *currentElementValue; //用于存储元素标签的值 NSMutableArray *books; //用于存储一组书籍 Book *aBook; //书籍实例,代表一本书 BOOL storingFlag; //查询标签所对应的元素是否存在 NSArray *elementToParse; //要存储的元素 } - (IBAction)xmlButton:(id)sender; @end
.m文件
#import "ViewController.h" #import "AppDelegate.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //初始化要解析的元素标签 elementToParse = [[NSArray alloc] initWithObjects:@"title",@"author",@"summary", nil]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { if([elementName isEqualToString:@"Books"]) { //Initialize the array. //在这里初始化用于存储最终解析结果的数组变量,我们是在当遇到Books根元素时才开始初始化 books = [[NSMutableArray alloc] init]; } else if([elementName isEqualToString:@"Book"]) { //Initialize the book. //当碰到Book元素时,初始化用于存储Book信息的实例对象aBook aBook = [[Book alloc] init]; //Extract the attribute here. //从attributeDict字典中读取Book元素的属性 aBook.bookID = [[attributeDict objectForKey:@"id"] integerValue]; NSLog(@"ID:%i", aBook.bookID); } storingFlag = [elementToParse containsObject:elementName]; //判断是否存在要存储的对象 } - (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // 当用于存储当前元素的值是空时,则先用值进行初始化赋值 // 否则就直接追加信息 if (storingFlag) { if (!currentElementValue) { currentElementValue = [[NSMutableString alloc] initWithString:string]; } else { [currentElementValue appendString:string]; } } } // 这里才是真正完成整个解析并保存数据的最终结果的地方 - (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { if ([elementName isEqualToString:@"Book"]) { [books addObject:aBook]; aBook = nil; } if (storingFlag) { //去掉字符串的空格 NSString *trimmedString = [currentElementValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; //将字符串置空 [currentElementValue setString:@""]; if ([elementName isEqualToString:@"title"]) { aBook.title = trimmedString; NSLog(@"title :%@",aBook.title); } if ([elementName isEqualToString:@"author"]) { aBook.author = trimmedString; NSLog(@"author :%@",aBook.author); } if ([elementName isEqualToString:@"summary"]) { aBook.summary = trimmedString; NSLog(@"summary :%@",aBook.summary); } } } - (IBAction)xmlButton:(id)sender { //打开xml文件,读取数据到NSData NSString *path = [[NSBundle mainBundle] pathForResource:@"Books" ofType:@"xml"]; NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; NSData *data = [file readDataToEndOfFile]; [file closeFile]; //测试从xml接受到的数据 NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",dataString); NSXMLParser *m_parser = [[NSXMLParser alloc] initWithData:data]; //设置该类本身为代理类,即该类在声明时要实现NSXMLParserDelegate委托协议 [m_parser setDelegate:self]; //设置代理为本地 BOOL flag = [m_parser parse]; //开始解析 if(flag) { NSLog(@"解析指定路径的xml文件成功"); } else { NSLog(@"解析指定路径的xml文件失败"); } } @end
1、其中我用了一些NSLog来输出相关的信息验证,实际使用过程中,去掉就ok啦!
2、结合我上面的解释和代码,应该可以理解整个xml解析的过程的。
3、这里我用的是本地的xml文件,如果是想进行网络xml数据的解析的话,那也是很简单的,就是通过url获取xml数据替换掉这里的本地xml,通过url获取xml可以参考上一篇博文。