标题如何用PHP把RDF内容插入Web站点之中
日期:    作者:爱好者   来源:php之家
文章打印自:
访问文章完全地址:
头部广告
如何用PHP把RDF内容插入Web站点之中
名誉和巨大的财富

设想一个从最热门的门户网站获得最新的新闻的站点。股票价格天气信息新闻故事线式讨论组软件发布……所有这一切都将被动态更新每小时一次不需要任何手工干预。我们可以想象这随之而来的站点访问量源源不断的广告收入以及网管大人所受到的“阿谀奉承”。

但是现在停止幻想开始阅读因为只要你密切关注此项技术说不定你就能成为站点的主人。 对你的要求也只是稍许的想象力一些聪明的PHP编码和几个免费的RSS文件。另外很明显还包括这篇文章剩下的九个部分。



有内容就联合成辛迪加Have Content, Will Syndicate
我们从最基本的开始——那么RSS究竟是什么鬼东西呢

RSS即RDF Site Summary是一种格式最早由Netscape公司设计用于分发其门户站点My.Netscape.Com上的内容的描述信息。自1997年被提出以来几经沉浮——可以点击文章末尾的链接了解一下RSS悠久复杂的历史。现在的稳定的版本是RSS1.0符合RDF规范。这一版本可以说即轻便又功能齐全。

RSS使得网管及时公布和分发某一特定站点的特定位置的最新最有趣的内容的描述信息变的可能。 从新闻文章列表到股票市场数据或着是天气预报所有这些信息都可以通过结构良好的XML文档来发布从而也可以被任何XML分析器进行分析处理和翻译。

网站上最新信息的列表是经常更新的而RSS使得这一列表的分发成为可能也就为Web上简易的内容辛迪加联合打开了大门。想了解这其中的道理请看下面这个简单的例子

站点A属新闻站点“内容辛迪加组织者”能够每小时发布一个包含最新新闻列表以及相应链接的RSS文档。 而这一RSS文档可以被其它站点获取如站点B“内容收集者”分析并显示在站点B的索引页面上。 每次站点A发布一个新的RSS文档站点B的索引页面都可以自动更新以获取最新的新闻。

这种方案对交易中的双方机构都有效。 既然RSS文档中的链接都指向站点A上相应的文章那么站点A将迅速体验到访问量的增加。 而站点B的网管可以休假一个星期因为他有办法自动更新其站点上的索引页面而这一方法仅仅是把索引页面与站点A发布的动态内容相连接而已。

有许多受欢迎的站点向公众提供详细的RSS或RDF新闻如Freshmeathttp://www.freshmeat.net)和Slashdot(http://www.slashdot.org),当然还有其它许多站点。在这篇文章当中,我将广泛的使用Freshmeat网站的RDF文件。需要说明的一点是,这里所谈到的技术也可以应用于其它任何RSS1.0或RDF文件。



交换频道(Switching Channels)

典型的RSS文档包含一个由描述性元数据标记出来的资源列表(URLs),请看下面的例子:

<?xml version="1.0" encoding="UTF-8"
?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns
="http://purl.org/rss/1.0/">

<channel rdf:about
="http://www.melonfire.com/">
<title>Trog</title>
<description>Well-written technical articles and
tutorials on Web technologies</description>

<link>http
://www.melonfire.com/community/columns/trog/</link>
<items>
<rdf:Seq>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=100" />
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=71" />
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=62" />
</rdf:Seq>
</items>
</channel>

<item
rdf:about="http://www.melonfire.com/community/columns/trog/article.php?i
d=10
0">
<title>Building A PHP-Based Mail Client (part 1)</title>

<link>http://www.melonfire.com/community/columns/trog/article.php?id=100
</li
nk>
<description>Ever wondered how Web-based mail clients
work? Find out here.</description>
</item>

<item
rdf:about="http://www.melonfire.com/community/columns/trog/article.php?i
d=71">
<title>Using PHP With XML (part 1)</title>

<link>http://www.melonfire.com/community/columns/trog/article.php?id=71<
/link>
<description>Use PHP's SAX parser to parse XML data and
generate HTML pages.</description>
</item>

<item
rdf:about="http://www.melonfire.com/community/columns/trog/article.php?i
d=62">
<title>Access Granted</title>

