글 작성자: 써니루루

http://blog.naver.com/artmedia0?Redirect=Log&logNo=60028275704

지난해부터 국내에서 큰 인기를 얻고 있는 RSS는 웹2.0의 핵심 기술 가운데 하나. 특히 정보 생산자와 소비자 사이에 커뮤니케이션이 원활하게 이뤄질 때 RSS는 더 큰 의미를 가지게 된다. 일단 커뮤니케이션이 활발해지면 그 위에서 RSS 기반의 다양한 서비스들이 확장될 수 있기 때문이다. 여기서는 RSS 포맷에 대해 충분히 이해하고, 애플리케이션 기반의 간단한 RSS 브라우저를 만들어보자.


매일 아침 우리는 포털 사이트나 신문 홈페이지 등에서 최신 뉴스를 검색하고, MSDN이나 코드 프로젝트(Code Project)에 새로운 글들이 올라와 있는지를 훑어본다. 또한 자신의 블로그와 지인들의 블로그 등에 들러 흥미로운 콘텐츠 등을 읽게 된다. 이렇게 들려야 할 웹 사이트가 많아질수록 이리 저리 이동하는 것이 불편하고 찾아다니기가 귀찮아지는 게 사실이다.
그 런데 이런 일련의 행위는 최신의 글을 읽는다는 점에서 모두 비슷하다. 물론 그 내용이나 구성들도 대부분 크게 다르지 않다. 개발자는 물론이고, 심지어 일반인들도 이런 경우 여러 웹 사이트에 올라온 최신 글을 자신에게 자동으로 배송해 주는 툴이 있으면 좋겠다고 생각해 봤을지 모른다. 마치 아웃룩을 써서 배달된 메일을 읽는 것처럼, 특정 웹 사이트의 최신 글(뉴스, 블로그 콘텐츠 등)을 취합해 오프라인에서 아무 때나 그 글을 읽을 수 있게 해주는 프로그램을 꿈꾸게 되는 것이다.
다행스럽게도 이런 글과 그림으로 구성된 대부분의 콘텐츠들은 그 양식상의 공통점으로 인해 RSS라는 특정한 규칙(규약)이 적용될 수 있다. 따라서 여러 포털과 그들이 보유한 전용 웹 사이트에서는 RSS를 적용한 게시물들이 서비스 되고 있고, 그 수가 빠른 속도로 증가하는 추세다. 따라서 이 RSS를 충분히 이해하고 활용할 수 있으면 위와 같은 요구사항을 충족시켜 줄 툴을 개발할 수 있다. 필자도 자주 이슈로 떠오른 RSS에 대한 규약과 그 활용 방법에 대해 살펴보고, 간단한 RSS 뷰어(Viewer)를 만들어 봄으로써 이용자들의 다양한 요구사항을 충족시켜 줄 기초를 다지게 됐다. 독자들도 이 글을 통해 RSS를 보다 쉽게 이해하고 활용할 수 있는 계기가 되었으면 한다.


RSS의 개념과 쓰임새

RSS는 Rich Site Summary(혹은 RDF Site Summary, Really Simple Syndication)의 줄임 말로 뉴스나 블로그 등과 같이 콘텐츠가 자주 업데이트되는 사이트들이 업데이트된 정보를 쉽게 사용자들에게 제공하기 위해 만들어진 포맷이다. XML(Extensible Markup Language) 기반으로 되어 있고 제목, 내용, 날짜 등 배포에 필요한 최소한의 정보만으로 쉽게 작성할 수 있도록 구성되어 있다. 현재는 0.9, 1.0, 2.0 등 다양한 버전으로 서비스되고 있다. 이 RSS는 XML의 가장 성공적인 사례가 되어 수 만개의 웹 사이트에서 RSS를 이용할 수 있게 됐고, 그 수는 앞으로도 크게 늘어날 전망이다. 한편 새로운 RSS 표준으로 ATOM이 부상하고 있다. 이는 RSS의 단점인 버전 관리와 사용자의 임의 확장 제약 등을 보완한 새로운 표준인데 아직까지는 많이 활용되지 않으므로 여기서는 다루지 않는다.
한번쯤은 뉴스 사이트나 블로그 등에서 ‘RSS Feed’와 같은 아이콘을 본 기억이 있을 것이다. 이것은 곧 RSS 표준으로 서비스를 제공하고 있다는 의미다. 현재 RSS가 서비스에 많이 이용되는 곳은 다음과 같다.


