<?php/*****************************************************************************
 *       XMLRead 类 (xmlread.php)   *
 *       描述:XML文件数据读取类(SAX 解析)  *
 *       运行环境: PHP4 iconv() 函数支持              *
 *****************************************************************************/
class xmlRead
{
//解析器
var $var_parser;

//xml文件编码语言
var $var_lang = 'GB2312';

//*****************************************************
// $var_node[深度][节点名]    node_name
// $var_node[深度][目标类型]  target_type
// $var_node[深度][目标名称]  target_name
// 目标: 属性/子节点; 0/1 
// 深度: 数字 - by Mayer
//*****************************************************
var $var_node = array();
var $var_index = array();

var $var_stack = array(); //标记栈
var $var_stack_attrs = array(); //参数栈

//节点深度
var $var_depth = 0;

// $var_data[深度]; $var_data[0] 用来存 xml文件所有记录
var $var_data = array(); //数据

function xmlRead($file,$node='',$lang)
{
if(is_array($node))
{
$this->var_node = $node;
}
if($file)
{

if('UTF-8' == strtoupper($lang))
{
$this->var_parser = xml_parser_create('UTF-8');
}
else
{
$this->var_parser = xml_parser_create();
if('GBK' == strtoupper($lang))
{
$this->var_lang = $lang;
}
}
xml_set_object($this->var_parser,&$this);
xml_parser_set_option($this->var_parser, XML_OPTION_CASE_FOLDING, 0);
xml_set_element_handler($this->var_parser, "startElement", "endElement");
xml_set_character_data_handler($this->var_parser, "characterData");

$this->xmlRead_parser_file($file);
}
}

/******************************************************
* 获取xml数据记录  -by Mayer 2005-1-17
******************************************************/
function xmlRead_get_ret()
{
return $this->var_data[0];
}

function xmlRead_parser_file($file)
{
if (!($fp = fopen($file, "r")))
{
    die("could not open XML input");
}
$data = fread($fp, 4096);
if('GBK' == $this->var_lang)
{
//$data = str_replace(array('utf-8','gb2312','UTF-8','GB2312'),'GBK',$data);
$data = preg_replace("/encoding=(.+)\?\>/",'encoding="GBK" ?>',$data);
}

elseif('UTF-8' == $this->var_lang)
{

}
do
{
    if(!xml_parse($this->var_parser, $data, feof($fp)))
    {
        die(sprintf("XML error: %s at line %d",
                    xml_error_string(xml_get_error_code($this->var_parser)),
                    xml_get_current_line_number($this->var_parser)
                   )
            );
    }
}while($data = fread($fp, 4096));
xml_parser_free($this->var_parser);
}

function startElement($parser, $name, $attrs)
{
if(function_exists('iconv'))
{
$name = iconv('UTF-8', $this->var_lang, $name);
}

//节点开始, 节点名入栈
array_push($this->var_stack,$name);
array_push($this->var_stack_attrs,$attrs);
//设置节点深度
$this->var_depth = count($this->var_stack) - 1;


if($this->var_depth > 0)
{

//判断现在是否只有一个同级同名兄弟结点
// 当前深度标识的数据是否为一数组 && 是否存在同级同名索引为 $this->var_index[$this->var_depth][$name]] 的记录存在
// 或同级同名兄弟结点数据为字符串
if(is_array($this->var_data[$this->var_depth][$name]) && !isset($this->var_data[$this->var_depth][$name][$this->var_index[$this->var_depth][$name]]) || is_string($this->var_data[$this->var_depth][$name]))
{
//判断是否有索引设置
if($this->var_node[$this->var_depth]['node_name'] == $name)
{
//如果索引值不存在...
if(!$this->var_index[$this->var_depth][$name])
{
if(intval($this->var_node[$this->var_depth]['target_type']) == 1)
{
$index = $this->var_data[$this->var_depth][$name][$this->var_node[$this->var_depth]['target_name']];
if(is_array($index))
{
$this->var_index[$this->var_depth][$name] = 0;
}
}
else
{
$this->var_index[$this->var_depth][$name] = $attrs[$this->var_node[$this->var_depth]['target_name']];
}
}
}
else 
{
$this->var_index[$this->var_depth][$name] = 0;
}
$this->var_data[$this->var_depth][$name] = array($this->var_index[$this->var_depth][$name]=>$this->var_data[$this->var_depth][$name]);
}

}
//检查节点类型, 
}

解决方案 »

  1.   