<link>http://www.melonfire.com/community/columns/trog/article.php?id=62<
/link>
<description>Precisely control access to information
with the mySQL grant tables.</description>
</item>

你可以看到,RDF文件由几个界限分明的部分组成。首先是文档序码(prolog),

<?xml version="1.0" encoding="UTF-8"
?>

然后是根元素中的名称空间声明。

<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/">
接着是<channel>部分这部分包含了RDF所要描述的频道的一般信息。在上面的例子中频道是Melonfire网站的Trog专栏专栏内容是新的技术文章和指南每星期更新一次。

<channel rdf:about="http://www.melonfire.com/">
<title>Trog</title>
<description>Well-written technical articles and
tutorials on Web technologies</description>

<link>http://www.melonfire.com/community/columns/trog/</link>
<items>
<rdf:Seq>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=100"
/>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=71"
/>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=62"
/>
</rdf:Seq>
</items>
</channel>

<channel>区包含了一个<items>区块<items>区块又包含了文档中描述的所有资源的一个顺序列表。该列表通过一系列的<li />元素来表示。区块中每一个资源都在后面的<item>区块中有更详细的描述。

<items>
<rdf:Seq>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=100"
/>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=71"
/>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=62"
/>
</rdf:Seq>
</items>

还可以在其中放置一个<image>区块这样你就可以发布频道标志的URL。

所以为了肉RSS1.0文档中的每一个<item>区块都更详细地描述一个单独的资源包括标题URL和资源描述。

<items>
<rdf:Seq>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=100"
/>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=71"
/>
<li
rdf:resource="http://www.melonfire.com/community/columns/trog/article.ph
p?id
=62"
/>
</rdf:Seq>
</items>

在这个例子里<item>区块描述了Ttrog“频道”中单独的一篇文章并为这篇文章提供了描述和标题以及URL。内容收集者可以利用URL创建“向后”链接。



你看得到RSS1.0文件相当地直观明了不管是手工还是通过编程都非常容易创建。上面的例子和解释仅仅是说明性质的通常你可以用RSS1.0和RDF做更多的事情。你最好看一下文章末尾提供的链接以获取更多的信息。不过在这之前我们再花几分钟讨论一如何将RSS1.0文档插入到你自己的Web站点之中。
如何用PHP把RDF内容插入Web站点之中
既然从技术上讲RSS是结构良好的XML文档所以可以用标准的XML编程技术来处理它。主要有两种技术SAXthe Simple API for XML和DOM(the Document Object Model)



SAX分析器工作时遍历整个XML文档
在遇到不用类型的标记时调用特定的函数。比如调用特定函数处理一个开始标记调用另一个函数处理一个结束标记再调用一个函数处理两者之间的数据。分析器的职责仅仅是顺序遍历这个文档。而它所调用的函数负责处理发现的标记。一旦一个标记被处理完毕分析器继续分析文档中的下一个元素,这一过程不断重复。



另一方面
DOM分析器工作是把整个XML文档读进内存当中并将之转换成一种分层的树型结构。而且为访问不同的树结点以及结点所附的内容提供了API。递归处理方式加上API函数使得开发者能够区分不同类型的结点元素属性字符数据注释等同时根据文档树的结点类型和结点深度使得执行不同的动作成为可能。



SAX和DOM分析器几乎支持每一种语言
包括你我的最爱——PHP。我将在这篇文章中利用PHP的SAX分析器处理RDF的例子。 当然使用DOM分析器也同样很容易。



让我们看这个简单的例子
把它记在脑海里。下面是一个我将要使用的RDF文件这个文件直接选自http://www.freshmeat.net/ :



<?xml version="1.0" encoding="ISO-8859-1"
?>

<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://freshmeat.net/">

    <title>freshmeat.net</title>

    <link>http
://freshmeat.net/</link>

    <description>freshmeat.net maintains the Web's largest index of Unix

and cross-platform open source software. Thousands of applications are

meticulously cataloged in the freshmeat.net database, and links to new