- 뉴스 및 공지사항(매 시간 새로운 정보가 추가, 변경되는 뉴스와 신규 소식 서비스)
- 강좌(고객이 매번 사이트를 방문하여 규칙적으로 확인하지 않는 콘텐츠 서비스)
- 일정(주요 행사, 마감 일자, 휴일 정보)
- 검색 결과(관심 키워드에 대한 변경 및 신규 정보 조회 서비스)
- 메일링 리스트(주기적인 이메일로 서비스 한 내용 모음)
- 포드캐스팅을 통한 멀티미디어 파일 배포
- 입찰 정보, 채용 정보 등의 서비스


이외에도 RSS는 유연하고 간단한 포맷덕분에 다양한 형식의 콘텐츠를 배포하거나 활용하는 데 널리 쓰이고 있다.


RSS 활용의 실제

그럼 RSS의 장점을 십분 활용한 프로그램들에는 어떤 것들이 있을까? 여기서 대표적인 몇 가지를 소개한다. 물론, 이곳에 소개된 것 외에 많은 형태의 제품들이 상용 혹은 배포용으로 개발되어 인터넷상에서 이용되고 있다. 이런 프로그램들을 제대로 사용하면 독자들은 뉴스나 강좌, 그리고 블로깅 등을 이용하기 위해 인터넷을 헤매야 하는 불편을 크게 줄일 수 있다.


RSS 리더

