分类广告


推荐文章

  • 没有找到任何内容!
您当前的位置:中国站长下载网络编程PHP专区 → 文章内容

如何用PHP把RDF内容插入Web站点之中(2)

  • 作者:佚名    来源:不详    发布时间:2006-2-26 1:57:48
  • 字体大小:
鲜肉



既然从技术上讲
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>标记就显示一定的输出。你可以看一下下面的运行结果<