code are added daily.</description>

    <dc:language>en-us</dc:language>

    <dc:subject>Technology</dc:subject>

    <dc:publisher>freshmeat.net</dc:publisher>

    <dc:creator>freshmeat.net contributors</dc:creator>

    <dc:rights>Copyright (c) 1997-2002 OSDN</dc:rights>

    <dc:date>2002-02-11T10:20+00:00</dc:date>

    <items>

      <rdf:Seq>

        <rdf:li rdf:resource="http://freshmeat.net/releases/69583/" />

        <rdf:li rdf:resource="http://freshmeat.net/releases/69581/" />

       

      <!-- and so on -->



      </rdf:Seq>

    </items>

    <image rdf:resource="http://freshmeat.net/img/fmII-button.gif" />

    <textinput rdf:resource="http://freshmeat.net/search/" />

  </channel>



  <image rdf:about="http://freshmeat.net/img/fmII-button.gif">

    <title>freshmeat.net</title>

    <url>http://freshmeat.net/img/fmII-button.gif</url>

    <link>http://freshmeat.net/</link>

  </image>



  <item rdf:about="http://freshmeat.net/releases/69583/">

    <title>sloop.splitter 0.2.1</title>

    <link>http://freshmeat.net/releases/69583/</link>

    <description>A real time sound effects program.</description>

    <dc:date>2002-02-11T04:52-06:00</dc:date>

  </item>



  <item rdf:about="http://freshmeat.net/releases/69581/">

    <title>apacompile 1.9.9</title>

    <link>http://freshmeat.net/releases/69581/</link>

    <description>A full-featured Apache compilation HOWTO.</description>

    <dc:date>2002-02-11T04:52-06:00</dc:date>

  </item>



<!-- and so on -->



</rdf:RDF>







下面是分析这一文档并显示其中数据的PHP脚本:



  <?php

// XML file

$file = "fm-releases.rdf";



// set up some variables for use by the parser

$currentTag = "";

$flag = "";



// create parser

$xp = xml_parser_create();



// set element handler

xml_set_element_handler($xp, "elementBegin", "elementEnd");

xml_set_character_data_handler($xp, "characterData");

xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, TRUE);



// read XML file

if (!($fp = fopen($file, "r")))

{

      die("Could not read $file");

}



// parse data

while ($xml = fread($fp, 4096))

{

    if (!xml_parse($xp, $xml, feof($fp)))

    {

           die("XML parser error: " .

xml_error_string(xml_get_error_code($xp)));

    }

}



// destroy parser

xml_parser_free($xp);



// opening tag handler

function elementBegin($parser, $name, $attributes)

{

  global $currentTag, $flag;

  // export the name of the current tag to the global scope

  $currentTag = $name;

  // if within an item block, set a flag

  if ($name == "ITEM")

  {

           $flag = 1;

  }

}



// closing tag handler      

function elementEnd($parser, $name)

{

  global $currentTag, $flag;

  $currentTag = "";

  // if exiting an item block, print a line and reset the flag

  if ($name == "ITEM")

  {

           echo "<hr>";

           $flag = 0;

  }

}



// character data handler

function characterData($parser, $data)

{

  global $currentTag, $flag;

  // if within an item block, print item data

  if (($currentTag == "TITLE" || $currentTag == "LINK" ||

$currentTag ==

"DESCRIPTION") && $flag == 1)

  {

           echo "$currentTag: $data <br>";

  }

}



?>



看不明白
别着急后面将会作出解释。







捕获旗标



这段脚本首先要做的是设定一些全局变量




// XML file

$file
= "fm-releases.rdf";



// set up some variables for use by the parser

$currentTag
= "";

$flag = "";



$currentTag变量保存是分析器当前处理的元素的名称——你很快就会看到为什么需要它。



因为我的最终目的是显示频道中的每一个单独的条目
item并且带有链结。另外还要知道分析器什么时候退出了<channel></channel>区块什么时候又进入了文档的 <item></item>部分。再说我用的是SAX分析器它按顺序方式工作没有任何分析器API可供使用无法知道文档树中的深度和位置。所以我不得不自己发明一个机制来做这件事——这就是引入$flag变量的原因。



$flag变量将用于判断分析器是在
<channel>区块还是在<item>区块里面。



下一步要做的是初始化SAX分析器
并开始分析RSS文档。



// create parser

$xp
= xml_parser_create();



// set element handler

xml_set_element_handler
($xp, "elementBegin", "elementEnd");

xml_set_character_data_handler($xp, "characterData");

xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, TRUE);



// read XML file

if (!($fp = fopen($file, "r")))

{

      die("Could not read $file");

}



// parse data

