Objective-C 基础 - NSXMLParser
来自 Objective-C Fundamentals 的章节摘录
![]() |
Objective-C 基础 开发 iPhone 和 iPad 应用 作者:Christopher K. Fairbairn, Johannes Fahrenkrug, and Collin Ruffenach Apple 为 iPhone 开发者提供了一个名为 NSXMLParser 的类。开发者在解析 XML 时会使用这个类。这篇来自《Objective-C 基础》的文章展示了 NSXMLParser 提供的委托方法,这些方法可以处理基于 XML 和 DTD 文档的解析过程中的每一个环节。 在 www.manning.com 结账时使用优惠码 code40project,下次购买可享受 40% 的折扣。 |
Apple 为 iPhone 开发者提供了一个名为 NSXMLParser 的类。开发者在解析 XML 时会使用这个类。虽然有几个 NSXMLParser 的开源替代方案可供选择,并且被许多开发者使用,但我们将着重介绍标准 Cocoa XML 解析器的委托方法。
不存在 <NSXMLParser> 协议;即使你没有在你正在创建的应用程序头文件中声明它,也不会收到任何警告。NSXMLParser 是一个边缘设计类,它遵循协议设计的原则,但没有显式地定义一个协议。一个 NSXMLParser 对象有一个名为 delegate 的参数,这个参数需要被定义。任何被定义为委托的对象都可以选择性地实现 20 个不同委托方法的集合。NSXMLParser 提供的委托方法可以处理基于 XML 和 DTD 文档的解析过程中的每一个环节。
XML 是一种可以以非常结构化的方式保存数据的文件类型。简单介绍一下,XML 使用 HTML 的语法来创建独特的数据结构。列表 1 展示了一个描述一个人的 XML 元素示例。
列表 1 XML 中的作者
<Author> <name>Collin Ruffenach</name> <age>23</age> <gender>male</gender> <Books> <Book> <title>Objective C for the iPhone</title> <year>2010</year> <level>intermediate</level> </Book> </Books> </Author>
XML 是一种非常常见的从在线资源(如 Twitter)获取数据的方式。XML 也被用来为你的特定 iPhone 项目提供运行所需的数据。iPhone 开发严重依赖 PLISTS 文件。这些文件实际上就是 XML。
DTD 代表文档类型定义(Document Type Definition)。这是一个描述你将要处理的 XML 结构的文档。版本 7.4.3.1 中的 XML 的文档类型定义将会是
<!ELEMENT Author (name, age, gender, books_list(book*))> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT gender (#PCDATA)> <!ELEMENT Book (title, year, level)> <!ELEMENT title (#PCDATA)> <!ELEMENT year (#PCDATA)> <!ELEMENT level (#PCDATA)>
对于某些应用程序,检查它们接收到的 XML 的结构会改变应用程序的解析方式。在这种情况下,我们说 XML 将包含一个名为 Author 的元素。一个 Author 将由 name、age 和 gender 定义,这些都是简单的字符串。一个 author 还会有一个 Book 元素的列表。一本书(Book)由 title、year 和 level 定义,这些也都是简单的字符串。这确保了 NSXMLParser 知道该做什么。
在大多数情况下,当你解析 XML 时,你在编写解析器类的时候就已经知道它的结构了。对于这些情况,你不需要研究 XML 源的 DTD。一个例子就是 Twitter 时间线的 XML 源。我们将假设我们知道我们的 XML 的结构,并且只实现 NSXMLParser 委托的解析函数来解析我们已经看过的 Author XML。
使用 NSXMLParser 委托解析一个作者
实现 NSXMLParser 的第一步是创建一个类,该类将包含解析器对象并实现其委托方法。让我们创建一个新的基于视图的项目,名为 Parser_Project,并创建一个名为 Parser 的新 NSObject 子类。我们将为 Parser 类声明的唯一实例变量是一个 NSXMLParser 和一个用于辅助的 NSMutableString。让 Parser.h 看起来像下面这样。
#import <Foundation/ Foundation.h> @interface Parser : NSObject <NSXMLParserDelegate> { NSXMLParser *parser; NSMutableString *element; } @end
我们将需要一个 XML 文件来进行解析。你可以将列表 2 中的 XML 放入一个常规的文本文件中。将文件保存为 Sample.xml 并将其添加到项目中。这样我们就有了一个可以引用并解析的本地 XML 文件。
现在我们需要填充 Parser.m。Parser.m 将包含一个初始化方法以及三个最常用的 NSXMLParser 委托方法的实现。让我们从初始化方法开始,并将列表 2 中显示的代码添加到 XMLParser.m 中。
列表 2 Parser.m 初始化器
-init { if(self == [super init]) { parser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Sample" ofType: @"xml"]]]; [parser setDelegate:self]; [parser parse]; } return self; }
这里,我们将使用一个指向我们之前导入到项目中的 Sample.xml 文件的文件 URL 来初始化我们的 NSXMLParser 解析器。NSURL 是一个拥有各种初始化器的大类。在这种情况下,我们告诉它我们将提供一个文件 URL 的路径,也就是一个本地资源。完成之后,我们告诉 NSXMLParser 这个类将是解析器的委托,最后,我们通过发送 parse 消息告诉 NSXMLParser 我们准备好进行解析了。
一旦在 NSXMLParser 上调用了 parse 方法,解析器就会开始调用其委托方法。解析器读取 XML 文件的方式很像阅读拉丁/英文字符:从左到右,从上到下。虽然有很多委托方法,但我们将重点关注其中的三个。
§ - (void)parser:(NSXMLParser
*)parser didStartElement:(NSString *)elementName namespaceURI:(NSString
*)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary
*)attributeDict
虽然这个方法有很多参数传入,但对我们的目的来说,它实际上非常简单。当看到一个元素开始时,这个方法就会被调用。这意味着任何不带 / 的元素(在 <> 之间)。在这个方法中,我们首先打印出我们看到的开始元素,然后清空我们的 NSMutableString 元素。在实现新方法时你会看到,我们使用 element 变量作为一个字符串,在委托方法被调用时向其中添加内容。element 变量旨在只保存一个 XML 元素的值。所以,当一个新元素开始时,我们确保将它清空。请按照列表 3 所示,填写此委托方法的内容。
列表 3 NSXMLParser 方法
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict { NSLog(@"Started Element %@", elementName); element = [NSMutableString string]; } § - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
当看到一个元素结束时,这个方法就会被调用。这意味着当一个元素带有 / 时,这个方法就会被调用。当这个方法被调用时,我们的 NSMutableString 元素变量就完成了。我们将简单地打印出我们看到的值(见列表 4)。
列表 4 NSXMLParser 方法
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"Found an element named: %@ with a value of: %@", elementName, element); } § - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
当解析器看到元素开始和结束之间的任何内容时,这个方法就会被调用。我们将利用这个入口点来收集一个元素之间的所有字符;这是通过在我们的 NSMutableString 上调用 appendString 方法来完成的。每次调用此方法都这样做;到 didEndElement 方法被调用时,NSMutableString 就将是完整的。在这个方法中,我们首先确保我们已经初始化了我们的 NSMutableString 元素,然后我们追加所提供的字符串,如列表 5 所示。
列表 5 NSXMLParser 方法
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string if(element == nil) element = [[NSMutableString alloc] init]; [element appendString:string]; }
现在剩下的就是创建我们 Parser 的一个实例并看它运行了。转到 Parser_ProjectAppDelegate.m,并将列表 6 中显示的代码添加到已存在的方法中。
列表 6 初始化解析器
- (BOOL)application:(UIApplication *)application didFinishLaunchingWith Options:(NSDictionary *)launchOptions { // Override point for customization after app launch [window addSubview:viewController.view]; [window makeKeyAndVisible]; Parser *parser = [[Parser alloc] init]; return YES; }
如果你运行应用程序并调出终端窗口(shift + apple + r),应该会生成列表 7 中显示的输出。
列表 7 解析器输出
Parser_Project[57815:207] Started Element Author Parser_Project[57815:207] Started Element name Parser_Project[57815:207] Found an element named: name with a value of: Collin Ruffenach Parser_Project[57815:207] Started Element age Parser_Project[57815:207] Found an element named: age with a value of: 23 Parser_Project[57815:207] Started Element gender Parser_Project[57815:207] Found an element named: gender with a value of: male Parser_Project[57815:207] Started Element Books Parser_Project[57815:207] Started Element Book Parser_Project[57815:207] Started Element title Parser_Project[57815:207] Found an element named: title with a value of: Objective C for the iPhone Parser_Project[57815:207] Started Element year Parser_Project[57815:207] Found an element named: year with a value of: 2010 Parser_Project[57815:207] Started Element level Parser_Project[57815:207] Found an element named: level with a value of: intermediate Parser_Project[57815:207] Found an element named: Book with a value of: intermediate Parser_Project[57815:207] Found an element named: Books with a value of: intermediate Parser_Project[57815:207] Found an element named: Author with a value of: intermediate
你可以看到,使用 NSXMLParser 委托方法,我们成功地解析了我们 XML 文件中的所有信息。从这里开始,我们可以创建 Objective-C 对象来表示 XML,并在我们的整个应用程序中使用它。XML 处理是大多数从某种网络源获取内容的应用(如 Twitter 客户端、新闻客户端或 YouTube)中至关重要的一部分。
摘要
在为 iPhone 开发时,协议无处不在。它们是 Apple 提供的大多数类的基础设计决策之一。通过细致的编码,使用这些协议可以使你的应用程序高效且不易出错。通过正确理解和实现协议设计方法,你可以确保设计出一个优良的应用程序。
NSXMLParser 是一个边缘设计类,它遵循协议设计的原则,但没有显式地定义一个协议。一个 NSXMLParser 对象有一个名为 delegate 的参数,这个参数需要被定义。任何被定义为委托的对象都可以选择性地实现 20 个不同委托方法的集合。NSXMLParser 提供的委托方法可以处理基于 XML 和 DTD 文档的解析过程中的每一个环节。
![]() |
iPhone 和 iPad 实战 |
![]() |
iPhone 开发实践 |
![]() |
iPad 开发实践 |
最后更新:2011年8月27日