2012-07-31 3 views
2

현재 저는 대형 XML 파일을 SQLite 백엔드로 처리해야하는 iPad 프로젝트를 진행하고 있습니다. 나는 현재이 작업을 TBXML 파서를 사용하고있다.iOS : SAX와 DOM 구문 분석을 결합하여

그래서 모든 논리가 제자리에 있고 일반적으로 TBXML 파서는 필요한 작업을 수행합니다. 지금 직면 한 문제는 XML 파일이 너무 커지고 메모리가 부족하다는 것입니다. 이 때문에 Alan Quatermain의 AQXMLParser과 같은 핵심 NSXMLParser와 같은 SAX 파서로 전환 할 생각입니다. 그러나 이것은 내가 DOM 트리가 제공하는 함수에 어느 정도 의존하는 현재의 모든 로직을 다시해야 할 것입니다. 이것은 내가하지 않을 일입니다.

그래서 내가 시도하고 싶은 것은 하이브리드 방식을 만드는 것입니다. 내 XML 구조를 감안할 때 이것이 가능해야합니다. 기본적으로 반복되는 "레코드"요소입니다. 각 레코드에는 반복되고 중첩 될 수있는 다양한 요소가 있습니다. 현재 나의 접근 방식에서는 문서를 구문 분석하고 각 레코드 요소를 데이터베이스로 처리하는 함수에 전달합니다. 이미 존재하는 것을 감안할 때 하이브리드 파싱 접근 방식에서이를 사용하고 싶습니다.

이것은 내가 달성하기를 원하는 것입니다. SAX 파서를 사용하여 문서를 트래버스합니다. 문서를 가로 지르는 동안 필자는 레코드 요소를 만듭니다. 레코드 요소를 완성 할 때마다 TBXML을 사용하는 기존 함수에 레코드 요소를 전달합니다. 그런 다음 SAX 파서는 다음 레코드 요소를 계속 작성합니다. 주요 목표는 다음과 같습니다. - 메모리 풋 프린트를 수정합니다 (가능한 한 작을 필요는 없지만 TBXML을 사용하는 경우 콘스탄트 또는 적어도 작아야합니다) - 성능을 유지하십시오. 다음과 같이

현재이를 구현하려면 :

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict{ 
    //Recreate record string each time record element is encountered 
    if([elementName isEqualToString:@"Record"]) record = [[NSMutableString alloc] init]; 
    //Write XML tag with name 
    [record [email protected]"<%@>, elementName]; 
} 

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{ 
    //Write XML content 
    [record appendString:string]; 
} 

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{ 
    //Write XML tag 
    [record [email protected]"</%@>, elementName]; 
    if([elementName isEqualToString:@"Record"]){ 
     //Parse record string into TBXML object 
     TBXML * tbxmlRecord = [TBXML tbxmlWithXMLString:record]; 
     //Send it to the TBXML record processor 
     [self processElement:tbxmlRecord.rootXMLElement]; 
    } 
} 

내가이 일을해야한다고 생각하지만, 문자열을 사용하는 더러운 느낌. 또한 파서가 새로운 레코드 요소에 도달 할 때 레코드 문자열이 너무 빨리 덮어 쓰이지 않을지에 대한 우려가 있습니다.

내 질문은 이것이 올바른 접근 방법인가, 아니면 내가 찾고있는 것을 성취 할 수있는 더 좋은 방법이 있다면?

편집 : 저는이 접근 방식을 구현했으며 매우 잘 작동합니다. 내가 마주 친 딸꾹질은 소스 파일이 UTF-8로 인코딩되어 있지 않으면 부분적인 결과 만 얻는다는 것입니다. 그러나 내가 이것을 고칠 때 모두 잘된다. 그래도 메모리 사용량은 그리 좋지 않습니다. 그러나 아마도 그것이 할 수있는 것을 취할 것입니다. 더 많은 테스트를 실행해야합니다 ...

+0

코드에 오타가있는 것으로 보입니다. 코드를 업데이트 할 수 있습니까? 그것은 도움이 될 것입니다 – Chrizzz

답변

1

일반적으로 접근 방식은 나에게 잘 들립니다. 당신의 솔루션이 성능 문제없이 당신을 위해 일한다면 나는 문자열 처리에 대해 너무 걱정하지 않을 것입니다. 원하는 경우 응용 프로그램의 프로필을 작성하여 얼마나 많은 CPU 시간이 낭비되는지 확인할 수 있습니다.

좀 더 최적화 된 것을 원한다면 원래 버퍼의 바이트 오프셋을 제공하는 SAX 파서를 찾아서 null이 아닌 종료 된 C 문자열로 작업 할 수있는 DOM 구문 분석기와 결합 해보십시오 . 나는 이것이 C 또는 C++ 라이브러리로 전환해야한다는 것을 의미한다고 믿는다. 나는 당신이 시도하고있는 것과 막연하게 유사한 (거대한 파일에 포함 된 XML 청크) 무언가를 위해 rapidxml을 사용했다.

+0

좋아, C (++) 라이브러리를 사용하여 내가 편안하게 뭔가되지 않습니다. 그래서이 버전을 구현하고 그것이 어떻게 진행되는지 살펴 보겠습니다. – Deddiekoel

+0

실적 측면에서 보면 괜찮을 것이라고 생각하지만 문자를 제대로 벗어 났는지 확인하십시오 (예 :텍스트 문자열에 '>'가 표시되면 어떻게됩니까?) 또한 위의 스 니펫은 특성 등을 처리하지 않지만 사용자가 입력을 제어 할 수 있다고 가정합니다. – Krumelur

+0

XML 자체는 매우 간단합니다. CDATA 블록이 없습니다 (문제가 아니더라도 구현할 수있는 또 다른 위임 방법). 문자를 이스케이프 처리하는 것은 좋은 지적입니다! – Deddiekoel

관련 문제