while ($xml = fread($fp, 4096))

{

    if (!xml_parse($xp, $xml, feof($fp)))

   
{

           die("XML parser error: " .

xml_error_string(xml_get_error_code($xp)));

    }

}



// destroy parser

xml_parser_free
($xp);







这段代码简单明了
其中的注释已经解释的足够清楚了。xml_parser_create()函数建立一个分析器实例并将之赋给句柄$xp。接着再创建回调函数处理开标记和闭标记以及二者之间的字符数据。最后xml_parse()函数联合多次fread()调用读取RDF文件并分析它。



在文档中
每次遇到开标记开标记处理器elementBegin()就会被调用。



// opening tag handler

function elementBegin($parser, $name, $attributes)

{

  global $currentTag, $flag;

  // export the name of the current tag to the global scope

  $currentTag
= $name;

  // if within an item block, set a flag

 
if ($name == "ITEM")

  {

           $flag = 1;

  }

}







这个函数以当前标记的名称和属性作为起参数。标记名称被赋值给全局变量$currentTag。如果
这个开标记是<item>那么把$flag变量置1。



同样
如果遇到闭标记那么闭标记处理器elementEnd()将被调用。



// closing tag handler      

function elementEnd($parser, $name)

{

  global $currentTag, $flag;

  $currentTag = "";

  // if exiting an item block, print a line and reset the flag

 
if ($name == "ITEM")

  {

           echo "<hr>";

           $flag = 0;

  }

}



闭标记处理函数也是以标记名称作为其参数。如果是遇到的是一个为</item>的闭标记变量$flag的值重置为0并把变量$currentTag的值清空。



那么
如何处理标记之间的字符数据呢 这才是我们的兴趣所在。先向字符数据处理器characterData()打个招呼吧。



// character data handler

function characterData($parser, $data)

{

  global $currentTag, $flag;

  // if within an item block, print item data

 
if (($currentTag == "TITLE" || $currentTag == "LINK" ||

$currentTag ==

"DESCRIPTION") && $flag == 1)

  {

           echo "$currentTag: $data <br>";

  }

}







现在你可以看一下传给这个函数的参数
你会发现它只接收了开标记和闭标记之间的数据而根本不知道分析器当前正在处理哪个标记。而这正事我们一开始就引入全局变量$currentTag的原因。



如果$flag变量的值为1
也就是说如果分析器当前处于<item></itme>区块之间那么当前被处理的元素不管是<title>,<link>还是<description>数据都被打印到输出设备上在这里输出设备是Web浏览器并在每个元素的输出后面加上换行符<br>



整个RDF文档就是以这种顺序方式处理
每发现一个<item>标记就显示一定的输出。你可以看一下下面的运行结果
如何用PHP把RDF内容插入Web站点之中
筑巢时间Nesting Time

前面的例子只是用来说明问题的。如果你真想把RDF内容插入到Web站点当中就需要把事情做的更好一些。所以把前面的脚本的作了改进新增了一些东西从而简化格式化RDF数据的任务。



<html>

<head>

<basefont face="Verdana">

</head>

<body>



<table border="0" cellspacing="5" cellpadding="5">

<tr>

<td><b>New releases on freshmeat.net today:</b></td>

</tr>



<?php

// XML file

$file = "http://www.freshmeat.net/backend/fm-releases.rdf";



// set up some variables for use by the parser

$currentTag = "";

$flag = "";

$count = 0;



// this is an associative array of channel data with keys ("title",

"link",

"description")

$channel = array();



// this is an array of arrays, with each array element representing an

<item> // each outer array element is itself an associative array

// with keys ("title", "link", "description")

$items = array();



// opening tag handler

function elementBegin($parser, $name, $attributes)

{

  global $currentTag, $flag;

  $currentTag = $name;

  // set flag if entering <channel> or <item> block

  if ($name == "ITEM")

  {

           $flag = 1;

  }

  else if ($name == "CHANNEL")

  {

           $flag = 2;

  }

}



// closing tag handler      

function elementEnd($parser, $name)

{

  global $currentTag, $flag, $count;

  $currentTag = "";



  // set flag if exiting <channel> or <item> block

  if ($name == "ITEM")

  {

           $count++;

           $flag = 0;

  }

  else if ($name == "CHANNEL")

  {

           $flag = 0;

  }

}



