NSXMLParser 的 ReactiveCocoa 扩展:使用 NSXMLParser 解析 XML 的简洁、基于流的 API。
定义了一个围绕 NSXMLParserDelegate 的包装器,废弃了需要实现复杂代理方法的需求。应用任何您想要的 ReactiveCocoa 魔法(请参阅NSXMLParserRACElement)
#import "NSXMLParser+ReactiveCocoa.h"
[[NSXMLParser rac_parseURL:url] subscribeNext:^(NSXMLParserRACElement *element) {
// Each element is passed as it's read
// TODO: Handle element
} error:^(NSError *error) {
// TODO: Handle error
} completed:^{
// TODO: Handle completion event
}];
以下 ReactiveCocoa 代码片段将按顺序加载每个 XML 文件,逐个解析它们,并将每个提取转换为自定义对象(任何值对象或您选择的 NSDictionary)(基于此单元测试)。
#import "NSXMLParser+ReactiveCocoa.h"
// Only parse element name from this list
NSSet *elementFilter = [NSSet setWithArray:@[@"title", @"itunes:author", @"enclosure", @"pubDate", @"link", // General
@"image", @"width", @"height", @"url", // Album art
@"item", @"itunes:subtitle", @"itunes:summary"]]; // Items
// Define filter block here to be used with each feed
ElementFilterBlock filterBlock = ^BOOL(NSString *elementName) {
return [elementFilter containsObject:elementName];
};
// Store signals for each parse job in this array.
NSArray *signals = @[[NSXMLParser rac_dictionaryFromURL:[NSURL URLWithString:@"http://feeds.twit.tv/ww.xml"] elementFilter:self.filterBlock],
[NSXMLParser rac_dictionaryFromURL:[NSURL URLWithString:@"http://feeds.twit.tv/sn.xml"] elementFilter:self.filterBlock]];
// [RACSignal -concat] creates a list of aforementioned signals an executes
// them *sequentially*. If you desire parallel execution, you could use one of
// the [RACSignal -conmbine..] methods.
[[[[RACSignal concat:signals] map:^NSDictionary*(NSDictionary *result) {
// The 'result' dictionary will contain the raw object graph for the XML
// [RACSignal -map:] provides a hook for you to transform this NSDictionary into any
// data type you want:
Podcast *podcast = [[Podcast alloc] init];
podcast.title = [result valueForKeyPath:@"title.text"];
return podcast;
}] collect] subscribeNext:^(NSArray *podcasts) {
// The 'podcasts' array contains each Podcast* object as mapped in the previous block
// [RACSignal -collect:] aggregates all values into a single NSArray.
// TODO: Use the data
} error:^(NSError *error) {
// TODO: Do something with this error
}];
您也可以自行解析 XML,使用 [RACSignal +rac_parseURL:]
方法。这是围绕 NSXMLParserDelegate 的 ReactiveCocoa 包装器。请参阅NSXMLParser+ReactiveCocoa.m 中的示例实现。
简而言之,这是您可以使用 -rac_parseURL:
API 的方法:
#import "NSXMLParser+ReactiveCocoa.h"
[[[NSXMLParser rac_parseURL:url] filter:^BOOL(NSXMLParserRACElement *element) {
// Filter non-applicable elements (optional)
return YES;
}] subscribeNext:^(NSXMLParserRACElement *element) {
// Each time an element is processed, it will be passed here.
if (element.phase == NSXMLParserRACElementPhaseOpen)
{
// Element tag was opened
// TODO: Handle this
}
if (element.phase == NSXMLParserRACElementPhaseData)
{
// Element's text or CData was read
// TODO: Use element.body
}
if (element.phase == NSXMLParserRACElementPhaseClose)
{
// Element was closed
// TODO: Handle this
}
} error:^(NSError *error) {
// TODO: Handle error
} completed:^{
// TODO: Handle completion event
}];