最近,公司交给我一项学习XML的任务。OK,但它不是技术上的XML,而是RDF。但是我发现PHP中的XML 分析函数同样可以工作。我分析的是DMOZ(http://www.dmoz.org/),但是为了简单,我将只使用XML的基本 东西,在你的时间里,自由去分析DMOZ ;o)
开始之前,先要确定你所拥有的PHP二进制执行码编译时是带'--with-xml'选项的。如果是这样的,你 就可以开始分析XML了。接着从Slashdot的主页上抓取XML文件(http://www.slashdot.org/slashdot.xml)。 Slashdot有一个相当简单的文件,非常容易分析。
记住对XML的处理很象处理数据库中的表。你会得到xml分析器的一个结果索引,象是XML文档的一个"假" 表。一旦清楚了不同之处,就可以立刻开始分析了。
PHP的XML函数允许你指定三个函数,用来处理XML文件中的数据。一个函数用来处理开标记,一个处理 两个标记之间的数据,另一个处理闭标记。根据传给你的标记的名字,你就可以按照意愿操作数据了。为了 开始,需要查看XML文件,找出文件中的标记。在slashdot文件中,包含有STORY,TITLE,URL,TIME,AUTHOR, DEPARTMENT,TOPIC,COMMENTS,SECTION和IMAGE标记。在某种情况下可能还有一些属性,例如HREF在HTML 中是A标记的属性。PHP有一种非常“酷”的方法来自动地处理属性。接着需要在脚本中定义这些标记。
< ?php
$open_tags = array( 'STORY' => '< STORY> ', 'TITLE' => '< TITLE> ', 'URL' => '< URL> ');
$close_tags = array( 'STORY' => '< /STORY> ', 'TITLE' => '< /TITLE> ', 'URL' => '< /URL> ');
?>
我只想分析上面的数据,因为我只想处理这些Slashbox其中之一。在列表的后面是用来提取数据的函数。 下面就是我所创建的函数。
< ?php
// 处理开标记的属性 // $attrs 是一个多维数组,以属性名为键值,值为它的属性值 function startElement($parser, $name, $attrs=''){ global $open_tags, $temp, $current_tag; $current_tag = $name; if ($format = $open_tags[$name]){ switch($name){ case 'STORY': echo 'New Story: '; break; default: break; } } }
// $current_tag 用来表示当前正在处理的标记, // 后面将在characterData函数中使用 // // 当看到一个< /STORY> 标记时,这时就应该输出临时变量 // 并且准备转移到下一个标记 function endElement($parser, $name, $attrs=''){ global $close_tags, $temp, $current_tag; if ($format = $close_tags[$name]){ switch($name){ case 'STORY': return_page($temp); $temp = ''; break; default: break; } } }
// 在两个元素间的数据将传给这个函数, // 那么在< TITLE> Title Here< /TITLE> 这行中, // $data将等于'Title Here' function characterData($parser, $data){ global $current_tag, $temp, $catID; switch($current_tag){ case 'TITLE': $temp['title'] = $data; $current_tag = ''; break; case 'URL': $temp['url'] = $data; $current_tag = ''; break; default: break; } }
?>
如你所见,到目前为止用PHP分析XML一切很顺利。下面是有趣的部分 -- 分析文件!要对文件进行分析, 需要剩下的代码,它们相当简单。
< ?php
function return_page(){ global $temp; echo 'o < A HREF="'.$temp['url'].'"> '.$temp['title'].'< /A> < BR> '; }
// 我们正在分析什么? $xml_file = 'slashdot.xml';
// 声时字符集 - 缺省为UTF-8 $type = 'UTF-8';
// 创建分析器 $xml_parser = xml_parser_create($type);
// 设置一些分析选项 xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true); xml_parser_set_option($xml_parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
// 告诉PHP,当找到一个标记时应该调用哪一个函 // 数,而且这些函数也会处理元素的属性 xml_set_element_handler($xml_parser, 'startElement','endElement');
// 告诉PHP,用哪一个函数来处理字符数据 xml_set_character_data_handler($xml_parser, 'characterData');
if (!($fp = fopen($xml_file, 'r'))) { die("Could not open $xml_file for parsing!n"); }
// 循环处理文件 while ($data = fread($fp, 4096)) { if (!($data = utf8_encode($data))) { echo 'ERROR'."n"; } if (!xml_parse($xml_parser, $data, feof($fp))) { die(sprintf( "XML error: %s at line %dnn", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser))); } }
xml_parser_free($xml_parser);
?>
现在发生了这些事情:PHP开始处理,直到它找到< ELEMENT ATTRIBUTE='bold'> 。然后将ELEMENT和它的 属性传给startElement函数。因为Slashdot文件没有任何属性,所以不必担心。但是如果文件有属性,应该 在这里处理它们。然后PHP将闭元素与开元素之间的数据传给characterData函数,最后将闭元素和它的属性 传给endElement函数。endElement函数调用了return_page()函数,但是只有当碰到故事结束时才会调用。在 这个时候,$temp变量保存着从startElement和characterData所收集来的数据。
现在最后要做的就是在cron[注1]中加入一条wget了!
--------------------------------------------------------------------------------
[注1] cron是在unix/linux中自动定时处理守护,可以将一些想定时处理的工作交给它来完成。详细的请参阅 unix/linux手册。
|