// character data handler

function characterData($parser, $data)

{

  global $currentTag, $flag, $items, $count, $channel;

  $data = trim(htmlspecialchars($data));

  if ($currentTag == "TITLE" || $currentTag == "LINK" ||

$currentTag ==

"DESCRIPTION")

  {

           // add data to $channels[] or $items[] array

           if ($flag == 1)

           {

                   $items[$count][strtolower($currentTag)] .=

$data;

           }

           else if ($flag == 2)

           {

                   $channel[strtolower($currentTag)] .= $data;

           }

  }



}



// create parser

$xp = xml_parser_create();



// set element handler

xml_set_element_handler($xp, "elementBegin", "elementEnd");

xml_set_character_data_handler($xp, "characterData");

xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, TRUE);

xml_parser_set_option($xp, XML_OPTION_SKIP_WHITE, TRUE);



// read XML file

if (!($fp = fopen($file, "r")))

{

      die("Could not read $file");

}



// parse data

while ($xml = fread($fp, 4096))

{

    if (!xml_parse($xp, $xml, feof($fp)))

    {

           die("XML parser error: " .

xml_error_string(xml_get_error_code($xp)));

    }

}



// destroy parser

xml_parser_free($xp);



// now iterate through $items[] array

// and print each item as a table row

foreach ($items as $item)

{

  echo "<tr><td><a href=" . $item["link"] . ">" . $item["title"] .

"</a><br>" . $item["description"] .  "</td></tr>"; }



?>

</table>

</body>

</html>



与先前的那段的主要区别在于这段脚本创建了两个数组用于保存分析过程中所提取的信息。其中$channel是联合性数组associative array存放被处理的频道的基本描述信息而$items是一个二维数组包含关于单独的频道条目channel intems的信息。$items数组中的每一个元素本身又是一个联合性数组包含title,URL和description关键字。$items数组中元素总数与RDF文档中的<item>区块总数相同。



还需注意$flag变量的变化
根据被处理的是<channel></channel>区块还是<item></item>区块它现在保存两个值。这一点很有必要因为只有这样分析器才能把信息放入正确的数组里面。



一旦文档分析完毕
事情就简单了——遍历$items 数组以表格形式打印其中的每一个条目item。远行结果如下
如何用PHP把RDF内容插入Web站点之中
返回到类Back To Class

既然你有这么大的权力那么究竟为什么要把自己限制在仅仅是单个的RDF来源呢就象我早先说过的一样大多数主要的站点都经常为他们所提供的内容做快照。其实将所有这些不同的来源插入到你的站点当中是相当简单的。让我们看看是如何做的。

首先我们把前面例子中的代码模块化。这样一来你就无须为每一个单个的来源都一遍又一遍的重写相同的代码了。简化的方法就是将之打包成类再把这个类包含到我的PHP脚本当中。

类代码如下

<?
class RDFParser
{
//
// variables
//

// set up local variables for this class
var $currentTag = "";
var $flag = "";
var $count = 0;

// this is an associative array of channel data with keys
("title", "link", "description")
var $channel = array();

// this is an array of arrays, with each array element
representing an <item>
// each outer array element is itself an associative array
// with keys ("title", "link", "description")
var $items = array();


//
// methods
//

// set the name of the RDF file to parse
// this is usually a local file
// you may set it to a remote file if your PHP build supports
URL fopen()
function setResource($file)
{
$this->file = $file;
}


// parse the RDF file set with setResource()
// this populates the $channel and $items arrays
function parseResource()
{
// create parser
$this->xp = xml_parser_create();

// set object reference
xml_set_object($this->xp, $this);

// set handlers and parser options
xml_set_element_handler($this->xp, "elementBegin",
"elementEnd");
xml_set_character_data_handler($this->xp,
"characterData");
xml_parser_set_option($this->xp,
XML_OPTION_CASE_FOLDING, TRUE);
xml_parser_set_option($this->xp, XML_OPTION_SKIP_WHITE,
TRUE);

// read XML file
if (!($fp = fopen($this->file, "r")))
{
die("Could not read $this->file");
}

// parse data
while ($xml = fread($fp, 4096))
{
if (!xml_parse($this->xp, $xml, feof($fp)))
{
die("XML parser error: " .
xml_error_string(xml_get_error_code($this->xp)));
}
}

// destroy parser
xml_parser_free($this->xp);
}

// opening tag handler
function elementBegin($parser, $name, $attributes)
{
$this->currentTag = $name;
// set flag if entering <channel> or <item> block
if ($name == "ITEM")
{
$this->flag = 1;
}
else if ($name == "CHANNEL")
{
$this->flag = 2;
}
}

// closing tag handler
function elementEnd($parser, $name)
{
$this->currentTag = "";

// set flag if exiting <channel> or <item> block
if ($name == "ITEM")
{
$this->count++;
$this->flag = 0;
}
else if ($name == "CHANNEL")
{
$this->flag = 0;
}
}

// character data handler
function characterData($parser, $data)
{
$data = trim(htmlspecialchars($data));
if ($this->currentTag == "TITLE" || $this->currentTag ==
"LINK" || $this->currentTag == "DESCRIPTION")
{
// add data to $channels[] or $items[] array
if ($this->flag == 1)
{

$this->items[$this->count][strtolower($this->currentTag)] .= $data;
}
else if ($this->flag == 2)
{

$this->channel[strtolower($this->currentTag)] .= $data;
}
}
}

// return an associative array containing channel information
// (the $channel[] array)
function getChannelInfo()
{
return $this->channel;
}

// return an associative array of arrays containing item
information
// (the $items[] array)
function getItems()
{
return $this->items;
}

}
?>

