65.9K
CodeProject 正在变化。 阅读更多。
Home

Objective-C 基础 - NSXMLParser

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1投票)

2011 年 9 月 2 日

CPOL

7分钟阅读

viewsIcon

54077

来自 Objective-C Fundamentals 的章节摘录

image002.jpg 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 文档的解析过程中的每一个环节。

您可能还会对以下 Manning 图书感兴趣:

image003.jpg

iPhone 和 iPad 实战
Brandon Trebitowski, Christopher Allen, and Shannon Appelcline

image004.jpg

iPhone 开发实践
Bear P. Cahill

image005.jpg

iPad 开发实践
Paul Crawford

最后更新:2011年8月27日

© . All rights reserved.