아이폰에서 XML을 파싱하기 위해서는 여러가지 방법이 있다.
라이브러리를 이용하는 방법(touchXML,KISSXML등등)과 NSXMLParser를 이용하는 방법이 있다.
아이폰이 아닌 그냥 맥개발에서는 NSXMLDocument가 있어서 편하게 쓸수 있다고 하는데 아무튼.. 그냥 힘든방법으로 가자.
c#으로 개발했을때는 시리얼라이즈가 있어서 클래스만 만들면 자동으로 xml을 만들고 파싱하고 아주 편했다.
하지만 Iphone Objective-C는........ㅠ.ㅠ
일단 WCF Rest서비스를 만들어서 DB내용을 XML로 동적으로 뿌려주기 위한 서비스를 만들었다.
그래서 파싱할 xml은 이렇다.
<ArrayOfHugeBoardInfo xmlns="http://schemas.datacontract.org/2004/07/HugeBoardService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<HugeBoardInfo>
<Date>2010-02-02T00:00:00</Date>
<Description>hi</Description>
<Name>leejaedong</Name>
<Title>hi</Title>
<idx>1</idx>
</HugeBoardInfo>
일단 이 데이터를 저장할 클래스부터 만들자 C#이랑 비슷하다 여기까지는
@interface HugeBoardData : NSObject {
NSString* _idx;
NSString* _name;
NSString* _title;
NSString* _description;
NSString* _date;
}
@property(copy) NSString* idx;
@property(copy) NSString* name;
@property(copy) NSString* title;
@property(copy) NSString* description;
@property(copy) NSString* date;
@end
헤더에 이렇게 넣고
@implementation HugeBoardData
@synthesize idx= _idx;
@synthesize name= _name;
@synthesize title= _title;
@synthesize description = _description;
@synthesize date= _date;
@end
구현부에 구현을 하자
그다음 일단 Xml을 파싱을 전문적으로 하는 class를 만들자.
@interface HugeBoardXmlParser : NSObject<NSXMLParserDelegate> {
NSXMLParser *parser;
NSMutableArray *_hugeBoardDataArray;
NSMutableArray *_elementStack;
}
@property (nonatomic,retain) NSXMLParser *parser;
-(NSMutableArray*)parseContent: (NSURL*) url;
@end
이름을 HugeBoardXmlParser라 만들고 NSXMLParser 델리게이트를 참조 하였다.그리고 XML을 parser할 NSXMLParser와 xml파일의 모든 데이터를 저장할 hugeboardDataArray그리고 elementStack이라고 해서 한줄한줄 읽을때마다 저장해서 이게 어떤 노드에 있고 어떤값지를 임시로 저장해놓는 array이다
#import "HugeBoardXmlParser.h"
#import "HugeBoardData.h"
@implementation HugeBoardXmlParser
@synthesize parser;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:@"HugeBoardInfo"] == TRUE)
{
HugeBoardData *data = [HugeBoardData new];
[_elementStack addObject:data];
}
else if([elementName isEqualToString:@"idx"] || [elementName isEqualToString:@"Name"] || [elementName isEqualToString:@"Title"] || [elementName isEqualToString:@"Description" ] || [elementName isEqualToString:@"Date"])
{
NSString *element = [NSString stringWithString:elementName];
[_elementStack addObject:element];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:@"HugeBoardInfo"] == TRUE)
{
HugeBoardData *data =(HugeBoardData*)[_elementStack lastObject];
[_hugeBoardDataArray addObject:data];
[_elementStack removeLastObject];
}
else if([elementName isEqualToString:@"idx"] || [elementName isEqualToString:@"Name"] || [elementName isEqualToString:@"Title"] || [elementName isEqualToString:@"Description" ] || [elementName isEqualToString:@"Date"])
{
[_elementStack removeLastObject];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
//trim을 쓰자면 이걸 쓰고 안하면 그냥 string 값을 넣어도 된다.
NSCharacterSet *characterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString *trimmedValue = [string stringByTrimmingCharactersInSet:characterSet];
if([trimmedValue length] == 0)
{
return;
}
id element = [_elementStack lastObject];
if([element isKindOfClass:[NSString class]])
{
NSUInteger count = [_elementStack count];
NSUInteger index = count -2;
id parentElement = [_elementStack objectAtIndex:index];
HugeBoardData *data = (HugeBoardData*)parentElement;
if([element isEqualToString:@"idx"])
{
data.idx = trimmedValue;
}
else if([element isEqualToString:@"Name"])
{
data.name = trimmedValue;
}
else if([element isEqualToString:@"Title"])
{
data.title = trimmedValue;
}
else if([element isEqualToString:@"Description"])
{
data.description = trimmedValue;
}
else if([element isEqualToString:@"Date"])
{
data.date = trimmedValue;
}
}
}
-(NSMutableArray*) parseContent:(NSURL*) url
{
NSXMLParser* xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[xmlParser setDelegate:self];
_hugeBoardDataArray =[NSMutableArray arrayWithCapacity:1024];
_elementStack = [NSMutableArray arrayWithCapacity:1024];
[xmlParser parse];
return _hugeBoardDataArray;
}
@end
이것은 구현부이다.
하나씩 알아보자.일단 파싱을 하기 위해서 필요한 3가지 델리게이트가 있다.첫째 이부분이다.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:@"HugeBoardInfo"] == TRUE)
{
HugeBoardData *data = [HugeBoardData new];
[_elementStack addObject:data];
}
else if([elementName isEqualToString:@"idx"] || [elementName isEqualToString:@"Name"] || [elementName isEqualToString:@"Title"] || [elementName isEqualToString:@"Description" ] || [elementName isEqualToString:@"Date"])
{
NSString *element = [NSString stringWithString:elementName];
[_elementStack addObject:element];
}
}
초반 엘리먼트를 읽는다. 우린 이것을 일단 모두 저장한다. 어디에? elementStack에
그다음 호출되는것은 이거다
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
//trim을 쓰자면 이걸 쓰고 안하면 그냥 string 값을 넣어도 된다.
NSCharacterSet *characterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString *trimmedValue = [string stringByTrimmingCharactersInSet:characterSet];
if([trimmedValue length] == 0)
{
return;
}
id element = [_elementStack lastObject];
if([element isKindOfClass:[NSString class]])
{
NSUInteger count = [_elementStack count];
NSUInteger index = count -2;
id parentElement = [_elementStack objectAtIndex:index];
HugeBoardData *data = (HugeBoardData*)parentElement;
if([element isEqualToString:@"idx"])
{
data.idx = trimmedValue;
}
else if([element isEqualToString:@"Name"])
{
data.name = trimmedValue;
}
else if([element isEqualToString:@"Title"])
{
data.title = trimmedValue;
}
else if([element isEqualToString:@"Description"])
{
data.description = trimmedValue;
}
else if([element isEqualToString:@"Date"])
{
data.date = trimmedValue;
}
}
}
실제 Value값을 여기서 얻을수가 있는데 아까 처음에 _elementStack에 저장했던 값을 분석해서 HugeBoardData라는 아까 만든 저장형 클래스에 담는다. trimmedValiue대신에 string을 넣어도 된다.
마지막으로 호출되는것은 이것이다.
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:@"HugeBoardInfo"] == TRUE)
{
HugeBoardData *data =(HugeBoardData*)[_elementStack lastObject];
[_hugeBoardDataArray addObject:data];
[_elementStack removeLastObject];
}
else if([elementName isEqualToString:@"idx"] || [elementName isEqualToString:@"Name"] || [elementName isEqualToString:@"Title"] || [elementName isEqualToString:@"Description" ] || [elementName isEqualToString:@"Date"])
{
[_elementStack removeLastObject];
}
}
여기서하는것은 아까 foundCharacters에서 저장한 HugeBoardData를 _HugeBoardDataArray에 저장한다. 여기까지가 한텀이 끝난것이다. 이제 아마 같은 방식으로 계속 한텀한텀씩 저장해서 모든 xml데이터를 _hugeBoardDataArray에 저장할것이다.한텀이 끝났으면 다음텀을 위해서 _elementStack을 삭제한다. 이렇게 3개의 델리게이트 메소드가 계속 호출되면서 반복된다.
이제 이 모든기능을 작동되게 만드는 외부에서 호출 당하는 메소드를 보자
-(NSMutableArray*) parseContent:(NSURL*) url
{
NSXMLParser* xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[xmlParser setDelegate:self];
_hugeBoardDataArray =[NSMutableArray arrayWithCapacity:1024];
_elementStack = [NSMutableArray arrayWithCapacity:1024];
[xmlParser parse];
return _hugeBoardDataArray;
}
여기보면 xmlParser를 작동되게 하고 모든 xmlData를 포함하는 _hugeBoardDataArray를 리턴한다.
그래서 외부에서 사용할려면
NSURL *XMLURL =[NSURL URLWithString:@"http://192.168.10.3:9090/hugeboardService/getboardinfo"];
HugeBoardXmlParser* parser = [[HugeBoardXmlParser alloc] init];
NSMutableArray *hugeboardArr = [parser parseContent:XMLURL];
이렇게 하면 된다. 그럼 hugeBoardArr에 모든 데이터가 저장될것이다.
'iPhone App' 카테고리의 다른 글
[iphone] WCF Rest Service로 HttpRequest하는법과 한글 인코딩 (0) | 2011.07.22 |
---|---|
[iphone] tableview에서 cell을 표시할때 KeyValue쓰지 않고 표시하기 (0) | 2011.07.22 |
[iphone] navigationItemButton 추가하는법 (0) | 2011.07.19 |
[iphone] NSMutableArray may not respond to ObjectForKey란 에러메세지 (0) | 2011.07.18 |
[iphone] UITabbarController에서 탭을 선택했을때 항상 Reload, Refresh하기 (0) | 2011.07.18 |