如果你对PHP类较为熟悉的话那么理解这段代码是相当容易的。如果不太懂的话那么请直接跳到文章末尾的链接部分看一篇关于类工作原理的好文章。然后在回来继续阅读上面的代码。

在使用这个类之前我要特别花几分钟指出其中的一行代码——即上面对xml_set_object()函数调用的那一行。

现在的问题是如何使用这个类实际生成具有多个内容来源的Web页。

<?
include("class.RDFParser.php");
// how many items to display in each channel
$maxItems = 5;
?>
<html>
<head>
<basefont face="Verdana">
<body>

<table width="100%" border="0" cellspacing="5" cellpadding="5"> <tr>
<!-- first cell -->
<td valign=top align=left>
<font size="-1">
<?
// get and parse freshmeat.net channel
$f = new RDFParser();
$f->setResource("http://www.freshmeat.net/backend/fm-releases.rdf");
$f->parseResource();
$f_channel = $f->getChannelInfo();
$f_items = $f->getItems();
// now format and print it...
?>
The latest from <a href=<? echo $f_channel["link"]; ?>><? echo
$f_channel["title"]; ?></a> <br> <ul> <? // iterate through items array
for ($x=0; $x<$maxItems; $x++) {
if (is_array($f_items[$x]))
{
// print data
$item = $f_items[$x];
echo "<li><a href=" . $item["link"] . ">" .
$item["title"] . "</a>";
}
}
?>
</ul>
</font>
</td>

<!-- second cell -->
<td align=center width=50%>
<i>Primary page content here</i>
</td>

<!-- third cell -->
<td valign=top align=left>
<font size="-1">
<?
// get and parse slashdot.org channel
$s = new RDFParser();
$s->setResource("http://slashdot.org/slashdot.rdf");
$s->parseResource();
$s_channel = $s->getChannelInfo();
$s_items = $s->getItems();
// now format and print it...
?>
The latest from <a href=<? echo $s_channel["link"]; ?>><? echo
$s_channel["title"]; ?></a> <br> <ul> <? // iterate through items array
for ($x=0; $x<$maxItems; $x++) {
if (is_array($s_items[$x]))
{
// print data
$item = $s_items[$x];
echo "<li><a href=" . $item["link"] . ">" .
$item["title"] . "</a>";
}
}
?>
</ul>
</font>
</td>

</tr>
</table>

</body>
</head>
</html>



这段代码相当简单。一旦你用“new”关键字生成一个类的实例

$f = new RDFParser();

那么就可以用类方法来设置要分析的RDF文件的位置

$f->setResource("http://www.freshmeat.net/backend/fm-releases.rdf");
$f->parseResource();

并且获取$channel和$items数组以用于后面的处理。



<?
$f_channel = $f->getChannelInfo();
$f_items = $f->getItems();
?>

