PHP用SAX解析XMLの実現コードと問題分析

3693 ワード

 
<?php
$g_books = array();
$g_elem = null;
function startElement( $parser, $name, $attrs )
{
global $g_books, $g_elem;
if ( $name == 'BOOK' ) $g_books []= array();
$g_elem = $name;
}
function endElement( $parser, $name )
{
global $g_elem;
$g_elem = null;
}
function textData( $parser, $text )
{
global $g_books, $g_elem;
if ( $g_elem == 'AUTHOR' ||
$g_elem == 'PUBLISHER' ||
$g_elem == 'TITLE' )
{
$g_books[ count( $g_books ) - 1 ][ $g_elem ] = $text;
}
}
$parser = xml_parser_create();
xml_set_element_handler( $parser, "startElement", "endElement" );
xml_set_character_data_handler( $parser, "textData" );
$f = fopen( 'books.xml', 'r' );
while( $data = fread( $f, 4096 ) )
{
xml_parse( $parser, $data );
}
xml_parser_free( $parser );
foreach( $g_books as $book )
{
echo $book['TITLE']." - ".$book['AUTHOR']." - ";
echo $book['PUBLISHER']."
";
}
?>
PHPにおいてSAX方式でXMLで発見された問題XMLを解析すると、以下のようになります。class.php
 
<?xml version="1.0" encoding="GBK"?>
<result>
<row>
<id>1047869</id>
<date>2008-08-28 14:54:51</date>
<title> -- </title>
<summary> , ,3、4000 , , , , , ? , , 。 </summary>
</row>
...( )
</result>
search.php
 
<?php
class xml {
var $parser;
var $i =0;
var $search_result = array();
var $row = array();
var $data = array();
var $now_tag;
var $tags = array("ID", "CLASSID", "SUBCLASSID", "CLASSNAME", "TITLE", "SHORTTITLE", "AUTHOR", "PRODUCER", "SUMMARY", "CONTENT", "DATE");
function xml()
{
$this->parser = xml_parser_create();
xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser, "tag_open", "tag_close");
xml_set_character_data_handler($this->parser, "cdata");
}
function parse($data)
{
xml_parse($this->parser, $data);
}
function tag_open($parser, $tag, $attributes)
{
$this->now_tag=$tag;
if($tag=='RESULT') {
$this->search_result = $attributes;
}
if($tag=='ROW') {
$this->row[$this->i] = $attributes;
}
}
function cdata($parser, $cdata)
{
if(in_array($this->now_tag, $this->tags)){
$tagname = strtolower($this->now_tag);
$this->data[$this->i][$tagname] = $cdata;
}
}
function tag_close($parser, $tag)
{
$this->now_tag="";
if($tag=='ROW') {
$this->i++;
}
}
}
?>
最終的に得た結果の中でsummaryのデータは少なくなりました。いつも完全なsummaryの内容が得られません。たまに文字化けがありますが、ネットで探してみましたが、何の問題が起きたのか分かりません。後になって問題を発見したのはxml_のためです。パーサー解析XMLはループ処理ノードの中のデータで、毎回大体300文字の長さだけを取っています。(具体的にはいくらですか?私もよく分かりません。streenで出力するだけで、300ぐらいです。)すると、毎回の循環で前回のデータをコピーしてしまうので、データが不完全な問題が発生します。解決策はxmlを使うことです。classファイルの中のxml類のcdataメソッドの中で$this->data[$this->i]==cdata;に変更しました。すぐ解決できます。(中にはNOTICEエラーがあります。PHPは無視しました。)