Iphone 将XML解析数据保存到NSMutableDictionary最佳实践

Iphone 将XML解析数据保存到NSMutableDictionary最佳实践,iphone,ios,objective-c,xml,nsxmlparser,Iphone,Ios,Objective C,Xml,Nsxmlparser,这个问题可能经常被问到,但我几乎阅读了所有的问题,却无法为我的案例找到解决方案。 我计划将解析后的数据保存到NSMutableDictionary中。解析器工作正常,若我得到一个日志,它会显示所有解析的数据。问题是最后一项只保存在NSDictionary中。我猜我把字典放错了地方,但我想不出更好的保存方法。我使用字典来保存元素的名称和文本。这是我的密码: @implementation Parser @synthesize currentElementPointer, rootElement;

这个问题可能经常被问到,但我几乎阅读了所有的问题,却无法为我的案例找到解决方案。 我计划将解析后的数据保存到NSMutableDictionary中。解析器工作正常,若我得到一个日志,它会显示所有解析的数据。问题是最后一项只保存在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结构:

问题的根源在于,每次调用
解析器:foundCharacters:
时都会重新实例化字典,对于包含文本的元素,至少会调用一次。只要
elementName
等于
@“时间表”
,就可以将字典实例化移动到
parser:didStartDocument:
,然后在
parser:didestartDocument:
中实例化一个可变数组,如果elementName为“@”时间表,则在
parser:didEndElement:…
中实例化一个可变数组,将其添加到数组中

这方面的示例如下所示:

Parser.h:

#import <Foundation/Foundation.h>

@interface Parser : NSObject <NSXMLParserDelegate>

- (void)parseData:(NSData *)data;

@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>
但是,您已经构建了文档树,可能是出于其他目的,因此您可以在解析结束时重新使用它来构建词典。例如,如果您只想为每个时间表使用字典,您可以使用伪代码执行如下操作:

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]

然后您可以放弃在解析器回调中使用可变字典。

亲爱的Carl,您知道问题的原因吗?为什么最后一个元素只保存?我也用NSArray(addObject)尝试过,但同样的问题也发生了。我在Parser init方法中移动了字典的实例化。它保存最后一条记录,而不是最后一个元素。例如,上次保存最后一个元素时。但现在它保存了包含6个元素的最后一个元素。这是当解析器解析4时间表时。使用我的解决方案,有什么解决方案可以保存字典中的所有内容吗?那个字典会是什么样子?所有元素,如果用作字典中的键,都会相互覆盖-这就是为什么我建议在解析时间表元素时使用可变数组来存储每个字典。反馈:将我的代码替换为你的代码,它可以完美地工作。稍后,通过一个简单的for(NSArray中的NSDictionary),我可以访问字典的成员以用于我的应用程序。非常感谢。最佳实践是使用JSON,我想我计划实现的Web服务只提供xml文件。
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]