The latest from <a href=<? echo $f_channel["link"]; ?>><? echo
$f_channel["title"]; ?></a> <br> <ul> <? // iterate through items array
for ($x=0; $x<$maxItems; $x++) {
if (is_array($f_items[$x]))
{
// print data
$item = $f_items[$x];
echo "<li><a href=" . $item["link"] . ">" .
$item["title"] . "</a>";
}
}
?>
</ul>



每次你重新装入上面的脚本相应的RDF文件就会被从特定的位置上取来经过分析之后按要求的格式显示出来。

如果你站点具有高的访问量你就可能觉得我们的辛苦无意义之极尤其是当所用的RDF数据更新地没有那么快时情况更糟。 在这种情况下或许探究一下在本地缓存RDF数据才是较明智的做法要么扩展上面的例子程序在其中加入缓存功能要么每阁几个小时都花很长的时间下载一个最新RDF文件的本地副本到你的Web服务器上然后使用这个本地副本而不是那个“活”的the “live” one
如何用PHP把RDF内容插入Web站点之中
出处     http://www.devshed.com/Server_Side/PHP/PHPRDF/page1.html 



上面我所写的那个类也是很基本的,是拿来说明问题的,或许也可以用于低访问量的站点。如果你想寻找一些更专业的东西,去网上吧,那里有许多的开放源码的RDF分析器,他们带有各种附加的功能(包括缓存)。 那么就让我们看一些如何运用这些分析器的例子吧。







第一个要讲的是由Stefan Saasen 为fase4网站开发的RDF分析器类,可以从http://www.fase4.com/rdf/上免费下载。这是一个功能非常齐全的RDF分析器,支持缓存和通过代理认证。下面是如何使用它的例子:



<html>

<head>

<style type="text/css">

body {font-family: Verdana; font-size: 11px;}   

.fase4_rdf {font-size: 13px; font-family: Verdana} .fase4_rdf_title

{font-size: 13px; font-weight : bolder;}

</style>   

</head>

<body>

<?

// include class

include("rdf.class.php");



// instantiate object

$rdf = new fase4_rdf;



// set number of items to display

$rdf->set_max_item(5);



// set RDF engine options

$rdf->use_dynamic_display(true);

$rdf->set_Options( array("image"=>"hidden", "textinput"=>"hidden") );



// parse and display data

$rdf->parse_RDF("http://www.freshmeat.net/backend/fm-releases.rdf");

$rdf->finish();

 上面我所写的那个类也是很基本的,是拿来说明问题的,或许也可以用于低访问量的站点。如果你想寻找一些更专业的东西,去网上吧,那里有许多的开放源码的RDF分析器,他们带有各种附加的功能(包括缓存)。 那么就让我们看一些如何运用这些分析器的例子吧。第一个要讲的是由Stefan Saasen 为fase4网站开发的RDF分析器类,可以从http://www.fase4.com/rdf/上免费下载。这是一个功能非常齐全的RDF分析器,支持缓存和通过代理认证。下面是如何使用它的例子:<html><head><style type="text/css">body {font-family: Verdana; font-size: 11px;}    .fase4_rdf {font-size: 13px; font-family: Verdana} .fase4_rdf_title{font-size: 13px; font-weight : bolder;}</style>    </head><body><?// include classinclude("rdf.class.php");// instantiate object$rdf = new fase4_rdf;// set number of items to display$rdf->set_max_item(5);// set RDF engine options$rdf->use_dynamic_display(true);$rdf->set_Options( array("image"=>"hidden", "textinput"=>"hidden") );// parse and display data$rdf->parse_RDF("http://www.freshmeat.net/backend/fm-releases.rdf");$rdf->finish();?>

</body>





</html>















另一个要介绍的是由Jason Williams开发的PHP RDF分析器
可以在http://www.nerdzine.net/php_rdf/下载。这是一个未经任何任何渲染的PHP类,实现了一些基本的方法。但是它包含的大量的属性,可以让你用来安排经过处理的数据,直到你满意为止。



--------------------------------------------------------------------------------

<html>

<head>

<basefont face="Verdana">

</head>

<body link="Red" vlink="Red" alink="Red">

<?

include("rdf_class.php");



// this needs to be a local file

$f = new rdfFile("./fm-releases.rdf");

$f->parse(True);

$f->ReturnTable(True, "black", "white", "100%");

?>

</body>





</html>







关于这些类的文档在他们各自的网站上都有介绍。















