본문 바로가기

C/Objective C/ios

아이폰 NSXMLParser 예제 따라하기

- XML 파서

XML 파서는 XML 파일을 읽어들이면, 앞에서부터 순서대로 분석하기 시작한다. 그러다가 ‘태그’나 ‘텍스 트’가 발견될 때마다 잘라내서 ‘이런 것이 발견되었습니다. 어떻게 처리할까요?’라고 물어오므로, 그때마다 처리할 방법을 프로그램에서 지정해주어야 한다(이를 델리게이트 메서드라고 한다).

다시 말해, ‘XML 파일을 읽고, 태그나 텍스트를 만나면 자르기’ 처리까지만 해주기 때문에 ‘태그나 텍스트 를 처리할 방법’을 프로그램으로 만들어야 한다.



1) URL 오브젝트 생성

XML 파일을 의미하는 URL 문자열로부터 URL 오브젝트(NSURL)를 생성한다.

NSURL *URL오브젝트 = [NSURL URLWithString: URL 문자열];

2) URL 오브젝트를 사용해 XML 파서 생성
XML 파서를 만들 때 initWithContentsOfURL에서 읽어들일 XML 파일의 URL 오브젝트를 설정한다.

NSXMLParser *XML파서 = [[NSXMLParser alloc] initWithcontentsOfURL: URL오브젝트];

3) delegate를 self로 지정
delegate를 self로 지정하면 XML 파서에서 해석을 할 때 통지 대상이 self(현재 프로그램을 작성하고 있 는 곳)가 된다. ‘태그’나 ‘텍스트’를 발견할 때마다 현재 프로그램을 작성하고 있는 곳에 마련된 델리게이 트가 호출되어 분석할 수 있게 된다.

4) 해석 시작
해석을 시작하려면 XML 파서의 parse 메소드를 실행해야 한다. 이 메소드를 실행하면 XML 파일을 읽어 들여 해석을 시작한다.

5) 해석을 시작하면 무엇을 할 것인가? parserDidStartDocument
해석을 시작했을 때 호출되는 델리게이트 메서드는 parserDidStartDocument이다.
주로 데이터 초기화나 해석 준비를 행한다. 해석 중에 ‘지금 조사하고 있는 태그’를 알아야 하므로, 이를 기억해 둘 변수 등을 준비하기도 한다.

6) 시작 태그를 발견하면 무엇을 할 것인가? didStartElement
태그의 이름은 elementName에 문자열 형태로 들어온다. 태그에 붙은 속성은 attributeDict에 사전 형식 으로 설정되므로, 키워드를 사용해 꺼낸다. 시작 태그를 발견한 다음에는 텍스트 요소를 읽어들이므로, 해 당 텍스트를 넣어둘 텍스트 버퍼 변수를 준비해둬야 한다.

7) 텍스트 요소를 발견하면 무엇을 할 것인가? foundCharacters
텍스트 요소는 string에 문자열 형태로 들어온다. 하지만 텍스트 요소는 반드시 한 번에 전부 읽힌다는 보 장이 없고, 몇 번으로 나뉘어 읽히기도 한다. 이 때문에 연속해서 텍스트 요소를 발견하면 그때마다 문자 열을 이어야 한다.

8) 종료 태그를 발견하면 무엇을 할 것인가? didEndElement
종료 태그를 발견하면 지금까지 읽어들인 텍스트 요소가 확정되었다는 의미가 된다.

9) 해석을 종료하면 무엇을 할 것인가? parserDidEndDocument 해석 종료 시에 처리가 필요하면 여기서 실행한다. 


- 화면 디자인

- NSXMLParser 예제 순 서

1. Xcode 실행

2. Single View Application
3. Project Name : “XMLTest”
4. storyboard에 Text View 위치
5. Assistant Editor로 Text View 드래그

6. “myTextView” 입력
7. ViewController.h 파일 편집

8. ViewController.h 파일 편집

@interface ViewController : UIViewController <NSXMLParserDelegate> { NSString *nowTagStr;

NSString *txtBuffer;

}
@property (weak, nonatomic) IBOutlet UITextView *myTextView; @end

