본문 바로가기
프로그래밍/iOS

iPhone libxml2 사용 하는 법

by 백룡화검 2011. 3. 24.

COCOA 에서 XML 파싱과 XPath queries를 위해 libxml2를 사용하기


NSXMLDocument는 Cocoa 에서 트리 기반의 일반적인 XML 파서 입니다. 하지만 iPhone에서 쓰려고 한다면,

이 클래스를 사용할 수 없습니다. 맥조차도, 때로 트리 기반의 파싱을 NSXMLDocument의 오버헤드 없이 쓰기를

원하기도 합니다. 이제 Cocoa 친화적인 트리기반의 파싱 플렛품인 libxml2를 사용하는가 보여 드리겠습니다.

소개

NSXMLDocument는 훌륭한 XML 파서이며, XML 생성도구 입니다. 애석하게도, 애플은 SDK에 포함하지 않았습니다.

애플은 NSXMLParser을 아이폰에 포함시켰습니다.

개인적으로 이벤트 기반의 NSXMLParser을 좋아하지 않습니다. 이 프로젝트에서 시간이 걸리며, 다루기 힘들다는

것을 알았습니다. 나역시 HTML을 먼저 깨끗이 정리하고, XML파서에 던져넣고 가장 빠른 퍼포먼스를 얻었습니다.

다행히, libxml2 이 아이폰에 존재하며, XML 파싱을 위해 이용하였습니다.

다른 개발자는 맥에서는 libxml2가 더 빠르며 메모리 효율도 더 높다고 합니다. 그래서 NSXMLDocument가 있음에도

불구하고, libxml2를 사용하는 이유가 여기 있다고 생각합니다.

libxml2의 단점

libxml2는 그 자체로는 심플합니다. 하지만 회사의 문서는 매우 복잡합니다. 헤더파일의 도움말은 매우 빈약합니다.

C로부터 시작되어 선언과 데이터 타입의 구조와 스타일이 Cocoa와 매우 다릅니다.

만일 Cocoa에서 libxml2를 사용하려면, 래퍼 클래스로 사용해야 합니다.

제안

내가 XML을 사용하는 방식이며, 해결책은 두가지 함수를 선언하는것입니다.

NSArray *PerformXMLXPathQuery(NSData *document, NSString *query);
NSArray *PerformHTMLXPathQuery(NSData *document, NSString *query);

NSData 타입은 NSString 쿼리 형태로 변경되며, NSDictionary의 NSArray형태로 노드가 반환됩니다.

두가지 리스트의 차이점은 xml데이터가 준비되었는지, 혹은 html 데이터가 준비되었는지 차이 입니다.

각 결과는 NSDictionary 가 되며 다음과 같은 구조를 가집니다.

nodeName — NSString : 노드명
nodeContent — NSString : 본문
nodeAttributeArray — NSDictionary의 NSArray 이며 두개의 키를 가집니다.
  attributeName(NSString)와 nodeContent(NSString)
nodeChildArray — NSArray의 자식노드 (이 노드와 같은 형태
)

구현

전체 버전을 아래 첨부파일에서 받습니다.


이 구현은 매우 직관적이며, 다음처럼 보일겁니다.

NSArray *PerformXMLXPathQuery(NSData *document, NSString *query)
{
    xmlDocPtr doc;
   
    /* Load XML document */
    doc = xmlReadMemory(
        [document bytes], [document length], "", NULL, XML_PARSE_RECOVER);
   
    if (doc == NULL)
    {
        NSLog(@"Unable to parse.");
        return nil;
    }
   
    NSArray *result = PerformXPathQuery(doc, query);
    xmlFreeDoc(doc);
   
    return result;
}

PreformHTMLXPathQuery 과 오직 차이점이라곤 xmlReadMemory대신 htmlReadMemory를 부른다는 것입니다.

쿼리 자체는 전체 함수를 내부에서 처리합니다.

NSArray *PerformXPathQuery(xmlDocPtr doc, NSString *query)
{
    xmlXPathContextPtr xpathCtx;
    xmlxpathObjectPtr xpathObj;

    /* Create XPath evaluation context */
    xpathCtx = xmlXPathNewContext(doc);
    if(xpathCtx == NULL)
    {
        NSLog(@"Unable to create XPath context.");
        return nil;
    }
   
    /* Evaluate XPath expression */
    xmlChar *queryString =
        (xmlChar *)[query cStringUsingEncoding:NSUTF8StringEncoding];
    xpathObj = xmlXPathEvalExpression(queryString, xpathCtx);
    if(xpathObj == NULL) {
        NSLog(@"Unable to evaluate XPath.");
        return nil;
    }
   
    xmlNodeSetPtr nodes = xpathObj->nodesetval;
    if (!nodes)
    {
        NSLog(@"Nodes was nil.");
        return nil;
    }
   
    NSMutableArray *resultNodes = [NSMutableArray array];
    for (NSInteger i = 0; i < nodes->nodeNr; i++)
    {
        NSDictionary *nodeDictionary = DictionaryForNode(nodes->nodeTab[i], nil);
        if (nodeDictionary)
        {
            [resultNodes addObject:nodeDictionary];
        }
    }

    /* Cleanup */
    xmlXPathFreeObject(xpathObj);
    xmlXPathFreeContext(xpathCtx);
   
    return resultNodes;


작업 결과는 매우 심플합니다 이 문서에 XPath 쿼리를 위한 공간을 만들며, XPath 쿼리를 요청하고, NSDictionary

객체로부터 DictionaryForNode 함수를 결과와 함께 모든 노드에서 얻고, 깨끗이 청소합니다.

DictionaryForNode 함수의 구현은 보여드리지 않습니다. 만일 전체 솔류션을(위의 링크) 다운받으면 어떻게 정리

되는지 보실 수 있습니다. 매우 힘들게 구현했습니다.

프로젝트 설정

libxml2.dylib를 프로젝트에 추가합니다.(Framework 섹션에 놓으면 안됩니다.) 맥에서는 /usr/lib/libxml2.dylib 에서

찾을 수 있으며, 아이폰에서는

/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.0.sdk/usr/lib/libxml2.dylib

에서 찾을 수 있습니다.

libxml2는 .dylib 임에도(프레임웍과 친화적이진 않습니다.) 한가지 이상 작업을 더 해줘야 합니다.

프로젝트 빌드 셋팅에 가서(Project->Edit Project Settings->Build) "Search Paths"를 찾고 "Header Search Paths"

안에 다음 경로를 추가합니다.

$(SDKROOT)/usr/include/libxml2

결론

이 방법으로 아이폰에 대해 코코아와 친화적인 XPath쿼리를 얻을 수 있습니다.

나는 본문의 데이터로 테스트 해봤습니다. - XML CDATA 데이터는 어떤 작동을 할지 모릅니다.

원문 : http://cocoawithlove.com/2008/10/using-libxml2-for-parsing-and-xpath.html

'프로그래밍 > iOS' 카테고리의 다른 글

여러가지 Util  (0) 2011.03.29
xcode 라이브러리 모음  (0) 2011.03.24
앞뒤 공백문자 제거(Trim white space)  (0) 2011.03.24
iOS에서의 XML 파싱 - NSXMLParser  (0) 2011.03.21
touchXML을 이용한. xml파싱하기...  (0) 2011.03.21