2013-08-11 2 views
0

이 질문은 자주 묻는 질문 일지 모르지만 거의 모든 질문을 읽었지만 내 경우에 대한 해결책을 찾지 못했습니다. 파싱 된 데이터를 NSMutableDictionary에 저장할 계획입니다. 파서가 정상적으로 작동합니다. 로그를 얻으면 모든 데이터를 분석합니다. 문제는 마지막 항목이 NSDictionary에만 저장된다는 것입니다. 내가 잘못한 방법으로 사전을 배치했다는 것을 짐작할 수 있지만 저장을위한 더 나은 솔루션을 찾을 수 없습니다. 나는 요소의 이름과 텍스트를 보유하기 위해 사전을 사용합니다. enter image description hereXML 구문 분석 된 데이터를 NSMutableDictionary에 저장 우수 사례

+0

모범 사례는 JSON을 사용하는 것입니다. – iiFreeman

+0

구현할 웹 서비스는 XML 파일 만 제공합니다. – Ben

답변

1

문제의 원인은 당신이 적어도 한 번 당 호출됩니다 parser:foundCharacters: 각 호출하여 사전을 다시 인스턴스화이다 : 이것은 내 XML 구조가

@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; 
    } 
} 

입니다 : 여기 내 코드입니다 텍스트가있는 요소. 당신이 할 수있는 한 가지는 과 같을 때마다 parser:didStartElement:...으로 사전 인스턴스화를 이동하고, parser:didStartDocument:에 가변 배열을 인스턴스화 한 다음 parser:didEndElement:...에 요소 이름이`@ "시간표"인 경우 배열에 추가 할 수 있습니다.

이것의 예는 다음과 같다 :

Parser.h :

#import <Foundation/Foundation.h> 

@interface Parser : NSObject <NSXMLParserDelegate> 

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

@end 

Parser.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] 

그런 다음 당신은 당신의 파서 콜백에서 변경 가능한 사전의 사용을 폐기 할 수있다.

+0

친애하는 Carl, 문제의 원인을 알고 있습니까? 마지막 요소가 저장하는 이유는 무엇입니까? 나는 또한 NSArray (addObject)로 시도했지만 같은 문제가 발생했습니다. – Ben

+0

@Ben 방금 다른 해결책을 포함하도록 답변을 업데이트했습니다. –

+0

파서 초기화 메소드에서 사전의 인스턴스를 옮겼습니다. 마지막 요소 대신 마지막 레코드를 저장합니다. 예를 들어 지난 번에 마지막 요소 인 을 저장했습니다. 그러나 이제는 6 원소를 포함하는 마지막 을 저장합니다. 파서가 4 시간표를 파싱하는 동안입니다. 내 솔루션을 사용하여 Dictionary에 모두 저장하는 모든 솔루션? – Ben