    function endElement($parser, $name)
    {
    if(function_exists('iconv'))
    {
    $name = iconv('UTF-8', $this->var_lang, $name);
    }
    //判断下级结点数据是否存在
    if(is_array($this->var_data[$this->var_depth+1]) && count($this->var_data[$this->var_depth+1]))
    {
    //判断同级结点是否存在 如在标签结束时同级结点存在的话那在这级同名结点为多数 同级同名首结点在startElement里判断并重命名索引
    //同级同名索引存在否 && 同级同名索引数据存在否
    if(isset($this->var_index[$this->var_depth][$name]) && isset($this->var_data[$this->var_depth][$name][$this->var_index[$this->var_depth][$name]]))
    {
    //判断是否要设置结点索引
    if($this->var_node[$this->var_depth]['node_name'] == $name)
    {
    if($this->var_node[$this->var_depth]['target_type'] == 0)
    {
    $attrs = end($this->var_stack_attrs);
    if(count($attrs))
    {
    $index = $attrs[$this->var_node[$this->var_depth]['target_name']];
    }
    }
    else
    {
    $index = $this->var_data[$this->var_depth+1][$this->var_node[$this->var_depth]['target_name']];
    }
    $this->var_data[$this->var_depth][$name][$index] = $this->var_data[$this->var_depth+1];
    }
    else 
    {
    $this->var_data[$this->var_depth][$name][] = $this->var_data[$this->var_depth+1];
    }
    }
    else 
    {
    $this->var_data[$this->var_depth][$name] = $this->var_data[$this->var_depth+1];
    //在还没有同级结点的时候,判断是否要设置索引
    if($this->var_node[$this->var_depth]['node_name'] == $name)
    {
    if(intval($this->var_node[$this->var_depth]['target_type']) == 1)
    {
    $index = $this->var_data[$this->var_depth][$name][$this->var_node[$this->var_depth]['target_name']];
    if(is_array($index))
    {
    $index = 0;
    }
    }
    else
    {
    $attrs = end($this->var_stack_attrs);
    $index = $attrs[$this->var_node[$this->var_depth]['target_name']];
    }

    //设置索引值
    $this->var_index[$this->var_depth][$name] = $index;
    }
    else 
    {
    //索引默认为 0
    $this->var_index[$this->var_depth][$name] = 0;
    }
    }
    }
    unset($this->var_data[$this->var_depth+1]);
    unset($this->var_index[$this->var_depth+1]);
    //print_r($this->var_data[$this->var_depth][$name]);
    //echo " : $name<br>";
    //节点结束, 节点名出栈
    array_pop($this->var_stack);
    array_pop($this->var_stack_attrs);
    $this->var_depth = count($this->var_stack) - 1;
    }

    function characterData($parser,$data)
    {
    if(trim($data) !== '')
    {
    $name = end($this->var_stack);
    if(function_exists('iconv'))
    {
    $data = iconv('UTF-8', $this->var_lang, $data);
    }
    //echo $data."<br>";
    //判断是否已经有同级并同名的记录存在
    if(is_array($this->var_data[$this->var_depth][$name]))
    {
    //判断是否要设置结点索引
    if($this->var_node[$this->var_depth]['node_name'] == $name && $this->var_node[$this->var_depth]['target_type'] == 0)
    {
    $attrs = end($this->var_stack_attrs);
    if(count($attrs))
    {
    $index = $attrs[$this->var_node[$this->var_depth]['target_name']];
    }
    $this->var_data[$this->var_depth][$name][$index] = $data;
    }
    else 
    {
    $this->var_data[$this->var_depth][$name][] = $data;
    }
    }
    else
    {
    $this->var_data[$this->var_depth][$name] = $data;
    //在还没有同级结点的时候,判断是否要设置索引
    if($this->var_node[$this->var_depth]['node_name'] == $name && $this->var_node[$this->var_depth]['target_type'] == 0)
    {
    $attrs = end($this->var_stack_attrs);
    $index = $attrs[$this->var_node[$this->var_depth]['target_name']];

    //设置索引值
    $this->var_index[$this->var_depth][$name] = $index;
    }
    else 
    {
    //索引默认为 0
    $this->var_index[$this->var_depth][$name] = 0;
    }
    }
    }
    }
    }

    /*
    //------------------------ XMLREAD 类的用法如下 ------------------------------------------------------
    $node = array();
    switch($_REQUEST['t'])
    {
    case 1 : {//----解析编码为UTF-8格式的XML文件,标签为中文---------------------------------
    $file = 'test_mod.xml';
    $lang = 'UTF-8';
    break;
     }
    case 2 : {//----解析编码为GB2312格式的XML文件------------------------------------------
    $file = 'ex34.xml';
    $lang = 'GB2312';
    break;
     }
    case 3 : {//----解析含有GBK繁体字数据的XML文件------------------------------------------
    $file = 'week_game.xml';
    $lang = 'GBK';
    break;
     }
    case 4 : {//----解析含有GBK繁体字数据的XML文件,并指定第2级名为m的结点的索引(数组下标)为其子结点i的值---
    $file = 'week_game.xml';
    $node[2] = array(
    'node_name'=>'m',
    'target_type'=>1,
    'target_name'=>'i'
       );
    $lang = 'GBK';
    break;
     }
    case 5 : {//解析含有GBK繁体字数据的XML文件,并指定索引------------------------------------
    $file = 'Europe_Full.xml';
    $node[1] = array(
    'node_name'=>'d',
    'target_type'=>0,
    'target_name'=>'d'
       );
    $node[2] = array(
    'node_name'=>'m',
    'target_type'=>1,
    'target_name'=>'i'
       );
    $lang = 'GBK';
    break;
     }
    default :{//---------------------------------------
    $file = 'test_mod.xml';
    $lang = 'UTF-8';
    break;
     }
    }

    $xml = new xmlRead($file,$node,$lang);
    echo "<pre>";
    print_r($xml->xmlRead_get_ret());
    echo "</pre>";
    */
    ?>
      

  2.   

    如果用php5有直接支持xml的函数
    :)
      

  3.   

    2、3楼的XML类经实验证明,超过5000条数据效率太低了,超过1万天down机~~~
    PHP5中的SimpleXML 还不错
      

  4.   

    偶最近也刚写了一个FOR PHP4的类库
    源代码:http://www.phpsalon.com/