지난 번 글에서는 블로그 글에 붙어 있는 ISBN 태그를 가지고 알라딘 OpenAPI를 써서 ISBN에 해당되는 책 정보를 가지고 오는 일을 해 봤습니다. 알라딘에서 받아온 책 정보는 XML 방식인데, 이걸로는 바로 페이지에 뿌릴 수가 없으니까 XML에서 필요한 정보를 뽑아서 HTML 방식으로 뿌려 줘야겠죠. 이 글에서는 일단 XML에서 필요한 정보를 뽑아내는 일을 해 보겠습니다. XML을 요리하는 방법은 크게 두 가지로 나뉩니다.
  • DOM : XML 전체를 분석해서 트리 구조 자료로 만듭니다. 복잡한 XML 구조에서 필요한 자료를 손쉽게 XPath라는 디렉터리 방식으로 가져올 수 있다는 장점이 있지만, 모든 내용을 다 트리 구조로 만들기 때문에 메모리를 많이 잡아먹고, 필요한 정보가 전체 XML 파일 가운데 일부일 경우에는 XML을 파싱하는 시간이나 메모리 낭비가 심합니다.
  • SAX : XML을 이벤트로 보는 방식입니다. 예를 들어서, 어떤 엘리먼트를 시작하는 태그가 나오면, 'A라는 엘리먼트가 시작되었다'는 이벤트가 생기고, 끝나는 태그가 나오면, 'A라는 엘리먼트가 끝났다'는 이벤트가 생기는 식입니다. 메모리를 적게 잡아먹고 필요한 정보만 빠르게 챙길 수 있다는 장점이 있지만, DOM처럼 알아서 정보를 관리해 주는 방식이 아니라 내가 알아서 정보를 어떤 식으로 관리할 것인지를 정해야 하기 때문에복잡한 XML에서 이곳 저곳에 널려 있는 정보들을 많이 읽어야 할 때에는 오히려 귀찮고 불편합니다.
알라딘 OpenAPI가 돌려주는 책 정보 XML은 구조가 간단하고 일부만 써먹을 거니까 SAX 방식으로 요리하도록 하겠습니다. 위에서도 얘기했습니다만 SAX는 이벤트 구조입니다. 따라서 XML을 파싱하는 엔진이 필요할 때마다 어떤 이벤트를 만듭니다. 이 이벤트를 받아서 이벤트를 처리하는 클래스를 하나 만들어야 합니다. 알라딘 OpenAPI 예제를 보면 AladdinXMLParser.php라는 파일이 있습니다. 이 파일을 들여다보면 AladdinXMLParser라는 클래스가 정의되어 있는데, 이 클래스가 바로 SAX 엔진이 만드는 이벤트를 받아서 처리하는 일을 합니다. 하지만 이 클래스를 그대로 쓸 수는 없는데, 예제에서는 상품 API가 아닌 검색 API 결과를 처리하기 때문입니다. XML 구조가 좀 달라서 그대로 쓸 수는 없고, 이 클래스를 좀 고쳐보도록 하지요. 일단, 클래스를 보면 멤버 함수가 셋 있습니다.
  • AladdinXMLParser::startHandler()
    어떤 엘리먼트가 시작했을 때 그 이벤트를 받아줍니다.
  • AladdinXMLParser::endHandler()
    어떤 엘리먼트가 끝났을 때 그 이벤트를 받아줍니다.
  • AladdinXMLParser::cdataHandler()
    엘리먼트 안에 텍스트가 있을 때 그 이벤트를 받아줍니다.
먼저, 우리가 지난 번 글에서 OpenAPI로부터 받았던 결과 하나를 보도록 하겠습니다.

<?xml version="1.0" encoding="UTF-8"?>
<object xmlns="http://www.aladdin.co.kr/ttb/apiguide.aspx">
    <title>알라딘 상품정보 - 개가 된 CEO</title>
    <link>http://www.aladdin.co.kr/shop/wproduct.aspx?ISBN=8947526037</link>
    <language>ko</language>
    <copyright>&amp;copy;copyright 2006 aladdin</copyright>
    <pubDate>Tue, 16 Oct 2007 11:04:05 GMT</pubDate>
    <totalResults>1</totalResults>
    <startIndex>1</startIndex>
    <itemsPerPage>1</itemsPerPage>
    <query>isbn=981972</query>
    <version>20070901</version>
    <searchCategoryId>0</searchCategoryId>
    <searchCategoryName></searchCategoryName>
            <item itemId="981972">
                <title>개가 된 CEO - 알고 있는 모든 상식과 편견을 뒤집어라</title>
                <link>http://www.aladdin.co.kr/shop/wproduct.aspx?ISBN=8947526037</link>
                <author>조한필 지음</author>
                <pubDate>Wed, 26 Sep 2007 15:00:00 GMT</pubDate>
                <description>&lt;img src='http://image.aladdin.co.kr/coveretc/book/coveroff/8947526037_1.jpg'/&gt; 개가 된 CEO - 조한필 지음 &lt;br/&gt; 편견이 가지고 있는 문제점을 유쾌하고 지적하고, 편견이 사람 간의 커뮤니케이션에 어느 정도 영향을 미치는가를 흥미진진한 우화로 풀어낸다. 주인공인 CEO 고대명과 안하리가 편견이라는 막을 걷어내는 과정을 통해 편견이 우리의 성공과 자기계발을 저해함을 깨달을 수 있다.</description>
                <creator>aladdin</creator>
                <isbn>8947526037</isbn>
                <priceSales>9900</priceSales>
                <priceStandard>11000</priceStandard>
                <stockStatus></stockStatus>
                <mileage>1490</mileage>
