XML과 관련해서 관심을 갖고 있는 방식 중 한가지는 DOM, SAX와 비견될만한 XPP(xml pull parser)라는 방식이다. 실은 이 방식을 C++에 접목해보기 위해 xpp라는 테스트용 프로젝트를 만들었었는데, 이원구님의 XML C++ Library 프로젝트 소개 를 읽다가 문득 생각이 났다.

XPP는 SAX와 유사하지만, 다른 방식이다. SAX는 보통 parse()를 호출하면, 파싱을 수행하면서 이벤트가 발생할때마다 등록된 이벤트 핸들러를 호출해 주는 방식으로 정보를 전달하게 된다. 어떻게 보면, 사용자 코드가 각 이벤트를 SAX파서로부터 push받는다고 볼 수도 있다. XPP는 이와는 다르게 사용자 코드가 각 이벤트를 XPP파서로부터 땡겨온다. (pull)

백번말해 무엇하랴. 대충 슈도 코드를 보자.


xml_pull_parser xpp;
xpp.parse(data.begin(), data.end());

xml_event evt;

while(xpp)
{
xpp >> evt; // (1)
std::cout << evt.name() << std::endl; std::cout << evt.value() << std::endl; if(evt1.is_element_start()) { std::cout << "Element Start!!" << std::endl; } } [/cpp] 중요한 포인트는 xpp >> evt1; – 바로 (1)줄 – 이다. xpp.parse()를 통해 받아온 데이터를 쭉 보다가 XML관련이벤트 (요소 시작, 요소 끝, 속성, 텍스트 등등)을 만나면 해당 이벤트의 정보가 evt객체에 담기게 된다. 즉, >> 연산자가 parser로 부터 이벤트를 끌어오는 역할을 하는 것이다.

이 방식의 파서를 구현하는 방식은 여러가지가 있을 수 있다. SAX로 모든 이벤트를 쭉 받은다음, 이를 queue에 넣고 빼오는 방법이 가장 쉽게 생각할 수 있는 형태이고, 필자가 생각했던 방식은 이벤트를 하나 볼때마다 멈추었다가 가는 방식이었다. 이런 방식으로 작업을 하려니 머리가 좀 아파왔다. 뭐니뭐니해도 XML 문법분석기를 직접 짜고 싶지 않다는 귀차니즘이었다. 이때 구세주가 나타나셨으니…

바로 James Clark씨가 만든 너무나도 유명한 XML Parser인 Expat이다. SAX와 유사한 형태를 가지고 있는 녀석으로, C로 구현이 되어있다. 게다가 XML_StopParser라는 녀석을 지원한다. 훗. Resumable하게 멈출 수 있기 때문에 딱 좋았다. 실제로 테스트삼아 구현한 녀석은 parse()에선 파서 생성과 준비작업만 수행하고, operator>>()에서 Parser를 진행시키고, Expat에 등록한 이벤트 핸들러에서 Parser를 정지시키는 방식을 채택했었다. (정확히는, 첫이벤트는 parser()에서 만들어진다. 바로 Stop이 되지만..)

proof-of-concept 수준으로 작성한 코드는 http://crowmaniac.net/xpp.cpp에 올려두었다. 구동하려면 아마 Expat 2.0.0이상은 필요하지 않을까 싶다.

사실, 이 아이디어는 여기서 멈출 것은 아니다. xpp를 시작으로 해서, DOM형태의 트리구조를 지원하는 자료구조도 등장해야하고 템플릿을 이용해 XPath와 유사한 DSL을 구현해볼 생각도 있다. DSL을 파싱하는 비용을 컴파일 타임으로 넘겨버리겠다는 소박한 목표!

+1. 바쁘다. 하아.

XPP + C++

XPP + C++”에 대한 2개의 생각

  • 2006/10/11 11:18 오전
    고유주소

    저런게 있었군요. 근데 pull을 가지고 push를 만드는건 자연스러운데 push를 가지고 pull을 만드는건 좀 부자연스러운 느낌이네요. Expat이 Stop을 지원한다니 괜찮은 것 같기도 하고. 🙂

    그리고 저도 처음엔 XML 파싱을 좀 compile time에 해볼까 하는 막연한 생각을 했었는데 막상 구현하려니 XML 파싱에서 가장 중요한건 node들의 이름(string)인데 이 이름들은 당연하게도 runtime에서만 사용 가능한 것들이라 딱히 compile time에 할만한 일이 없더라고요. 🙂

    실제 XML 파싱 엔진도 만들어보고 싶으나 encoding이라는 벽이 너무 높네요. 먼저 char만 지원하는 것을 한번 만들어볼까 하는 생각중입니다. 🙂

    응답
  • 2006/10/11 6:16 오후
    고유주소

    저도 encoding이라는 막강한 벽에 부딪혔답니다.. T_T

    좀 부자연스럽긴 하지만, 최단시간에 최대효과를 내려면… 🙂
    하부 구현구조를 손쉽게 바꿀수 있는 형태로 작업해주면 큰 무리는 없으리라 봅니다.

    XPath를 분해해보면, 로직부분와 로직부분에서 비교로 사용될 값으로 크게 나눌수 있을 듯 한데요. bind와 유사하게 compile time과 run time을 절묘하게 오고가도록 짜면 불가능할 것 같진 않습니다.xpath expression을 파싱하는 시간을 줄이자는 것이지요. ^_^

    근데 요즘은 어째, 서로 커멘트를 다는 것보다 트랙백이 많은듯 합니다. 🙂

    응답

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.