前一篇文章已经介绍了如何通过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),事件和文档。
dom实现的原理是把整个xml文档一次性读出,放在一个树型结构里。在需要的时候,查找特定节点,然后对节点进行读或写。他的主要优势是实现简单,读写平衡;缺点是比较占内存,因为他要把整个xml文档都读入内存,文件越大,这种缺点就越明显。
sax的实现方法和dom不同。他只在xml文档中查找特定条件的内容,并且只提取需要的内容。这样做占用内存小,灵活。
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
Book.m文件
- #import "Book.h"
-
- @implementation Book
-
- @synthesize bookID;
- @synthesize title;
- @synthesize author;
- @synthesize summary;
-
- @end
三、要实现对xml数据的解析实际上是通过实现NSXMLParserDelegate委托中的几个方法。
- #pragma mark xmlparser
- - (void)parserDidStartDocument:(NSXMLParser *)parser
- {
-
- }
- - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
- {
-
- }
- - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
- {
-
- }
-
- - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
- {
-
- }
-
- - (void)parserDidEndDocument:(NSXMLParser *)parser
- {
-
- }
- - (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
- {
-
- }
在实现xml解析过程以上方法中的step3 、4、5是必须的,而step1、5可选。
下面分别介绍:
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
说明:这里我用一个按键来触发xml解析。
.m文件