반응형

http://www.gisdeveloper.co.kr/499




[C++] XML 파서, CMarkup 

XML 데이터를 쓰고 읽기 위해서 인터넷을 검색하던 차에 속도를 강점으로 내세우면서 STL 만을 사용하여 플랫폼 이식에도 뛰어난 오픈소스를 찾았는데요. 바로 CMarkup 입니다. 다운로드 사이트는 http://www.firstobject.com/ 이구요. 사용해 보니 XML의 charset도 지원하여 더욱 믿음이 가는 오픈소스였습니다. XML을 처리할 일이 있다면 한번 사용해 보시기 바랍니다.

추후 이 오픈소스를 다시 사용할 때를 대비하여 사용 방법을 정리해 정리차원에서 올려봅니다.

컴파일 시 주의할 사항은... CMarkup은 MFC의 CString와 STL의 string에 대한 문자열 타입을 사용하며 기본적으로 CString을 사용합니다. 플랫폼에 독립적인 구성을 위해서 STL을 사용하는것이 좋기 때문에 전처리에서 MARKUP_STL를 정의해줘야 합니다. 이 전처리 정의는 프로젝트의 속성 페이지에서 해줌으로써 전역적으로 적용되도록 해야 합니다. 아래의 코드는 XML을 쓰는 예제 코드입니다. 윈도우즈 계열의 개발툴인 VS2008로 작성했습니다.




#include "stdafx.h"

#include "../Markup.h"


int _tmain(int argc, _TCHAR* argv[])

{

    CMarkup xml;


    xml.AddElem( "ORDER" );

    xml.AddChildElem( "ITEM" );

    xml.IntoElem();

    xml.AddAttrib("type", "A");

    xml.AddChildElem( "SN", "132487A-J" );

    xml.AddChildElem( "NAME", "crank casing" );

    xml.AddChildElem( "QTY", "1" );

    xml.OutOfElem();


    xml.AddChildElem( "ITEM" );

    xml.IntoElem();

    xml.AddAttrib("type", "C");

    xml.AddChildElem( "SN", "434417F-Y" );

    xml.AddChildElem( "NAME", "kully casing" );

    xml.AddChildElem( "QTY", "2" );

    xml.OutOfElem();


    std::string csXML = xml.GetDoc();


    printf("%s", csXML.c_str());


    return 0;

}


결과는 다음과 같습니다.

사용자 삽입 이미지

AddElement를 통해 엘리먼트를 만들고, 해당 엘리먼트의 자식을 추가하기 위해 AddChildElem을 사용하거나 먼저 IntoElem을 호출한 후 다시 AddElement를 사용합니다.

이제 반대로 위와 같은 XML 데이터를 읽어 보도록 하겠습니다. 먼저 위의 결과를 파일로 저장해 놓고 그 파일을 읽어 데이터를 추출하는 예제를 들어 보겠습니다. 예를 들어... 아이템(ITEM)의 이름(NAME)과 수량(QTY)을 읽어 보도록 하겠습니다. 위의 XML 문자열의 경우 아이템의 개수는 총2개이므로 2개가 검색될 것입니다. 다음이 이 예제와 부합되는 코드입니다.




CMarkup xml;
xml.Load("d:/data.xml");

while ( xml.FindChildElem("ITEM") )
{
    xml.IntoElem();

    xml.FindChildElem( "NAME" );
    std::string csSN = xml.GetChildData();
    xml.FindChildElem( "QTY" );
    int nQty = atoi(xml.GetChildData().c_str());

    xml.OutOfElem();

    printf("%s, %d\n", csSN.c_str(), nQty);
}



먼저 XML 데이터를 가지고 있는 파일을 Load 매서드를 이용해 읽습니다. 다시 반복문을 사용하여 루트 엘리먼트의 자식 ITEM 엘리먼트를 검색하기 위해 FindChildElem을 사용합니다. 그러면 해당되는 자식 엘리먼트가 추출됩니다. 해당되는 자식 엘리먼트의 자식 엘리먼트를 읽기 위해 IntoElem() 함수를 사용한 뒤에 원하는 엘리먼트(NAME, QTY)를 검색하기 위해 FindChildElem을 호출하고 실제로 값을 읽기 위해서 GetChildData 매서드를 호출합니다. 다 읽은 후 OutOfElem()을 호출합니다. 결과는 아래와 같습니다.

사용자 삽입 이미지







 Commented by 산비둘기 at 2009/11/16 12:09  r x
바쁜업무에 시간내서 글들 정리 하시느라 수고가 많으십니다 . 
좋은 정보 얻고 갑니다 . ^^ 
Replied by 김형준 at 2009/11/16 22:55 x
산비둘기님, 별 말씀을요. 제 스스로에게도 큰 도움이 되고 있습니다.
 Commented by DarkKiss at 2010/01/04 16:13  r x
xml parser에 관한 정보를 찾다가 오게되었네요 좋은 정보 얻어갑니다^^ CMarkup 이용해서 xml에서 정보 가져오는 부분 구현해 봐야 겠네요^^ 그럼 새해 복 많이 받으시고 행복한 하루 하루 보내세요^^ 
Replied by 김형준 at 2010/01/04 17:02 x
네, 이 글이 도움이 되시면 좋겠습니다. 새해 복 많이 받으세요~
 Commented by 나무 at 2010/04/24 09:13  r x
