这个问题可能经常被问到,但我已经阅读了几乎所有的问题,但无法找到适合我的情况的解决方案。 我计划将解析后的数据保存到 NSMutableDictionary 中。解析器工作正常,如果我收到日志,它会显示已解析的所有数据。问题是最后一个 Item 仅保存在 NSDictionary 中。我可以猜测我将字典放置在错误的方法中,但我无法找到更好的保存解决方案。我使用字典来保存元素的名称和文本。这是我的代码:
@implementation Parser
@synthesize currentElementPointer, rootElement;
@synthesize dictionary;
-(id)initParser
{
if(self = [super init]) {
tvc = (TimeTableViewController*)[[UIApplication sharedApplication]delegate];
APUAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
context = [appDelegate managedObjectContext];
[self deleteAllObjects:@"TimeTable"];
}
return self;
}
#pragma mark -
#pragma mark PARSER
-(void)parserDidStartDocument:(NSXMLParser *)parser
{
self.parsing = YES;
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:@"intake"])
{
NSString *name = attributeDict[@"name"];
self.parsing = [name isEqualToString:[self sendIntakeToParser]];
}
if(![self isParsing]) return;
if(self.rootElement == nil) {
self.rootElement = [[List alloc]init];
self.currentElementPointer = self.rootElement;
} else {
List *newList = [[List alloc]init];
newList.parent = self.currentElementPointer;
[self.currentElementPointer.subElements addObject:newList];
self.currentElementPointer = newList;
}
self.currentElementPointer.name = elementName;
self.currentElementPointer.attributes = attributeDict;
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(![self isParsing]) return;
if([self.currentElementPointer.text length] > 0) {
self.currentElementPointer.text = [self.currentElementPointer.text stringByAppendingString:string];
} else {
self.currentElementPointer.text = string;
}
dictionary = [[NSMutableDictionary alloc]init];
[dictionary setObject:[self.currentElementPointer text] forKey:[self.currentElementPointer name]];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([self isParsing])
{
self.currentElementPointer = self.currentElementPointer.parent;
} else if ([elementName isEqualToString:@"intake"])
{
self.parsing = YES;
}
}
这是我的 xml 结构:
最佳答案
问题的根源在于,每次调用 parser:foundCharacters:
时都会重新实例化字典,每个包含文本的元素至少会调用一次。您可以做的一件事是,每当 elementName
等于 @"timetable"
时,将字典实例化移动到 parser:didStartElement:...
,实例化在 parser:didStartDocument:
中创建一个可变数组,然后在 parser:didEndElement:...
中,如果 elementName 是 `@"timetable",则将其添加到数组中。
下面显示了一个示例:
解析器.h:
#import <Foundation/Foundation.h>
@interface Parser : NSObject <NSXMLParserDelegate>
- (void)parseData:(NSData *)data;
@end
解析器.m:
#import "Parser.h"
@interface Parser ()
@property (nonatomic,strong) NSMutableArray *timetableDictionaries;
@property (nonatomic,strong) NSMutableDictionary *currentTimetableDictionary;
@property (nonatomic,copy) NSString *currentElementName;
@end
@implementation Parser
- (void)parseData:(NSData *)data
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
}
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
self.timetableDictionaries = [NSMutableArray array];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
self.currentElementName = elementName;
if ([elementName isEqualToString:@"timetable"]) {
self.currentTimetableDictionary = [NSMutableDictionary dictionary];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (self.currentElementName) {
NSString *existingCharacters = self.currentTimetableDictionary[self.currentElementName] ? : @"";
NSString *nextCharacters = [existingCharacters stringByAppendingString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
if ([nextCharacters length] > 0) {
self.currentTimetableDictionary[self.currentElementName] = nextCharacters;
}
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"timetable"]) {
[self.timetableDictionaries addObject:self.currentTimetableDictionary];
self.currentTimetableDictionary = nil;
}
self.currentElementName = nil;
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(@"timetable dictionaries = %@",self.timetableDictionaries);
}
@end
我使用以下文件测试了上面的类:
<weekof week="2013-07-29">
<intake name="APCF1304">
<timetable>
<date>SOME DATE</date>
<time>SOME TIME</time>
<lecturer>SOME LECTURER</lecturer>
</timetable>
<timetable>
<date>ANOTHER DATE</date>
<time>ANOTHER TIME</time>
<lecturer>ANOTHER LECTURER</lecturer>
</timetable>
</intake>
</weekof>
它给出了以下输出:
2013-08-11 11:50:03.205 MyParser[25368:c07] timetable dictionaries = (
{
date = "SOME DATE";
lecturer = "SOME LECTURER";
time = "SOME TIME";
},
{
date = "ANOTHER DATE";
lecturer = "ANOTHER LECTURER";
time = "ANOTHER TIME";
}
)
但是,您已经构建了文档树,可能是出于其他目的,因此您可以在解析结束时重新使用它来构建字典。例如,如果您只需要每个时间表的字典,您可以用伪代码执行如下操作:
dictionaries = [new mutable array]
element = self.root
[extract dictionaries from: element to:dictionaries]
implementation of extractDictionariesFrom:element to:dictionaries:
if any subelement has non-nil text:
item = [new mutable dictionary]
for each sub element:
item[element name] = element text
[add item to dictionaries]
else
for each subelement:
[extract dictionaries from: subelement to: dictionaries]
然后您可以在解析器回调中放弃使用可变字典。
关于iphone - 将 XML 解析数据保存到 NSMutableDictionary 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18170809/