<cover>http://image.aladdin.co.kr/coveretc/book/coversum/8947526037_1.jpg</cover>
                <categoryId>2948</categoryId>
                <categoryName>도서&gt;자기계발&gt;성공전략/성공학&gt;성공학 일반</categoryName>
                <publisher>한국경제신문</publisher>
                <customerReviewRank>8</customerReviewRank>
                    <bookinfo>
                        <subTitle>알고 있는 모든 상식과 편견을 뒤집어라</subTitle>
                        <originalTitle></originalTitle>
                        <itemPage>0</itemPage>                    
                        <toc><![CDATA[<p>1. 편견이 부른 위기에 봉착하다 <BR>
2. 편견의 늪에 빠지다 <BR>
3. 서로의 모습을 보다 <BR>
4. 복리의 마법, 미래를 위한 씨앗을 뿌려라 <BR>
5. 열등감이 오만과 편견을 낳다 <BR>
6. 겸손한 자세로 늘 위기에 대비하라 <BR>
7. 생각을 뒤집어야 삶도 변한다 <BR>
8. 첫 번째 편견의 벽을 허물다 <BR>
9. 명품이 될 만한 꿈을 가져라 <BR>
10. 좋은 평판의 씨앗을 뿌려라 <BR>
11. 사람을 움직이는 마음의 힘, 이해 <BR>
12. 두 번째 편견의 벽을 깨다 <BR>
13. 세상을 움직이는 성장엔진, 관심과 배려 <BR>
14. 세 번째 편견의 막을 거둬내다 <BR>
15. 마법의 벽을 깨다</p>]]></toc>
                    </bookinfo>
            </item>
</object>

여기서 눈여겨 볼 것은, XML의 루트 엘리먼트인 <object> 아래에 있는 <item>이란 엘리먼트입니다. 우리가 필요한 책 정보는 이 엘리먼트 안에 다 들어 있기 때문에 <item> 엘리먼트 안에 있는 정보 말고는 다 버릴 겁니다. 그리고 차례가 나와 있는 <toc> 엘리먼트 같은 것들도 쓰지 않을 거니까 버려야겠죠. 이 플러그인에서 쓸, <item>아래에 있는 엘리먼트는 다음과 같습니다.
  • <title>: 책 제목
  • <author> : 지은이에 대한 정보
  • <cover> : 책 표지 이미지 파일 URL
  • <publisher> : 출판사 정보
먼저, AladdinXMLParser::startHandler() 함수를 구경해 보죠.

function startHandler($parser, $element, $attr){
        if($element=="ITEM") { $this->inItems = TRUE; }
        $this->currentElement = $element;
}

이 함수는 인수로 $parser, $element, $attr 세 가지를 받습니다. 이 가운데서 $parser는 관심 가질 필요 없고, $element는 어떤 엘리먼트가 시작됐는지 그 이름을 가지고 있습니다. 곧, <title> 엘리먼트가 시작됐다면 "title"이란 문자열이 들어 있겠지요. $attr는 엘리먼트에 속성이 있으면, 그 속성 이름과 값을 배열 형태로 가지고 있습니다. 위 XML을 보면 <item> 엘리먼트가 "itemId"란 속성을 가지고 있습니다. 그러면 $attr은 { "itemId"=>"981972" }와 같은 배열이 되겠죠.

보는 김에 AladdinXMLParser::endHandler() 함수도 구경해 보죠.

function endHandler($parser, $element){
        if($element=="ITEM") {
            $this->itemList[] = $this->itemInfo;
            $this->itemInfo = array();
            $this->inItems = FALSE;
        }
        $this->currentElement = '';
}

endHandler()는 인자를 $parser와 $element를 가지고 있는데 startHandler() 함수와 똑같으니까 따로 설명 안 합니다.

예제 XML 파일을 보면 <object>이 시작된 다음, <object> 안에서 <item>이 시작되고, <item> 안에서 <title>이 시작됩니다. 그리고 그 반대 순서로 엘리먼트가 끝나겠죠. 그럼 이벤트가 생기는 순서는 아래와 같을 것입니다.
  1. startHandler() : $element = "object"
  2. startHandler() : $element = "item"
  3. startHandler() : $element = "title"
  4. endHandler() : $element = "title"
  5. endHandler() : $element = "item"
  6. endHandler() : $element = "object"
곧, startHandler()에서 $element를 보고, 우리가 정보를 뽑아낼 엘리먼트라면 뭔가 작업을 준비하고, 그렇지 않으면 그냥 무시하면 됩니다.

얘기가 많이 길어졌네요. 실제로 AladdinXMLParser 클래스를 어떻게 고칠 것인지는 다음 글로 넘겨야겠습니다.
Posted by MP4/13

BLOG main image
Drive with your sense. by MP4/13
Add to Technorati Favorites

카테고리

분류 전체보기 (1202)
광속질주 (205)
취생몽사 (160)
주지육림 (3)
독서삼매 (10)
음담패설 (28)
전광석화 (146)
우매상자 (66)
포장후면 (20)
악마사전 (6)
팔도유람 (20)
혹세무민 (508)
일상포착 (30)
Total : 3,964,680
Today : 302 Yesterday : 403