- (void)viewDidLoad
{ [super viewDidLoad];

// 텍스트 뷰를 초기화 시키고 편집불가로 설정 myTextView.text = @"";

myTextView.editable = NO;
// URL을 지정해서 XML서버를 작성한다.

NSURL *myURL = [NSURL URLWithString:@"http://www.ymori.com/itest/test.xml"]; NSXMLParser *myParser = [[NSXMLParser alloc] initWithContentsOfURL:myURL]; myParser.delegate = self;
// 해석을 개시한다.

[myParser parse];

}
- (void)parserDidStartDocument:(NSXMLParser *)parser {

// 해석중인 태그를 초기화한다.
nowTagStr = [NSString stringWithString:@""];

}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName

namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
// 개시 태그가 "sweets"이면
if([elementName isEqualToString:@"sweets"]) {

} }

// 해석중인 태그로 설정
nowTagStr = [NSString stringWithString:elementName]; // 텍스트 버퍼를 초기화시킨다.
txtBuffer = [NSString stringWithString:@""];

// 텍스트 뷰에 태그 명과 price속성을 추가한다.
myTextView.text = [myTextView.text stringByAppendingFormat:

@"태그 명=[%@]\n 속성 price=[%@]",
elementName, [attributeDict objectForKey:@"price"]];

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // 해석중인 태그가 "sweets"이면

if ([nowTagStr isEqualToString:@"sweets"]) {
// 텍스트 버퍼에 문자열을 추가한다.

txtBuffer = [txtBuffer stringByAppendingString:string];

} }

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

// 종료태그가 "sweets"이면
if ([elementName isEqualToString:@"sweets"]) {

} }

- (void)viewDidUnload {

// 텍스트 뷰에 텍스트 버퍼의 문자열을 추가한다.
myTextView.text = [myTextView.text stringByAppendingFormat:

@"\n 요소=[%@]\n\n",txtBuffer];

[self setMyTextView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view. // e.g. self.myOutlet = nil;

}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations

return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); }

@end

일반적으로 프로그램에서 XML을 읽어들이면 자동으로 계층 구조까지 해석해주지만, NSXMLParser를 이 용할 때는 내용을 직접 해석해야 한다. 일반적인 전자동 해석 방법은 편리하기는 하지만 메모리 사용량이 많아지거나, 처리 내용이 많아져서 속도가 느려지는 등 하드웨어에 부담을 준다. 이 때문에 아이폰에서 NSXMLParser를 사용한다고 생각한다. 


- ViewController.m 소스코드

#import "ViewController.h"


@interface ViewController ()


@end


@implementation ViewController

@synthesize myTextView;


- (void)viewDidLoad

{

    [super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

myTextView.text = @"";

myTextView.editable = NO;

NSURL *myURL = [NSURL URLWithString:@"http://www.ymori.com/itest/test.xml"];

NSXMLParser *myParser = [[NSXMLParser alloc] initWithContentsOfURL:myURL];

myParser.delegate = self;

// 해석을 개시한다.

[myParser parse];

}


- (void)viewDidUnload

{

[self setMyTextView:nil];

    [super viewDidUnload];

    // Release any retained subviews of the main view.

}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {

    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);

} else {

    return YES;

}

}


-(void)parserDidEndDocument:(NSXMLParser *)parser{

//해석중인 태그를 초기화한다.

nowTagStr = [NSString stringWithFormat:@""];

}


-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{

// 개시 태그가 "sweets"이면

if([elementName isEqualToString:@"sweets"]){

//해석중인 태그로 설정

nowTagStr = [NSString stringWithString:elementName];

//텍스트 버퍼를 초기화시킨다.

txtButter = [NSString stringWithString:@""];

//텍스트 뷰에 태그 명과 price속성을 추가한다.

myTextView.text = [myTextView.text stringByAppendingFormat:   @"태그 =[%@]\n 속성 price=[%@] \n 요소 = [%@]",

elementName, [attributeDict 

objectForKey:@"price"]];

}

}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{

// 해석중인 태그가 "sweets" 이면

if ([nowTagStr isEqualToString:@"sweets"]) {

// 텍스트 버퍼에 문자열을 추가한다.

txtButter = [txtButter stringByAppendingFormat:string];

}

}

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{

// 종료태그가 "sweets"이면

if([elementName isEqualToString:@"sweets"]){

// 텍스트 뷰에 텍스트 버퍼의 문자열을 추가한다.

myTextView.text = [myTextView.text stringByAppendingFormat:

  @"\n 요소=[%@]\n\n",txtButter];

}

}


@end


- 실행화면