좋은 정보 감사합니다...^^ 
Replied by 김형준 at 2010/04/26 15:59 x
댓글 감사드립니다.
 Commented by JHoney at 2010/06/15 23:38  r x
감사합니다 정말 좋은 정보네요 ^-^ 
Replied by 김형준 at 2010/06/16 18:59 x
저 역시 지금도 잘 활용하고 있는 xml 처리 라이브러리입니다. 도움되셨다니 저도 좋네요!
 Commented by 미아 at 2010/07/06 01:06  r x
xml 파싱으로 검색하다가 들어왔습니다.
덕분에 생각보다 쉽게 문제를 해결했어요. 
좋은 정보 감사합니다~~^_^ 
Replied by 김형준 at 2010/07/07 10:16 x
네, 도움되셨다니 좋습니다!
 Commented by 울티 at 2010/08/16 18:30  r x
안녕하세요 해당 강좌를 보고 조금 어설프게라도 따라했는데 잘 되지 않는 부분이 있어서 문의드려요~ 간단하게 작성했는데.. 실행결과는 아무것도 나오질 않네요 ㅠㅠ
CMarkup xml;

xml.AddElem(MCD_T("Test"));
xml.AddChildElem(MCD_T("a"));
xml.IntoElem();
xml.AddAttrib(MCD_T("type"),MCD_T("a"));
xml.AddChildElem(MCD_T("sss"),MCD_T("2344"));
xml.OutOfElem();

std::wstring csXML = xml.GetDoc();

printf("%s",csXML.c_str());

이게 전부인데 아무런 결과가 나오지 않네요; 
아 그리고 저는 문자열 앞에 MCD_T 이걸 꼭 써야 하던데 안쓰면 에러가나더라구요 
어떻게 해야 그냥" " 이런식으로 사용할 수 있나요 ? 
Replied by 김형준 at 2010/08/18 18:42 x
글쎄요.. MCD_T 매크로를 사용은 처음봅니다만.. 프로젝트 속성 중 사용하는 캐릭터를 멀티바이트 모드로 하면.. 단순히 ".." 만으로 될테고.. 유니코드라면.. L".."인가.. 아니면 T".."인가로 하면 될텐데요..
 Commented by 나쁜남자 at 2010/08/20 18:11  r x
많은 도움이 됐습니다. 
Replied by 김형준(Dip2K) at 2010/08/20 18:31 x
댓글, 감사합니다!
 Commented by 굳굳 at 2010/11/07 22:21  r x
정말 간단하군요 ^^ 
Replied by 김형준 at 2010/11/08 21:27 x
도움이 되셨길 바랍니다!
 Commented by 빵집상인 at 2010/11/13 20:56  r x
올ㅋ 유용한데요~?
Load메서드로 로드하려면 *.xml파일만 읽어들일수있는겐가요? 
Replied by 김형준 at 2010/11/16 15:14 x
파일 확장자는 큰 의미가 없고.. 파일 내용이 xml 포맷이면 됩니다.
 Commented by 김진 at 2010/12/08 17:54  r x
각 함수인자가 유니코드로 되어 변환 에러(error C2664)가 나오는데 이는 어떻게 해결해야 할까요? L 붙이면 printf 에서 에러가 발생하는데;;ㄷㄷ 
Replied by 김형준(Dip2K) at 2010/12/09 22:36 x
유니코드 문자에 함수가 따로 존재합니다.. printf인 경우 wprintf 문을 사용하셔야 합니다..
 Commented by 이효진 at 2011/01/05 10:17  r x
XML 검색하다 찾아왔습니다. 좋은 정보 감사합니다 ^^ 종종 찾아오게 될거 같아요 ㅎㅎ 
Replied by 김형준 at 2011/01/05 19:34 x
도움이 되셨다니 저도 기분이 좋습니다. ^^
 Commented by 안병규 at 2011/04/04 13:31  r x
혹시 라이센스 문제는 어떻게 되는건지 알수 있을까요??
CMarkup Parser 파일안에 들어있는 evaluationlicense.txt 이것 읽어봐도 잘 이해가 안가네요;;; 
Replied by 김형준 at 2011/04/06 17:11 x
상용버전에 사용하려면 구입하라는 의미인듯한데요..
 Commented by 한창영 at 2011/04/13 10:28  r x
CMarkup은 push-pop 구조라서 프로그래밍하기가 수월해서 좋더군요. 다만, 제가 필요하던 주요기능들은 모두 사용버젼에서만 지원하더라구요. 여하튼 주어진 함수들로 필요한 기능은 구현했는데 한가지 아쉬운 것은 indentation 기능이었습니다. 그래서, 다음과 같이 다른 클래스를 사용해서 저장만 하고 있습니다. 참조하세요.
CXml myXML;
myXML.LoadXml( (LPCTSTR) m_strXML );
myXML.SaveWithFormatted(lpszPathName, _T("UTF-8") ); ///default is UTF-8
myXML.Close(); 



반응형

+ Recent posts