增加一点样式
Adding A Little Style







万一你讨厌遍历那些PHP数组并把他们用HTML标记出来的方式那么你也可以选择通过使用XSLT样式单来格式化和显示这些数据。PHP4 .1可以通过新的XSLT API来支持Sablotron XSLT处理器新的API可以用来合并一个XSLT样式单和一个XML文档在这里即RDF文件从而非常容易的把XML标记转化为浏览器可读的HTML标记。







我不想在这上面讲的太细
你可以看一下PHP 手册或者关注一下本文后面的链接以获得更加详细的信息。不过我还是会给出一个简单的例子来说明这个问题。首先给出样式单文件



<?xml version="1.0"?>



<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

xmlns:rdf
="http://www.w3.org/1999/02/22-rdf-syntax-ns#"

xmlns:rss
="http://purl.org/rss/1.0/"

xmlns:dc
="http://purl.org/dc/elements/1.1/" version="1.0">



<!-- main page -->

<xsl:template match="/rdf:RDF">

  <html>

  <head>

  <basefont face="Arial" size="2"/>

  </head>

  <body>

  <xsl:apply-templates select="rss:channel" />

  <ul>

  <xsl:apply-templates select="rss:item" />

  </ul>

  </body>

  </html>

</xsl:template>



<!-- channel -->

<xsl:template match="rss:channel">

  <b>

  <a>

  <xsl:attribute name="href"><xsl:value-of select="rss:link"

/></xsl:attribute>

  <xsl:value-of select="rss:title" />

  </a>

  </b>

</xsl:template>



<!-- item -->

<xsl:template match="rss:item">

  <li />

  <a>

  <xsl:attribute name="href"><xsl:value-of select="rss:link"

/></xsl:attribute>

  <xsl:value-of select="rss:title" />

  </a>

  <br />

  <xsl:value-of select="rss:description" />

</xsl:template>







</xsl:stylesheet>







   下面是PHP脚本用来把上面的样式单和讲的“鲜肉”RDF文档合并起来生成一个HTML页面



    <?php

// XML file

// this needs to be a local file

$xml = "fm-releases.rdf";



// XSLT file

$xslt = "fm.xsl";



// create a new XSLT processor

$xp = xslt_create();



// transform the XML file as per the XSLT stylesheet

// return the result to $result

$result = xslt_process($xp, $xml, $xslt);

if ($result)

{

  // print it

  echo $result;

}



// clean up

xslt_free($xp);







?>







我想这相当简单
无须再加说明。两个文档合并在一起产生了下面的“合成物”













































这是把RDF数据转换成浏览器可读的HTML的另一种方法
或许简单一些尽管并不是最理想的。不过要注意一点你需要运行一个外部程序来定期更新你的RDF文件的本地副本原因在于PHP XSLT处理器访问远端文件可能有困难。















家庭作业
Homework







如果你有兴趣对这些文中谈到的和没谈到的技术了解的更多你可以考虑访问下面的链接







RSS 1.0 规范







http://www.purl.org/rss/1.0/

RSS 发展史







http://backend.userland.com/stories/rss091



W3C 网站关于RDF的内容








http://www.w3.org/RDF/



PHP中关于SAX和DOM编程的讨论http://www.devshed.com/Server_Side/XML/XMLwithPHP



用PHP实现XSLT转换的讨论








http://www.devshed.com/Server_Side/XML/XSLTrans



关于PHP类的讨论








http://www.devshed.com/Server_Side/PHP/BackToClass



XML基础的讨论








http://www.devshed.com/Server_Side/XML/XMLBasic



  XSLT基础的讨论








http
://www.devshed.com/Server_Side/XML/XSLBasics



  PHP手册中关于SAX函数的内容








http
://www.php.net/manual/en/ref.xml.php



  PHP手册中关于XSLT函数的内容








http://www.php.net/manual/en/ref.xslt.php















下次再见了……保重身体呀








注意本文中的所有例子都在Linux/i386Apache1.3.12,PHP4.1.1环境下通过检验。







这些例子仅用于说明问题
不是为了某一个产品。Melonfire网站不对文中的源代码提供任何授权或支持。本文版权为Melonfire网站所有, 原文出处http://www.devshed.com/Server_Side/PHP/PHPRDF/page1.html
责任编辑:semirock