[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()을 호출합니다. 결과는 아래와 같습니다.

사용자 삽입 이미지

“[C++] XML 파서, CMarkup”에 대한 26개의 댓글

  1. xml parser에 관한 정보를 찾다가 오게되었네요 좋은 정보 얻어갑니다^^ CMarkup 이용해서 xml에서 정보 가져오는 부분 구현해 봐야 겠네요^^ 그럼 새해 복 많이 받으시고 행복한 하루 하루 보내세요^^

  2. xml 파싱으로 검색하다가 들어왔습니다.
    덕분에 생각보다 쉽게 문제를 해결했어요.
    좋은 정보 감사합니다~~^_^

  3. 안녕하세요 해당 강좌를 보고 조금 어설프게라도 따라했는데 잘 되지 않는 부분이 있어서 문의드려요~ 간단하게 작성했는데.. 실행결과는 아무것도 나오질 않네요 ㅠㅠ
    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 이걸 꼭 써야 하던데 안쓰면 에러가나더라구요
    어떻게 해야 그냥” ” 이런식으로 사용할 수 있나요 ?

    1. 글쎄요.. MCD_T 매크로를 사용은 처음봅니다만.. 프로젝트 속성 중 사용하는 캐릭터를 멀티바이트 모드로 하면.. 단순히 “..” 만으로 될테고.. 유니코드라면.. L”..”인가.. 아니면 T”..”인가로 하면 될텐데요..

  4. 각 함수인자가 유니코드로 되어 변환 에러(error C2664)가 나오는데 이는 어떻게 해결해야 할까요? L 붙이면 printf 에서 에러가 발생하는데;;ㄷㄷ

    1. 유니코드 문자에 함수가 따로 존재합니다.. printf인 경우 wprintf 문을 사용하셔야 합니다..

  5. 혹시 라이센스 문제는 어떻게 되는건지 알수 있을까요??
    CMarkup Parser 파일안에 들어있는 evaluationlicense.txt 이것 읽어봐도 잘 이해가 안가네요;;;

  6. CMarkup은 push-pop 구조라서 프로그래밍하기가 수월해서 좋더군요. 다만, 제가 필요하던 주요기능들은 모두 사용버젼에서만 지원하더라구요. 여하튼 주어진 함수들로 필요한 기능은 구현했는데 한가지 아쉬운 것은 indentation 기능이었습니다. 그래서, 다음과 같이 다른 클래스를 사용해서 저장만 하고 있습니다. 참조하세요.
    CXml myXML;
    myXML.LoadXml( (LPCTSTR) m_strXML );
    myXML.SaveWithFormatted(lpszPathName, _T(“UTF-8”) ); ///default is UTF-8
    myXML.Close();

  7. 라이센스..
    본 라이브러리는 테스트 용으로만 사용할 수 있고,
    배포할 경우 개발자로부터 라이센스를 구입해야 함.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다