php를 이용해서 간단한 xml 파서기를 만들어 봤습니다. 개인적으로 joinc(:12)에서 간단히 사용할 RSS(:12)리더기 제작을 위한 베이스 클래스 용도로 사용할 생각입니다.
코드는 정재되지 않았으며, 충분히 지저분합니다. 에러처리도 안했고요. 여하튼지간에 작동되네? 하는 것에 중점을 둔거라서 말이죠. 깔끔하게 하는건 나중일로 할 생각입니다. php(:12)의 xml(:12)조작은 expat(:12) 라이브러리(:12)를 이용합니다. libexpat가 설치되어 있는지 미리 확인해봐야 겠죠 ? 만약 C(:12)에서 expat(:12)라이브러리를 이용한 프로그래밍을 해보았다면, 거의 동일한 방법으로 사용할 수 있을겁니다. 함수명들도 거의 동일하고 하는일도 비슷합니다.
<?php
class XmlParser
{
public $parser;
public $depth=0;
public $termStack;
public $nodeData;
public $fullParseData;
public $prevdepth;
public $uri;
public $last_node;
public $inside_data;
function XmlParser($uri)
{
$this->setURI($uri);
$this->run();
}
function run()
{
$this->termStack = array();
$this->xmlInit();
$this->parsing();
}
function setURI($uri)
{
$this->uri = $uri;
}
function xmlInit()
{
$this->parser = xml_parser_create();
if(!$this->parser) echo "Parser Error<br>";
if(!xml_set_object($this->parser, $this)) echo "xml set object error<br>";
if(!xml_set_element_handler($this->parser, "tag_open", "tag_close")) echo "handler set error<br>";
if(!xml_set_character_data_handler($this->parser, "cdata")) echo "cdata handler error<br>";
}
function cdata($parser, $cdata)
{
if($this->depth > $this->prevdepth)
{
if($this->inside_data)
$this->nodeData[$this->nodeName()] .= $cdata;
else
$this->nodeData[$this->nodeName()] = $cdata;
$this->last_node = $this->nodeName();
}
$this->inside_data=true;
}
function getData($node=null)
{
if($node == null)
{
return $this->fullParseData;
}
return $this->fullParseData[$node];
}
function parsing()
{
$fp = fopen($this->uri, "r");
if(!$fp)
{
return 0;
}
while($data = fread($fp, 9182))
{
$this->parse($data);
}
fclose($fp);
return 1;
}
function parse($data)
{
if(!xml_parse($this->parser, $data)) echo xml_error_string(xml_get_error_code($this->parser));
}
function getpNode($depth=0)
{
if($depth != 0)
{
$node=count($this->termStack) + $depth;
$stack = array_slice($this->termStack, 0, $node);
}
else
{
$stack = $this->termStack;
}
return join("/",$stack);
}
function pushStack($name)
{
array_push($this->termStack, $name);
}
function getStackSize()
{
return count($this->termStack);
}
function tag_open($parser, $tag, $attributes)
{
$this->pushStack($tag);
if($this->depth > $this->prevdepth)
{
if(count($this->nodeData))
{
$last_node = $this->getpNode(-2);
$this->fullParseData[$last_node] = $this->nodeData;
}
$this->nodeData=array();
$this->prevdepth = $this->depth;
}
$this->depth++;
$this->inside_data=false;
}
function tag_close($parser, $tag)
{
$count = count($this->nodeData);
if($count == 0)
array_pop($this->termStack);
$this->depth--;
if($this->depth < $this->prevdepth)
{
if(count($this->nodeData) > 1)
$this->fullParseData[$this->getpNode()][] = $this->nodeData;
else
$this->fullParseData[$this->getpNode()] = $this->nodeData;
$this->nodeData=array();
}
else
{
$this->prevdepth = $this->depth;
}
if($count != 0)
array_pop($this->termStack);
$this->inside_data=false;
}
function nodeName()
{
return $this->termStack[$this->depth-1];
}
}
// yundream 블로그의 RSS를 이용해서 테스트해보았다.
$parser = new XmlParser('http://teamblog.joinc.co.kr/yundream/rss');
$items = $parser->getData('RSS/CHANNEL/ITEM');
print_r($items);
foreach($items as $item)
{
echo $item['AUTHOR'],"<br>";
echo $item['TITLE'],"<br>";
}
?>
사용방법
다음은 사용방법입니다.
$parser = new XmlParser('http://teamblog.joinc.co.kr/yundream/rss');
$data = $parser->getData();
getData() 메서드를 이용해서 필요한 노드의 정보를 가져올 수 있습니다. 노드의 표현은 디렉토리 방식을 이용하고 있습니다. ITEM 정보를 가져오길 원한다면 RSS/CHANNEL/ITEM하는 식이 됩니다. 위의 예제에서는 RSS(:12)를 파싱하고 있습니다. 각 NODE의 정보는 다음과 같이 얻어올 수 있겠습니다.
php xml 파서기
<?php class XmlParser { public $parser; public $depth=0; public $termStack; public $nodeData; public $fullParseData; public $prevdepth; public $uri; public $last_node; public $inside_data; function XmlParser($uri) { $this->setURI($uri); $this->run(); } function run() { $this->termStack = array(); $this->xmlInit(); $this->parsing(); } function setURI($uri) { $this->uri = $uri; } function xmlInit() { $this->parser = xml_parser_create(); if(!$this->parser) echo "Parser Error<br>"; if(!xml_set_object($this->parser, $this)) echo "xml set object error<br>"; if(!xml_set_element_handler($this->parser, "tag_open", "tag_close")) echo "handler set error<br>"; if(!xml_set_character_data_handler($this->parser, "cdata")) echo "cdata handler error<br>"; } function cdata($parser, $cdata) { if($this->depth > $this->prevdepth) { if($this->inside_data) $this->nodeData[$this->nodeName()] .= $cdata; else $this->nodeData[$this->nodeName()] = $cdata; $this->last_node = $this->nodeName(); } $this->inside_data=true; } function getData($node=null) { if($node == null) { return $this->fullParseData; } return $this->fullParseData[$node]; } function parsing() { $fp = fopen($this->uri, "r"); if(!$fp) { return 0; } while($data = fread($fp, 9182)) { $this->parse($data); } fclose($fp); return 1; } function parse($data) { if(!xml_parse($this->parser, $data)) echo xml_error_string(xml_get_error_code($this->parser)); } function getpNode($depth=0) { if($depth != 0) { $node=count($this->termStack) + $depth; $stack = array_slice($this->termStack, 0, $node); } else { $stack = $this->termStack; } return join("/",$stack); } function pushStack($name) { array_push($this->termStack, $name); } function getStackSize() { return count($this->termStack); } function tag_open($parser, $tag, $attributes) { $this->pushStack($tag); if($this->depth > $this->prevdepth) { if(count($this->nodeData)) { $last_node = $this->getpNode(-2); $this->fullParseData[$last_node] = $this->nodeData; } $this->nodeData=array(); $this->prevdepth = $this->depth; } $this->depth++; $this->inside_data=false; } function tag_close($parser, $tag) { $count = count($this->nodeData); if($count == 0) array_pop($this->termStack); $this->depth--; if($this->depth < $this->prevdepth) { if(count($this->nodeData) > 1) $this->fullParseData[$this->getpNode()][] = $this->nodeData; else $this->fullParseData[$this->getpNode()] = $this->nodeData; $this->nodeData=array(); } else { $this->prevdepth = $this->depth; } if($count != 0) array_pop($this->termStack); $this->inside_data=false; } function nodeName() { return $this->termStack[$this->depth-1]; } } // yundream 블로그의 RSS를 이용해서 테스트해보았다. $parser = new XmlParser('http://teamblog.joinc.co.kr/yundream/rss'); $items = $parser->getData('RSS/CHANNEL/ITEM'); print_r($items); foreach($items as $item) { echo $item['AUTHOR'],"<br>"; echo $item['TITLE'],"<br>"; } ?>사용방법
$parser = new XmlParser('http://teamblog.joinc.co.kr/yundream/rss'); $data = $parser->getData();$channel = $parser->getData('RSS/CHANNEL'); echo $channel['TITLE']; echo $channel['LINK']; echo $channel['PUBDATE'];$items = $parser->getData('RSS/CHANNEL/ITEM'); foreach($items as $item) { echo $item['AUTHOR'],"<br>"; echo $item['TITLE'],"<br>"; }해야할 것
Recent Posts
Archive Posts
Tags