'rss parser'에 해당되는 글 1건

  1. 2008/03/03 RSSParser Class 제작하기 - 아이헬퍼스
이번 시간 부터는 뉴스,블로그등의 사이트에서 제공하는 RSS 서비스를 읽는 RSS Reader를 제작하는 방법에 대하여 설명하도록 하겠습니다. RSS 서비스를 제공하는 것이 그렇게 어렵지 않지만 해당 서비스를 읽는 프로그램을 작성하는 것은 그렇게 쉽지 않습니다. PHP로 웹메일 솔루션을 구현하려고 할때 메일발송 부분은 간단하나 메일을 읽는 부분은 POP3,IMAP 프로토콜과 통신하고 인코딩(Base64,QP등)된 메일정보에 대한 디코딩처리와 같이 어려운 부분이 많은 것 처럼 말입니다.

다음은 RSS Reader의 주요 작업 순서입니다.

  1. RSS URL 정보로 HTTP 프로토콜 통신을 하여 정보를 얻어 온다.
  2. RSS 정보를 해당 버전에 맞게 파싱한다.
  3. 파싱된 정보를 Client( Web,Application )에 맞게 정보를 출력해 준다.

해당 강좌에서는 먼저 XML 기반의 RSS 문서를 파싱하는 방법에 대하여 설명하도록 하겠습니다.

아래의 rss.xml 파일은 아이헬퍼스에서 제공하는 RSS 서비스의 내용입니다. 여러분은 해당 구문을 어떻게 파싱하시겠습니까? 이번 강좌의 목표가 아래의 rss.xml 파일을 파싱하여 배열로 저장하는 것입니다.

<?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, 17 2004 06:51:58 GMT</lastBuildDate>
<webMaster>smson@ihelpers.co.kr</webMaster>
<item>
<title>RSS 강좌 - RSSWriter Class 제작 및 활용</title>
<link>http://www.ihelpers.co.kr/programming/lec.php?CMD=view&TYPE=1&IDX=247</link>
<author>손상모</author>
<pubDate>Nov, 17 2004 06:51:58 GMT</pubDate>
<category>강좌</category>
</item>
<item>
<title>RSS 강좌 - RSS 0.9x,2.0 그리고 1.0</title>
<link>http://www.ihelpers.co.kr/programming/lec.php?CMD=view&TYPE=1&IDX=246</link>
<author>손상모</author>
<pubDate>Nov, 16 2004 09:59:12 GMT</pubDate>
<category>강좌</category>
</item>
<item>
<title>RSS 강좌 - 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>

[ rss.xml ]
1. XML Parser function
XML(eXtensible Markup Language)은 인터넷과 같은 다양한 환경이 존재하는 곳에서 자료 교환을 위한 최선의 솔루션(형식)이며, 뉴스,날씨,증권등의 정보를 다양한 CP로 부터 얻어와야 하는 곳에서 많이 사용되고 있습니다. RSS는 이와 같은 XML의 가장 성공한 예입니다.

먼저 PHP에서 XML 구문 분석을 위한 "XML Parser function"에 대하여 알아보도록 하겠습니다. 대부분의 환경은 이미 "XML parser functions"이 설치 되어 있을 것이라고 생가합니다. 그러나 혹시 모르니 아래의 구문으로 설치여부를 점검해 주시고 설치가 되지 않은 분은 메뉴얼을 참고하여 주십시요.

