ConLite/pear/XML/Parser.php

356 lignes
9.1 KiB
PHP

<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Stig Bakken <ssb@fast.no> |
// +----------------------------------------------------------------------+
//
// $Id$
cInclude('pear', 'PEAR.php');
/**
* XML Parser class. This is an XML parser based on PHP's "xml" extension,
* based on the bundled expat library.
*
* @author Stig Bakken <ssb@fast.no>
* @todo Tests that need to be made:
* - error class
* - mixing character encodings
* - a test using all expat handlers
* - options (folding, output charset)
* - different parsing modes
*
* @notes - It requires PHP 4.0.4pl1 or greater
* - From revision 1.17, the function names used by the 'func' mode
* are in the format "xmltag_$elem", for example: use "xmltag_name"
* to handle the <name></name> tags of your xml file.
*/
class XML_Parser extends PEAR
{
// {{{ properties
/**
* @var resource XML parser handle
*/
var $parser;
/**
* @var resource File handle if parsing from a file
*/
var $fp;
/**
* @var boolean Whether to do case folding
*/
var $folding = true;
/**
* @var string Mode of operation, one of "event" or "func"
*/
var $mode;
/**
* Mapping from expat handler function to class method.
*
* @var array
*/
var $handler = array(
'character_data_handler' => 'cdataHandler',
'default_handler' => 'defaultHandler',
'processing_instruction_handler' => 'piHandler',
'unparsed_entity_decl_handler' => 'unparsedHandler',
'notation_decl_handler' => 'notationHandler',
'external_entity_ref_handler' => 'entityrefHandler'
);
/**
* @var string source encoding
*/
var $srcenc;
/**
* @var string target encoding
*/
var $tgtenc;
/*
* Use call_user_func when php >= 4.0.7
* @var boolean
* @see setMode()
*/
var $use_call_user_func = true;
// }}}
// {{{ constructor
/**
* Creates an XML parser.
*
* @param string source charset encoding, use NULL (default) to use
* whatever the document specifies
* @param string how this parser object should work, "event" for
* startelement/endelement-type events, "func"
* to have it call functions named after elements
*
* @see xml_parser_create
*/
function __construct($srcenc = null, $mode = "event", $tgtenc = null)
{
$this->PEAR('XML_Parser_Error');
if ($srcenc === null) {
$xp = @xml_parser_create();
} else {
$xp = @xml_parser_create($srcenc);
}
if (is_resource($xp)) {
if ($tgtenc !== null) {
if (!@xml_parser_set_option($xp, XML_OPTION_TARGET_ENCODING,
$tgtenc)) {
return $this->raiseError("invalid target encoding");
}
}
$this->parser = $xp;
$this->setMode($mode);
xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, $this->folding);
}
$this->srcenc = $srcenc;
$this->tgtenc = $tgtenc;
}
// }}}
// {{{ setMode()
/**
* Sets the mode and all handler.
*
* @param string
* @see $handler
*/
function setMode($mode)
{
$this->mode = $mode;
xml_set_object($this->parser, $this);
switch ($mode) {
case "func":
// use call_user_func() when php >= 4.0.7
// or call_user_method() if not
if (version_compare(phpversion(), '4.0.7', 'lt')) {
$this->use_call_user_func = false;
} else {
$this->use_call_user_func = true;
}
xml_set_element_handler($this->parser, "funcStartHandler", "funcEndHandler");
break;
case "event":
xml_set_element_handler($this->parser, "startHandler", "endHandler");
break;
}
foreach ($this->handler as $xml_func => $method)
if (method_exists($this, $method)) {
$xml_func = "xml_set_" . $xml_func;
$xml_func($this->parser, $method);
}
}
// }}}
// {{{ setInputFile()
/**
* Defines
*
* @param string Filename (full path)
* @return resource fopen handle of the given file
* @throws XML_Parser_Error
* @see setInput(), parse()
* @access public
*/
function setInputFile($file)
{
$fp = @fopen($file, "rb");
if (is_resource($fp)) {
$this->fp = $fp;
return $fp;
}
return $this->raiseError($php_errormsg);
}
// }}}
// {{{ setInput()
/**
* Sets the file handle to use with parse().
*
* @param resource fopen
* @access public
* @see parse(), setInputFile()
*/
function setInput($fp)
{
if (is_resource($fp)) {
$this->fp = $fp;
return true;
}
return $this->raiseError("not a file resource");
}
// }}}
// {{{ parse()
/**
* Central parsing function.
*
* @throws XML_Parser_Error
* @return boolean true on success
* @see parseString()
* @access public
*/
function parse()
{
if (!is_resource($this->fp)) {
return $this->raiseError("no input");
}
while ($data = fread($this->fp, 2048)) {
$err = $this->parseString($data, feof($this->fp));
if (PEAR::isError($err)) {
fclose($this->fp);
return $err;
}
}
fclose($this->fp);
return true;
}
// }}}
// {{{ parseString()
/**
* Parses a string.
*
* @param string XML data
* @param boolean ???
* @throws XML_Parser_Error
* @return mixed true on success or a string with the xml parser error
*/
function parseString($data, $eof = false)
{
if (!xml_parse($this->parser, $data, $eof)) {
$err = $this->raiseError($this->parser);
xml_parser_free($this->parser);
return $err;
}
return true;
}
// }}}
// {{{ funcStartHandler()
function funcStartHandler($xp, $elem, $attribs)
{
$func = 'xmltag_' . $elem;
if (method_exists($this, $func)) {
if ($this->use_call_user_func) {
call_user_func(array(&$this, $func), $xp, $elem, $attribs);
} else {
call_user_method($func, $this, $xp, $elem, $attribs);
}
}
}
// }}}
// {{{ funcEndHandler()
function funcEndHandler($xp, $elem)
{
$func = 'xmltag_' . $elem . '_';
if (method_exists($this, $func)) {
if ($this->use_call_user_func) {
call_user_func(array(&$this, $func), $xp, $elem);
} else {
call_user_method($func, $this, $xp, $elem);
}
}
}
// }}}
// {{{ startHandler()
/**
*
* @abstract
*/
function startHandler($xp, $elem, &$attribs)
{
return NULL;
}
// }}}
// {{{ endHandler()
/**
*
* @abstract
*/
function endHandler($xp, $elem)
{
return NULL;
}
// }}}
}
class XML_Parser_Error extends PEAR_Error
{
// {{{ properties
var $error_message_prefix = 'XML_Parser: ';
// }}}
// {{{ constructor()
function __construct($msgorparser = 'unknown error', $code = 0, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE)
{
if (is_resource($msgorparser)) {
$code = xml_get_error_code($msgorparser);
$msgorparser = sprintf("%s at XML input line %d",
xml_error_string($code),
xml_get_current_line_number($msgorparser));
}
$this->PEAR_Error($msgorparser, $code, $mode, $level);
}
// }}}
}
?>