RSS 프로그램들은 주로 뉴스 리더로 사용되고 있는데, RSS 문서(Document)를 읽을 수 있도록 뷰어, 아이템 리스트(Item List) 등으로 구성되어 있다. 손쉽게 콘텐츠를 분류해 요약된 글을 읽고, 흥미 있는 내용이면 원문으로 이동해 읽을 수 있는 기능을 제공한다. 또한 기존 항목에 대한 검색 기능을 추가한 제품도 있다. 국내의 ‘연모’(http://yeonmo.theple.com)와 ‘Xpyder’(http://www.xpyder.co.kr)가 대표적이다.


RSS 검색 엔진

인터넷 상에서 정리된 자료와 뉴스, 블로그 등을 모두 검색하는 엔진으로 웹 블로그 검색 엔진이 가장 대표적인 형태다. ‘FeedStar’(http://www.feedster.com)가 그 좋은 예다.


RSS 포맷의 역사

RSS 0.9는 넷스케이프(Netscape)사의 포털 서비스를 위한 목적으로 처음 개발됐다. 그 후 웹 블로그와 기타 다른 제품 등에 쓰기 위해 UserLand Software에서 더 간단한 형태의 RSS 0.91을 발표한다. 비슷한 시기에 RSS-DEV Working Group은 RDF(Resource Description Framework)를 기반으로 한 RSS 1.0을 제작했는데, 1.0 역시 RSS 0.9를 기본으로 삼았다. 그 후에 UserLand는 0.92, 0.93, 0.94에 이어 2.0을 발표했다. 실제 많이 쓰이는 버전은 심플함을 지향하는 RSS 0.9x(2.0) 버전과 확장성이 강한 RSS 1.0이다. 이들은 모두 동일한 기반 구조를 지녔고 XML을 바탕으로 한다.
그럼 지금부터 RSS의 버전별 특징을 간단히 살펴보자. 현재 가장 많이 사용되고 있는 2.0과 1.0 버전에 대한 특징을 실제 XML 소스를 통해 설명한다.


RSS 포맷 2.0

현재 가장 많이 사용되고 있다. 2.0을 만든 데이브 와이너(Dave Winer)가 하버드로 옮김에 따라 이 포맷의 소유권 역시 현재 하버드가 가지고 있다. 현재 http://blogs.law.harvard. edu/tech/rss에서 공식 배포되고 있다.
RSS 0.92까지는 아이템의 수가 제한되어 있었으나, RSS 2.0에 오면서 숫자 제한이 없어졌다. 아이템에 해당하는 모든 엘리먼트는 선택 사항이다(<표 3> 참조).


<리스트 1> RSS 2.0의 샘플

< ?xml version="1.0" encoding="euc-kr" ?>
< rss version="2.0">
< channel>
< title>아이헬퍼스< /title >
< link>http://www.ihelpers.co.kr< /link >
< description>아이헬퍼스< /description >
< language> ko< /language>
< lastBuildDate>Nov, 15 2004 08:13:29 GMT< /lastBuildDate>
< webMaster>smson@ihelpers.co.kr< /webMaster>
< item>
< title>RSS에 대하여< /title>
< link>http://www.ihelpers.co.kr/programming/lec.php?CMD=view&TYPE=1&IDX=245< /link>
< author>홍상영< /author>
< pubDate>Nov, 15 2004 08:13:29 GMT< /pubDate>
< category>강좌< /category>
< /item>
< item>
< title>게시판의 조회수를 정확하게 측정하자< /title>
< link>http://www.ihelpers.co.kr/programming/tipntech.php?CMD=view&TYPE=0&IDX=458< /link>
< author>홍상영< < /author>
< pubDate>Nov, 13 2004 01:33:48 GMT< /pubDate>
< category>Tip&Tech< /category>
< /item>
< item>
< title>글자와 이미지에 Blink 효과주기< /title>
< link>http://www.ihelpers.co.kr/programming/tipntech.php?CMD=view&TYPE=0&IDX=457< /link>
< author>홍상영< /author>
< pubDate>Nov, 12 2004 19:36:07 GMT< /pubDate>
< category>Tip&Tech< /category>
< /item>
< /channel>
< /rss>


Element Description Example
title 채널 명(사이트 명 또는 사이트 메뉴 명) 아이헬퍼스 - 새 소식
link 웹사이트(채널) URL 정보 http://www.ihelpers. co.kr
description 채널 설명(HTML은 쓰지않는 것이 좋다) 아이헬퍼스의 최신 소식

<표 1> 필수적인 채널 엘리먼트

Element Description Example
language 채널에 사용한 언어 - 사용 가능 언어 ko
copyright 채널 정보에 대한 권한 Copyright ⓒ 2000-2004
iHelpers.
manageing
Editor
채널 수정 담당자 이메일 주소 smson@ihelpers.co.kr
(홍길동)
webMaster 채널 관련 문의 담당자 이메일 주소 webmaster@ihelpers.co.kr
(홍길동)
pubDate 발행 일자 (RFC 822 형식) Nov, 15 2004 08:13:29 GMT
lastBuild 최종 변경 시간 Nov, 15 2004 08:13:29 GMT
category 채널이 속해 있는 카테고리 정보
(한 개 이상 가능)
공지사항
generator 채널 생성 프로그램 EditPlus
docs RSS 형식에 대한 문서 URL http://blogs.law.harvard.edu /tech/rss
cloud < cloud domain=”” port=””
path=”” registerProcedure=””
protocol=”” />
< cloud domain=”rpc.sys.com”
port=”80” path=”/RPC2”
registerProcedure=”
docs RSS 형식에 대한 문서 URL http://blogs.law.harvard.edu /tech/rss
myCloud.rssPleaseNotify”
protocol=”xml-rpc” />
ttl 채널 정보 갱신 주기(단위: 분) <ttl>60< /ttl>
image 이미지 정보 (GIF, JPEG 또는 PNG)
url 이미지 URL 정보
title 이미지 설명, HTML의 IMG
태그의 ALT 구문과 동일
width
height
넓이, 높이(단위: pixel) width, height (최대, 기본) - 144/88,400/31
rating PICS Rating
textInput CGI Script와 연계할 수 있는
Text Input 박스와 Submit
Button 기능
title Submit Button의 Label
description Input 박스설명
name Input 박스의 name
link CGI Script URL
skipHours skipHoursReader(Aggregator)가 채널
정보를 읽지 않길 원하는 시간
0 ~ 23
skipDays Reader(Aggregator)가 채널 정보를 읽지 않길 원하는 날짜 Monday,Tuesday,Wednes,Day...
<표 2> 선택적인 채널 엘리먼트

Element Description Example
title 아이템 제목 스파이더(Spider) 쫓아 버리기
link 아이템 URL 정보 http://www.ihelpers.co.kr/
programming/tipntech.php?
CMD=view&TYPE=0&IDX=452
iHelpers.
description
Editor
아이템에 대한 간략한 설명 robots.txt을 이용하여 (entity-encoded HTML) 스파이더 사용 제한하기
author 작성자 이메일 주소 smson@ihelpers.co.kr
(홍길동)
category 아이템 해당 카테고리(메뉴) 강좌
comments 아이템과 관련 있는 URL 정보
enclosure 아이템에 추가할 media 정보 < enclosure url=”http://www. scripting.com/mp3s/weather ReportSuite.mp3” length=” 12216320” type=”audio/mpeg” />
guid 유일한 식별문자 http://www.ihelpers.co.kr/ programming/tipntech.php? CMD=view&TYPE=0&IDX=452
pubDate 발행일자 Nov, 05 2004 22:53:27 GMT
source 출처 http://www.robotstxt.org/wc/robots.html
<표 3> 아이템 엘리먼트


RSS 포맷 1.0

RSS 1.0에서 RSS는 ‘RDF Site Summary’를 의미한다. RSS 1.0은 RDF를 사용하고 XML-Namespaces(RSS Modules)를 이용해 큰 마찰 없이 확장되도록 해준다. 모듈로써는 Dublin Core Module이 가장 잘 알려져 있다. RSS 1.0은 <리스트 2>의 샘플에서 보는 것처럼 RSS 0.9x (2.0)와 비슷하나 다음의 네 가지 부분에서 차이를 나타낸다.

  • < rdf:RDF>...< rdf:RDF> 엘리먼트를 사용한다.
  • RSS 1.0은 ‘http://purl.org/rss/1.0’ (Default Namespace), ‘http://purl.org/dc/elements/1.1/’(Dublin Core)과 같이 Namespace를 사용한다.
  • 아이템 엘리먼트가 채널 엘리먼트 밖에서 사용된다(RSS 0.9x의 경우는 채널 엘리먼트 내부에 있다).

    RDF란?

    XML은 비록 HTML보다 확장성이 뛰어나고 유연하지만, 시맨틱 웹의 표준 언어로 사용하기에는 한계가 있다. XML로 정의한 태그(Tag)는 사람들이 이해하는 데는 유리하지만, 기계가 자동적으로 그 의미를 해석하기는 어렵기 때문이다. 특히 태그 사이의 의미 연관성을 추론하기가 쉽지 않다. 임의로 만든 태그 사용법은 알 수 있어도 어떤 의미를 담고 있는 태그인지 파악하기가 어려운 게 XML의 단점이다.
    RDF(Resource Description Framework)는 이런 단점을 극복하기 위해 제시된 기술로, 특정 자원에 대해 숨은 자료를 설명하는 XML 기반의 프레임워크이다. RDF는 자원, 속성, 속성 값을 묶어 하나의 단위로 취급하는데, 정보를 구성하는 자원과 관련해 보다 세밀하게 설명하고 관계 파악을 용이하게 해 준다. 다시 말해, RDF를 이용하면 문서 내 각 요소의 의미와 문서 사이의 관련성을 표시하기가 쉬워지고, 기계간의 자동화 처리가 한결 수월해질 수 있다.


    <리스트 2> RSS 1.0의 샘플

    <rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns="http://purl.org/rss/1.0/"
    xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel rdf:about="http://www.xml.com/cs/xml/query/q/ 19">
    <title>XML.com</title>
    <link>http://www.xml.com/</link>
    <description>
    XML.com features a rich mix of information and services for the XML community.
    </description>
    <language>en-us</language>
    <items>
    <rdf:Seq>
    <rdf:li rdf:resource="http://www.xml.com/pub/a/ 2002/12/04/normalizing.html"/>
    <rdf:li rdf:resource="http://www.xml.com/pub/a/ 2002/12/04/som.html"/>
    <rdf:li rdf:resource="http://www.xml.com/pub/a/ 2002/12/04/svg.html"/>
    </rdf:Seq>
    </items>
    </channel>
    <item rdf:about="http://www.xml.com/pub/a/2002/12/04/ normalizing.html">
    <title>Normalizing XML, Part 2</title>
    <link>http://www.xml.com/pub/a/2002/12/04/normalizing.html</link>
    <description>
    In this second and final look at applying relational normalization techniques
    to W3C XML Schema data modeling,Will Provost discusses when not to normalize,
    the scope of uniqueness and the fourth and fifth normal forms.
    </description>
    <dc:creator>Will Provost</dc:creator>
    <dc:date>2002-12-04</dc:date>
    </item>
    </rdf:RDF> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/"> <item rdf:about="http://www.xml.com/pub/a/2002/12/04/ normalizing.html"> </item> </rdf:RDF>


    RSS 브라우저의 구현

    필자는 최근 DTV용 프로그램(니오젠 ‘레보’)의 일부 모듈을 개발한 경험이 있다. 이는 RSS 기반의 다양한 웹 콘텐츠를 리모컨만으로 쉽게 볼 수 있어 유용하지만, 이곳에서 예제로 쓰기에는 구현 내용이 지나치게 많다. 따라서 여기서는 독자들을 위해서 핵심 기능만을 간추려 구현한 별도의 유틸리티를 소개한다. 바로 RSS 브라우저(Browser)가 그것이다.
    지금부터 RSS를 읽어 표현해주는 프로그램을 본격적으로 구현해본다. 필자가 구현한 RSS 브라우저는 Xpyder와 비슷한 사용자 인터페이스를 가진 유틸리티로, RSS 서비스를 제공하는 웹 사이트를 등록해 Tree 형태로 좌측에 나열한다. 그곳의 서비스를 받아 리스트 형태로 뉴스 목록을 나타내고, 뉴스 목록 가운데 한 아이템을 선택하면 그 요약을 역시 리스트 형태로 우측 상단에 표시해준다. 또한 문서를 더블 클릭하면 원문 웹 사이트로 이동해 글을 볼 수 있도록 해준다. 이런 기능을 지닌 간단한 RSS 리더를 RSS 2.0을 써서 구현해보자.
    RSS를 읽는 기본 클래스 구조는 <그림 1>과 같다. 뉴스에 포커스를 두어 간단히 정리해 봤다.
    RSS는 크게 채널 정보와 그 채널의 아이템 정보로 나뉜다. 따라서 이에 대한 클래스를 정의했고, 이중 아이템 정보는 채널 정보의 하위 정보로써 무수히 존재할 수 있으므로 별도의 배열로 정의했다.


    RSS File 읽기

    구현한 코드 내용은 꽤 간단하므로 간단히 소스에 주석을 달아 설명한다. XML의 해석 엔진은 MSXML 4.0을 사용했으므로, 본 프로그램을 변경하거나 사용하려면 MSXML이 설치되어 있는지 확인해봐야 한다(MSXML은 MS 웹 사이트에서 쉽게 구할 수 있다). <리스트 3>은 RSS를 파싱하는 부분을 구현한 것이다.
    <리스트 3>은 RSS를 서비스하는 웹 사이트에서 RSS 파일을 다운로드 하는 것부터 시작한다. 다운로드 할 대상이 되는 RSS 서비스용 웹 사이트들을 많이 알아 두면 좋은 정보를 수집하는 데 도움이 될 것이다. XML 엔진을 사용할 수 있도록 MSXML Object를 생성하고, 다운로드 한 XML 파일을 읽도록 호출한다. 이렇게 하면 XML 엔진은 XML 파일을 DOM Object로 구성하여 관리하게 된다. MSXML 엔진의 사용은 본래 내용에서 벗어난 것이므로 여기서는 다루지 않지만, 그 사용법이 무척 간단하므로 소스만 봐도 쉽게 이해할 수 있다. 그럼 이제 파싱을 통해 필요한 데이터를 추출해 보자.
    RSS 파일은 일정한 데이터 구조가 반복적으로 저장된 형태이므로, 그것을 파싱하기 위해 재귀호출 방식을 사용했다. RSS의 정보는 헤더(Header)에 해당하는 채널 정보의 Source 구조체와 그 채널의 실제 데이터가 있는 Item 구조체로 나눠 정의했고, 그 구조체 별로 데이터를 채우는 방법은 <리스트 4, 5>에 나타나 있다. <리스트 5>는 RSS XML 상에 기록되어 있는 정보를 채널과 아이템으로 분리 구성된 Data 구조체에 읽어 들여 배열로 만드는 과정을 보여준다. 이렇게 읽어 들인 RSS 정보는 뷰어의 좌측 Tree View에 채널 별(섹션 별)로 붙여 보여주고, 우측 상단에는 아이템 리스트를 리스트 콘트롤(List Control)에 추가해 사용자가 보고 선택할 수 있도록 했다. 그 리스트 아이템은 각 기사의 제목, 생성일, URL, 설명 등에 대한 정보를 가지고 있고, 이를 선택하면 그 원본 기사가 있는 URL로 이동할 수 있도록 처리했다. 그 상세한 내용은 제공되는 별도의 소스 코드를 통해 확인하길 바란다. 코드의 나머지 부분은 화면상에 데이터를 표시해 주는 일반적인 과정으로 이해하면 된다.
    지금까지 RSS 콘텐츠에 대해 알아보고 사용 방법과 그 활용 예를 들었다. 각자의 입맛에 맞는 더 우수한 프로그램으로 만드는 일은 이제 독자의 몫이 될 것이다. 이와 관련해 궁금한 사항이 있거나, 더 많은 정보를 얻길 바란다면 필자의 블로그(http:// www.devzen.net/blog?npcc)에 방문하길 바란다.


    <리스트 3> MSXML을 이용한 RSS XML 문서 읽기

    #import "msxml4.dll" named_guids // MSXML 사용하기..

    // RSS를 서비스 하는 웹 사이트에서 XML을 다운로드해 Section 별로 Item을 채워 넣는다.
    void CFeed::BuildFromFile(CString strXMLFile)
    {
    CString strTmpFile = GetModuleFileDir() + _T("\\RSSReader.xml");
    // Step 0. Download XML File From Web site
    if ( URLDownloadToFile( NULL, strXMLFile, strTmpFile,0, NULL ) != S_OK )
    {
    AfxMessageBox( _T("Failed to download ") + strXMLFile );
    return;
    }
    // Step 1. XML 문서를 읽는다. 실패하면 return
    if ( m_pDoc != NULL )
    {
    m_pDoc->Release();
    m_pDoc = NULL;
    }
    // MS XML Object Interface를 구한다.
    if ( SUCCEEDED (CoCreateInstance(MSXML2::CLSID_DOMDocument,
    NULL,
    CLSCTX_INPROC_SERVER,
    MSXML2::IID_IXMLDOMDocument,
    reinterpret_cast<void**>(&m_pDoc))))
    m_pDoc->put_async( VARIANT_FALSE );

    // XML 파일을 읽어서 DOM을 구성한다.
    if ( m_pDoc->load( _bstr_t(strTmpFile) ) == VARIANT_FALSE )
    {
    // Failed to load XML Document, report error message
    AfxMessageBox( _T("Failed to load XML Document") );
    return;
    }
    // Step 2. 버전 정보를 읽고 유효한지 확인한다.
    // Step 3. XML에서 채널 노드를 돌면서 아래의 하위 Item을 읽는다.
    // title
    // link
    // description
    // language
    // copyright
    // webMaster
    // lastBuildDate
    // ttl
    // generator
    // Then go to image node, get the following items
    // title
    // url
    // link
    // width
    // height
    // description

    // Step 4. item 노드로 가서 아래의 정보를 읽는다.
    // title
    // description
    // link
    // author
    // category
    // pubDate
    // subject

    MSXML2::IXMLDOMNode *pNode = NULL;
    if ( SUCCEEDED(m_pDoc->QueryInterface(MSXML2::IID_IXMLDOMNode,
    reinterpret_cast<void**>(&pNode))))
    {
    IterateChildNodes(pNode);
    // XML의 각 Node별 파싱을 통해 값을 읽는다.
    pNode->Release();
    pNode = NULL;
    }
    // We are not using smart pointer, so we have to release it outself
    if ( m_pDoc )
    {
    m_pDoc->Release();
    m_pDoc = NULL;
    }
    }


    <리스트 4> RSS에서 사용하는 노드를 기준으로 파싱해 데이터 수집

    void CFeed::IterateChildNodes(MSXML2::IXMLDOMNode *pNode)
    {
    BSTR bstrNodeName;

    if ( pNode )
    {
    m_nDepth++;
    CString strOutput;
    pNode->get_nodeName(&bstrNodeName);

    //
    // Find out the node type (as a string).
    //
    BSTR bstrNodeType;
    pNode->get_nodeTypeString(&bstrNodeType);
    CString strType;
    strType = CString( bstrNodeType );
    SysFreeString(bstrNodeType);

    MSXML2::DOMNodeType eEnum;
    pNode->get_nodeType(&eEnum);

    CString strValue;
    BSTR bstrValue;
    switch( eEnum )
    {
    case MSXML2::NODE_TEXT:
    {
    // Text string in the XML document
    BSTR bstrValue;
    pNode->get_text(&bstrValue);
    strOutput = CString( bstrValue );
    SysFreeString(bstrValue);
    break;
    }
    case MSXML2::NODE_COMMENT:
    {
    // Comment in the XML document
    VARIANT vValue;
    pNode->get_nodeValue(&vValue);
    VariantClear(&vValue);
    break;
    }
    case MSXML2::NODE_PROCESSING_INSTRUCTION:
    {
    // Processing instruction
    strOutput = CString( bstrNodeName );
    break;
    }
    case MSXML2::NODE_ELEMENT:
    {
    // Element
    strOutput = CString( bstrNodeName );
    if ( strOutput == _T("rss") )
    {
    GetVersion( pNode );
    }
    else if ( strOutput == _T("copyright") )
    {
    pNode->get_text(&bstrValue);
    m_source.m_strCopyright = CString( bstrValue );
    }
    else if ( strOutput == _T("title") && m_nDepth == 4 )
    {
    pNode->get_text(&bstrValue);
    m_source.m_strTitle = CString( bstrValue );
    }
    else if ( strOutput == _T("link") && m_nDepth == 4 )
    {
    pNode->get_text(&bstrValue);
    m_source.m_strLink = CString( bstrValue );
    }
    else if ( strOutput == _T("description") && m_nDepth == 4 )
    {
    pNode->get_text(&bstrValue);
    m_source.m_strDescription = CString( bstrValue );
    }
    else if ( strOutput == _T("language") )
    {
    pNode->get_text(&bstrValue);
    m_source.m_strLanguage = CString( bstrValue );
    }
    else if ( strOutput == _T("webMaster") )
    {
    pNode->get_text(&bstrValue);
    m_source.m_strWebMaster = CString( bstrValue );
    }
    else if ( strOutput == _T("lastBuildDate") )
    {
    pNode->get_text(&bstrValue);
    m_source.m_strLastBuildDate = CString( bstrValue );
    }
    else if ( strOutput == _T("ttl") )
    {
    pNode->get_text(&bstrValue);
    m_source.m_strTtl = CString( bstrValue );
    }
    else if ( strOutput == _T("generator") )
    {
    pNode->get_text(&bstrValue);
    m_source.m_strGenerator = CString( bstrValue );
    }
    else if ( strOutput == _T("image") )
    {
    BuildImage( pNode );
    }
    else if ( strOutput == _T("item") )
    {
    BuildItem( pNode );
    }
    break;
    }
    case MSXML2::NODE_DOCUMENT:
    case MSXML2::NODE_DOCUMENT_TYPE:
    case MSXML2::NODE_DOCUMENT_FRAGMENT:
    case MSXML2::NODE_NOTATION:
    case MSXML2::NODE_ENTITY:
    case MSXML2::NODE_ENTITY_REFERENCE:
    case MSXML2::NODE_CDATA_SECTION:
    {
    // CData section
    strOutput = CString( bstrNodeName ) + _T(" - ") + CString( strType );
    }
    }
    SysFreeString(bstrNodeName);
    }

    // Any child nodes of this node need displaying too.

    MSXML2::IXMLDOMNode *pNext = NULL;
    MSXML2::IXMLDOMNode *pChild;
    pNode->get_firstChild(&pChild);
    while( pChild )
    {
    IterateChildNodes(pChild);
    pChild->get_nextSibling(&pNext);
    pChild->Release();
    pChild = pNext;
    }
    m_nDepth--;
    }


    <리스트 5> RSS정보를 수집용 구조체에 채움

    void CFeed::BuildItem(MSXML2::IXMLDOMNode *pNode)
    {
    MSXML2::IXMLDOMNode *pNext = NULL;
    MSXML2::IXMLDOMNode *pChild;
    CString strOutput;
    BSTR bstrNodeName;
    CFeedItem item;
    BSTR bstrValue;
    pNode->get_firstChild(&pChild);
    while( pChild )
    {
    pChild->get_nodeName(&bstrNodeName);
    strOutput = CString( bstrNodeName );
    if ( strOutput == _T("title") )
    {
    pChild->get_text(&bstrValue);
    item.m_strTitle = CString( bstrValue );
    }
    else if ( strOutput == _T("description") )
    {
    pChild->get_text(&bstrValue);
    item.m_strDescription = CString( bstrValue );
    }
    else if ( strOutput == _T("link") )
    {
    pChild->get_text(&bstrValue);
    item.m_strLink = CString( bstrValue );
    }
    else if ( strOutput == _T("author") )
    {
    pChild->get_text(&bstrValue);
    item.m_strAuthor = CString( bstrValue );
    }
    else if ( strOutput == _T("category") )
    {
    pChild->get_text(&bstrValue);
    item.m_strCategory = CString( bstrValue );
    }
    else if ( strOutput == _T("pubDate") )
    {
    pChild->get_text(&bstrValue);
    item.m_strPubDate = CString( bstrValue );
    }
    else if ( strOutput == _T("subject") )
    {
    pChild->get_text(&bstrValue);
    item.m_strSubject = CString( bstrValue );
    }

    pChild->get_nextSibling(&pNext);
    pChild->Release();
    pChild = pNext;
    }
    m_item.Add( item );
    }


  • 참고자료 1. http://blogs.law.harvard.edu/tech/rss
    2. http://www.mnot.net/rss/tutorial
    3. http://web.resource.org/rss/1.0/spec
    4. http://www.codeproject.com