$parser = @xml_parser_create();
if (!is_resource($parser)){
	die("Failed to create an instance of PHP's XML parser - 
			http://www.php.net/manual/en/ref.xml.php");
}

XML 주요 함수에 대한 자세한 설명은 메뉴얼 참고해 주시고, 여기서는 XML Parser 함수를 이용하여 날씨정보( http://www.kma.go.kr/weather/xml/current.xml )와 RSS 정보( rss.xml 파일)를 분석하는 방법을 예제를 통하여 배워 보도록 하겠습니다.

'weather.xml'은 날씨정보를 XML형식으로 제공하는 예입니다.아마도 패턴 매칭을 잘 사용하는 개발자의 경우에도 XML 문장들을 파싱하여 웹과 Application으로 서비스 하는 것은 그렇게 간단한 문제는 아닐 것입니다. 그러나 XML Parser 함수를 이용하면 주요 함수인(xml_parser_create, xml_set_element_handler, xml_set_character_data_handler)를 사용하여 간단하고 깔끔하게 원하는 정보를 얻어 올 수 있습니다.

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE current>
<current xmlns="current">
  <weather day="18" hour="17" month="11" year="2004">
    <local desc="맑음" icon="01" stn_id="101" ta="13.3">춘천</local>
    <local desc="맑음" icon="01" stn_id="102" ta="11.4">백령도</local>
    <local desc="맑음" icon="01" stn_id="105" ta="14.3">강릉</local>
    <local desc="구름조금" icon="02" rn_hr1="10" stn_id="108" ta="13.1">서울</local>
    <local desc="구름조금" icon="02" rn_hr1="25" stn_id="112" ta="12.5">인천</local>
    <local desc="구름조금" icon="02" stn_id="115" ta="11.9">울릉도</local>
    <local desc="구름조금" icon="02" rn_hr1="15" stn_id="119" ta="13.1">수원</local>
    <local desc="구름조금" icon="02" stn_id="131" ta="14.4">청주</local>
    <local desc="구름조금" icon="02" stn_id="133" ta="14.3">대전</local>
    <local desc="맑음" icon="01" stn_id="143" ta="15.4">대구</local>
    <local desc="맑음" icon="01" stn_id="146" ta="14.8">전주</local>
    <local desc="구름조금" icon="02" stn_id="152" ta="15.1">울산</local>
    <local desc="맑음" icon="01" stn_id="155" ta="15.7">마산</local>
    <local desc="맑음" icon="01" stn_id="156" ta="14.7">광주</local>
    <local desc="맑음" icon="01" stn_id="159" ta="14.4">부산</local>
    <local desc="맑음" icon="01" stn_id="184" ta="15.8">제주</local>
  </weather>
</current>

[ weather.xml ]

예제 코드 확인 : http://www.ihelpers.co.kr/lib/jmrss/weather.php

<?

function startElement($parser, $name, $attrs) {
	global $weather,$local,$stn_id;
	if($name == "WEATHER"){
		$weather = $attrs;
	} elseif($name == "LOCAL"){
		$stn_id = $attrs["STN_ID"];
		$local[$stn_id] = $attrs;
	}
}

function endElement($parser, $name) {
	global $stn_id;
	$stn_id = '';
}

function cdataHandler($parser, $cdata){
	global $local,$stn_id;
	if(!empty($stn_id)){ 
		$local[$stn_id]["value"] = $cdata;
	}
}

$file = "weather.xml";
$fp = fopen($file, "r") or die("$file not found");

$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, "startElement", "endElement");
xml_set_character_data_handler($xml_parser, "cdataHandler");

$stn_id = '';
$weather = array();
$local = array();

while ($data = fread($fp, 4096)) {
    if (!xml_parse($xml_parser, $data, feof($fp))) {
        die(sprintf("XML error: %s at line %d",
			xml_error_string(xml_get_error_code($xml_parser)),
			xml_get_current_line_number($xml_parser)));
    }
}
xml_parser_free($xml_parser);

echo "<pre>";
print_r($weather); 
print_r($local);
echo "</pre>";
?>

[ weather.php ]

앞에서는 XML에 대한 이해를 위하여 날씨정보 XML 구문을 파싱하는 예제를 간단하게 소개하였습니다. RSS 구문도 XML 형식이기에 날씨정보에서와 같이 XML Parser function을 사용하여 간단하게 구문 분석을 할 수 있습니다. 음... 아래의 코드를 설명하려고 하니 뭘 설명해야 할지 모르겠군요. startElement,endElement 함수을 주의 깊게 보시고,직접 해당 함수로 이것 저것 해 보는 것이 가장 좋을 듯 하군요. ( 소스코드는 아래에 있으니 꼭 다운로드 받아서 직접 연습해 보십시요. )

<?
function startElement($parser, $name, $attrs) {
    global $depth;
    for ($i = 0; $i < $depth[$parser]; $i++) {
        print "  ";
    }
    print "$name
";
    $depth[$parser]++;
}

function endElement($parser, $name) {
    global $depth;
    $depth[$parser]--;
}

$file = "rss.xml";
$fp = fopen($file, "r") or die("$file not found");

$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, "startElement", "endElement");

while ($data = fread($fp, 4096)) {
    if (!xml_parse($xml_parser, $data, feof($fp))) {
        die(sprintf("XML error: %s at line %d",
			xml_error_string(xml_get_error_code($xml_parser)),
			xml_get_current_line_number($xml_parser)));
    }
}
xml_parser_free($xml_parser);
?>

[ rss.xml 파일에 대한 XML Parser function을 사용한 분석 예제 ]

2.RSSParser Class
RSSParser 클래스는 RSS구문을 분석하는 함수들과 분석된 배열정보를 호출하는 GET 함수로 구성되어 있습니다. 코드를 보시면 _create,_add 등과 같이 함수명 앞에 "_" 를 붙인 함수들을 보실 수 있을 것입니다.이것은 PHP가 접근제어자(public, private, protect )를 제공하지 않아 클래스 내부에서만 사용되는 함수에 대한 구분을 위해 사용하였습니다.

RSS Reader(Aggregator)를 만들기 위하여 RSSParser클래스와 앞으로 소개할 클래스들에 대하여 모두 이해하고 직접 제작할 필요는 없습니다. 이미 이와 관련되어 좋은 모듈들이 많이 나와 있고 해당 강좌에서 제시하고 있는 클래스들을 사용하시면 쉽게 제작을 할 수 있습니다. 빠르게 RSS Reader 기능을 구현하고 싶은 분들은 아래의 샘플코드에 대한 이해만으로도 충분히 구현을 하실 수 있을 것입니다. RSS에 대하여 깊게 이해 하고 싶은 분들은 제시된 클래스 구문을 분석하시면 많은 도움이 될 것입니다.

<?
/*///////////////////////////////////////////////////////////////

작성자	: 손상모<smson@ihelpers.co.kr>
최초작성일	: 2004.10.25
변경내용	: 없슴

/////////////////////////////////////////////////////////////////*/

/**
* RSS parser class.
*
* This class is a parser for Resource Description Framework (RDF) Site
*
* @author Sang Mo,Son <smson@ihelpers.co.kr>
* @version 0.9 beta
* @access  public
*/
class RSSParser {

	var $parser;

	var $insideTag	= '';
	var $activeTag	= '';
	var $channel	= array();

	var $items		= array();
	var $item		= array();

	var $images	= array();
	var $image		= array();

	var $textinput	= array();
	var $textinputs	= array();

	// 2004.10.25 RSS 2.0 적용
	var $parentTags	= array('CHANNEL', 'ITEM', 'IMAGE', 'TEXTINPUT');
	var $channelTags	= array('TITLE', 'LINK', 'DESCRIPTION', 'LANGUAGE','COPYRIGHT','MANAGINGEDITOR',
			'WEBMASTER','PUBDATE','LASTBUILDDATE','CATEGORY','GENERATOR','DOCS','CLOUD',
			'TTL','RATING','SKIPHOURS','SKIPDAYS','IMAGE','ITEMS', 'TEXTINPUT');
	var $itemTags	= array('TITLE', 'LINK', 'DESCRIPTION',
			'AUTHOR','CATEGORY','COMMENTS','ENCLOSURE','GUID','PUBDATE','SOURCE');
	var $imageTags	= array('TITLE', 'URL', 'LINK','WIDTH','HEIGHT','DESCRIPTION');
	var $textinputTags = array('TITLE', 'DESCRIPTION', 'NAME', 'LINK');
	var $moduleTags	= array('DC:TITLE', 'DC:CREATOR', 'DC:SUBJECT', 'DC:DESCRIPTION',
			'DC:PUBLISHER', 'DC:CONTRIBUTOR', 'DC:DATE', 'DC:TYPE',
			'DC:FORMAT', 'DC:IDENTIFIER', 'DC:SOURCE', 'DC:LANGUAGE',
			'DC:RELATION', 'DC:COVERAGE', 'DC:RIGHTS',
			'BLOGCHANNEL:BLOGROLL', 'BLOGCHANNEL:MYSUBSCRIPTIONS',
			'BLOGCHANNEL:MYSUBSCRIPTIONS', 'BLOGCHANNEL:CHANGES');

	/**
	 * Constructor
	 *
	 * @access	public
	 * @return	void
	 */
	function RSSParser(){
		$this->_create();
	}

	/**
	 * create the XML parser resource
	 *
	 * @access  private
	 * @return	boolean
	 *
	 * @see		xml_parser_create
	 */
	function _create(){
		$this->parser = @xml_parser_create();
		if (is_resource($this->parser)) {
			xml_set_object($this->parser, &$this);
			xml_set_element_handler($this->parser, "startHandler", "endHandler");
			xml_set_character_data_handler($this->parser, "cdataHandler");
			return true;
		}
		return false;
	}

	/**
	 * Free the internal resources associated with the parser
	 * 
	 * @return null
	 **/
	function free(){
		if (is_resource($this->parser)) {
			xml_parser_free($this->parser);
			unset( $this->parser );
		}
		return null;
	}

	/**
	 * Start element handler for XML parser
	 *
	 * @access private
	 * @param  object XML parser object
	 * @param  string XML element
	 * @param  array  Attributes of XML tag
	 * @return void
	 */
	function startHandler($parser, $element, $attr){
		switch ($element) {
			case 'CHANNEL':
			case 'ITEM':
			case 'IMAGE':
			case 'TEXTINPUT':
				$this->insideTag = $element;
				break;

			default:
				$this->activeTag = $element;
		}
	}

	/**
	 * End element handler for XML parser
	 *
	 * @access private
	 * @param  object XML parser object
	 * @param  string
	 * @return void
	 */
	function endHandler($parser, $element){
		if ($element == $this->insideTag) {
			$this->insideTag = '';
			$this->struct[] = array_merge(array('type' => strtolower($element)),
					$this->last);
		}

		if ($element == 'ITEM') {
			$this->items[] = $this->item;
			$this->item = '';
		}

		if ($element == 'IMAGE') {
			$this->images[] = $this->image;
			$this->image = '';
		}

		if ($element == 'TEXTINPUT') {
			$this->textinputs = $this->textinput;
			$this->textinput = '';
		}

		$this->activeTag = '';
	}

	/**
	 * Handler for character data
	 *
	 * @access private
	 * @param  object XML parser object
	 * @param  string CDATA
	 * @return void
	 */
	function cdataHandler($parser, $cdata){
		if (in_array($this->insideTag, $this->parentTags)) {
			$tagName = strtolower($this->insideTag);
			$var = $this->{$tagName . 'Tags'};

			if (in_array($this->activeTag, $var)){
				$this->_add($tagName, strtolower($this->activeTag),$cdata);
			} elseif(in_array($this->activeTag, $this->moduleTags)) {
				$this->_add($tagName, strtolower($this->activeTag),$cdata);
			}
		}
	}

	/**
	 * Add element to internal result sets
	 *
	 * @access private
	 * @param  string Name of the result set
	 * @param  string Fieldname
	 * @param  string Value
	 * @return void
	 * @see    cdataHandler
	 */
	function _add($type, $field, $value)
	{
		if (empty($this->{$type}) || empty($this->{$type}[$field])) {
			$this->{$type}[$field] = $value;
		} else {
			$this->{$type}[$field] .= $value;
		}
		$this->last = $this->{$type};
	}

	/**
	 * Central parsing function.
	 *
	 * @access	public
	 * @param	string	XML Content
	 * @return	boolean
	 */
	function parse($data){
		xml_parse($this->parser,$data);
		return true;
	}

	/**
	 * Get complete structure of RSS file
	 *
	 * @access public
	 * @return array
	 */
	function getStructure()
	{
		return (array)$this->struct;
	}

	/**
	 * Get general information about current channel
	 *
	 * @access public
	 * @return array
	 */
	function getChannel()
	{
		return (array)$this->channel;
	}

	/**
	 * Get items from RSS file
	 *
	 * @access public
	 * @return array
	 */
	function getItems()
	{
		return (array)$this->items;
	}

	/**
	 * Get images from RSS file
	 *
	 * @access public
	 * @return array
	 */
	function getImages()
	{
		return (array)$this->images;
	}

	/**
	 * Get text input fields from RSS file
	 *
	 * @access public
	 * @return array
	 */
	function getTextinputs()
	{
		return (array)$this->textinputs;
	}
}
?>

[ RSSParser Class 코드 ]

<?
require "RSSParser.php";

$file = "rss.xml";
$fp = fopen($file, "r") or die("$file not found");
while (!feof ($fp)) {
    $buffer .= fgets($fp, 4096);
}
fclose ($fp);

$rss = new RSSParser();
$rss->parse($buffer);
echo "<pre>";
print_r($rss->getStructure());
print_r($rss->getChannel());
print_r($rss->getItems());
echo "</pre>";
?>

[ RSSParser Class을 이용한 샘플코드 ]

예제 코드 확인 : http://www.ihelpers.co.kr/lib/jmrss/demoRSSParser.php
3. 소스코드
이올린에 북마크하기(0) 이올린에 추천하기(0)
Posted by 백성용 헬로우보이