2010-03-10 15:03:40 +03:00
|
|
|
<?php
|
2012-05-11 22:25:00 +04:00
|
|
|
|
|
|
|
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
2010-03-10 15:03:40 +03:00
|
|
|
|
|
|
|
/**
|
2012-05-11 22:25:00 +04:00
|
|
|
* XML_Parser
|
2010-03-10 15:03:40 +03:00
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* XML Parser package
|
|
|
|
*
|
|
|
|
* PHP versions 4 and 5
|
|
|
|
*
|
|
|
|
* LICENSE:
|
2010-03-10 15:03:40 +03:00
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* Copyright (c) 2002-2008 The PHP Group
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* * The name of the author may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
|
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* @category XML
|
|
|
|
* @package XML_Parser
|
|
|
|
* @author Stig Bakken <ssb@fast.no>
|
|
|
|
* @author Tomas V.V.Cox <cox@idecnet.com>
|
|
|
|
* @author Stephan Schmidt <schst@php.net>
|
|
|
|
* @copyright 2002-2008 The PHP Group
|
|
|
|
* @license http://opensource.org/licenses/bsd-license New BSD License
|
|
|
|
* @version CVS: $Id: Parser.php 302733 2010-08-24 01:09:09Z clockwerx $
|
|
|
|
* @link http://pear.php.net/package/XML_Parser
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* uses PEAR's error handling
|
|
|
|
*/
|
2012-05-11 22:25:00 +04:00
|
|
|
require_once 'PEAR.php';
|
2010-03-10 15:03:40 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* resource could not be created
|
|
|
|
*/
|
|
|
|
define('XML_PARSER_ERROR_NO_RESOURCE', 200);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* unsupported mode
|
|
|
|
*/
|
|
|
|
define('XML_PARSER_ERROR_UNSUPPORTED_MODE', 201);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* invalid encoding was given
|
|
|
|
*/
|
|
|
|
define('XML_PARSER_ERROR_INVALID_ENCODING', 202);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* specified file could not be read
|
|
|
|
*/
|
|
|
|
define('XML_PARSER_ERROR_FILE_NOT_READABLE', 203);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* invalid input
|
|
|
|
*/
|
|
|
|
define('XML_PARSER_ERROR_INVALID_INPUT', 204);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* remote file cannot be retrieved in safe mode
|
|
|
|
*/
|
|
|
|
define('XML_PARSER_ERROR_REMOTE', 205);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* XML Parser class.
|
|
|
|
*
|
|
|
|
* This is an XML parser based on PHP's "xml" extension,
|
|
|
|
* based on the bundled expat library.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
* - different parsing modes
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
|
|
|
* @category XML
|
|
|
|
* @package XML_Parser
|
|
|
|
* @author Stig Bakken <ssb@fast.no>
|
|
|
|
* @author Tomas V.V.Cox <cox@idecnet.com>
|
|
|
|
* @author Stephan Schmidt <schst@php.net>
|
|
|
|
* @copyright 2002-2008 The PHP Group
|
|
|
|
* @license http://opensource.org/licenses/bsd-license New BSD License
|
|
|
|
* @version Release: @package_version@
|
|
|
|
* @link http://pear.php.net/package/XML_Parser
|
|
|
|
* @todo create XML_Parser_Namespace to parse documents with namespaces
|
|
|
|
* @todo create XML_Parser_Pull
|
|
|
|
* @todo Tests that need to be made:
|
|
|
|
* - mixing character encodings
|
|
|
|
* - a test using all expat handlers
|
|
|
|
* - options (folding, output charset)
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
class XML_Parser extends PEAR
|
|
|
|
{
|
|
|
|
// {{{ properties
|
|
|
|
|
2012-05-11 22:25:00 +04:00
|
|
|
/**
|
2010-03-10 15:03:40 +03:00
|
|
|
* XML parser handle
|
|
|
|
*
|
|
|
|
* @var resource
|
|
|
|
* @see xml_parser_create()
|
|
|
|
*/
|
|
|
|
var $parser;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* File handle if parsing from a file
|
|
|
|
*
|
|
|
|
* @var resource
|
|
|
|
*/
|
|
|
|
var $fp;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether to do case folding
|
|
|
|
*
|
|
|
|
* If set to true, all tag and attribute names will
|
|
|
|
* be converted to UPPER CASE.
|
|
|
|
*
|
|
|
|
* @var boolean
|
|
|
|
*/
|
|
|
|
var $folding = true;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mode of operation, one of "event" or "func"
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
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'
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* source encoding
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
var $srcenc;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* target encoding
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
var $tgtenc;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* handler object
|
|
|
|
*
|
|
|
|
* @var object
|
|
|
|
*/
|
|
|
|
var $_handlerObj;
|
|
|
|
|
2012-05-11 22:25:00 +04:00
|
|
|
/**
|
|
|
|
* valid encodings
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
var $_validEncodings = array('ISO-8859-1', 'UTF-8', 'US-ASCII');
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// {{{ php4 constructor
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates an XML parser.
|
|
|
|
*
|
|
|
|
* This is needed for PHP4 compatibility, it will
|
|
|
|
* call the constructor, when a new instance is created.
|
|
|
|
*
|
|
|
|
* @param string $srcenc source charset encoding, use NULL (default) to use
|
|
|
|
* whatever the document specifies
|
|
|
|
* @param string $mode how this parser object should work, "event" for
|
|
|
|
* startelement/endelement-type events, "func"
|
|
|
|
* to have it call functions named after elements
|
|
|
|
* @param string $tgtenc a valid target encoding
|
|
|
|
*/
|
|
|
|
function XML_Parser($srcenc = null, $mode = 'event', $tgtenc = null)
|
|
|
|
{
|
|
|
|
XML_Parser::__construct($srcenc, $mode, $tgtenc);
|
|
|
|
}
|
2010-03-10 15:03:40 +03:00
|
|
|
// }}}
|
2012-05-11 22:25:00 +04:00
|
|
|
// {{{ php5 constructor
|
2010-03-10 15:03:40 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* PHP5 constructor
|
|
|
|
*
|
|
|
|
* @param string $srcenc source charset encoding, use NULL (default) to use
|
|
|
|
* whatever the document specifies
|
|
|
|
* @param string $mode how this parser object should work, "event" for
|
|
|
|
* startelement/endelement-type events, "func"
|
|
|
|
* to have it call functions named after elements
|
2012-05-11 22:25:00 +04:00
|
|
|
* @param string $tgtenc a valid target encoding
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
function __construct($srcenc = null, $mode = 'event', $tgtenc = null)
|
|
|
|
{
|
|
|
|
$this->PEAR('XML_Parser_Error');
|
|
|
|
|
|
|
|
$this->mode = $mode;
|
|
|
|
$this->srcenc = $srcenc;
|
|
|
|
$this->tgtenc = $tgtenc;
|
|
|
|
}
|
|
|
|
// }}}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the mode of the parser.
|
|
|
|
*
|
|
|
|
* Possible modes are:
|
|
|
|
* - func
|
|
|
|
* - event
|
|
|
|
*
|
|
|
|
* You can set the mode using the second parameter
|
|
|
|
* in the constructor.
|
|
|
|
*
|
|
|
|
* This method is only needed, when switching to a new
|
|
|
|
* mode at a later point.
|
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @param string $mode mode, either 'func' or 'event'
|
|
|
|
*
|
|
|
|
* @return boolean|object true on success, PEAR_Error otherwise
|
|
|
|
* @access public
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
function setMode($mode)
|
|
|
|
{
|
|
|
|
if ($mode != 'func' && $mode != 'event') {
|
2012-05-11 22:25:00 +04:00
|
|
|
$this->raiseError('Unsupported mode given',
|
|
|
|
XML_PARSER_ERROR_UNSUPPORTED_MODE);
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
$this->mode = $mode;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the object, that will handle the XML events
|
|
|
|
*
|
|
|
|
* This allows you to create a handler object independent of the
|
|
|
|
* parser object that you are using and easily switch the underlying
|
|
|
|
* parser.
|
|
|
|
*
|
|
|
|
* If no object will be set, XML_Parser assumes that you
|
|
|
|
* extend this class and handle the events in $this.
|
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @param object &$obj object to handle the events
|
|
|
|
*
|
|
|
|
* @return boolean will always return true
|
|
|
|
* @access public
|
|
|
|
* @since v1.2.0beta3
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
function setHandlerObj(&$obj)
|
|
|
|
{
|
|
|
|
$this->_handlerObj = &$obj;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Init the element handlers
|
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @return mixed
|
|
|
|
* @access private
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
function _initHandlers()
|
|
|
|
{
|
|
|
|
if (!is_resource($this->parser)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_object($this->_handlerObj)) {
|
|
|
|
$this->_handlerObj = &$this;
|
|
|
|
}
|
|
|
|
switch ($this->mode) {
|
|
|
|
|
2012-05-11 22:25:00 +04:00
|
|
|
case 'func':
|
|
|
|
xml_set_object($this->parser, $this->_handlerObj);
|
|
|
|
xml_set_element_handler($this->parser,
|
|
|
|
array(&$this, 'funcStartHandler'), array(&$this, 'funcEndHandler'));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'event':
|
|
|
|
xml_set_object($this->parser, $this->_handlerObj);
|
|
|
|
xml_set_element_handler($this->parser, 'startHandler', 'endHandler');
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return $this->raiseError('Unsupported mode given',
|
|
|
|
XML_PARSER_ERROR_UNSUPPORTED_MODE);
|
|
|
|
break;
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set additional handlers for character data, entities, etc.
|
|
|
|
*/
|
|
|
|
foreach ($this->handler as $xml_func => $method) {
|
|
|
|
if (method_exists($this->_handlerObj, $method)) {
|
|
|
|
$xml_func = 'xml_set_' . $xml_func;
|
|
|
|
$xml_func($this->parser, $method);
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
}
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// {{{ _create()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create the XML parser resource
|
|
|
|
*
|
|
|
|
* Has been moved from the constructor to avoid
|
|
|
|
* problems with object references.
|
|
|
|
*
|
|
|
|
* Furthermore it allows us returning an error
|
|
|
|
* if something fails.
|
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* NOTE: uses '@' error suppresion in this method
|
2010-03-10 15:03:40 +03:00
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @return bool|PEAR_Error true on success, PEAR_Error otherwise
|
|
|
|
* @access private
|
2010-03-10 15:03:40 +03:00
|
|
|
* @see xml_parser_create
|
|
|
|
*/
|
|
|
|
function _create()
|
|
|
|
{
|
|
|
|
if ($this->srcenc === null) {
|
|
|
|
$xp = @xml_parser_create();
|
|
|
|
} else {
|
|
|
|
$xp = @xml_parser_create($this->srcenc);
|
|
|
|
}
|
|
|
|
if (is_resource($xp)) {
|
|
|
|
if ($this->tgtenc !== null) {
|
2012-05-11 22:25:00 +04:00
|
|
|
if (!@xml_parser_set_option($xp, XML_OPTION_TARGET_ENCODING,
|
|
|
|
$this->tgtenc)
|
|
|
|
) {
|
|
|
|
return $this->raiseError('invalid target encoding',
|
|
|
|
XML_PARSER_ERROR_INVALID_ENCODING);
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->parser = $xp;
|
2012-05-11 22:25:00 +04:00
|
|
|
$result = $this->_initHandlers($this->mode);
|
2010-03-10 15:03:40 +03:00
|
|
|
if ($this->isError($result)) {
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, $this->folding);
|
|
|
|
return true;
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
if (!in_array(strtoupper($this->srcenc), $this->_validEncodings)) {
|
|
|
|
return $this->raiseError('invalid source encoding',
|
|
|
|
XML_PARSER_ERROR_INVALID_ENCODING);
|
|
|
|
}
|
|
|
|
return $this->raiseError('Unable to create XML parser resource.',
|
|
|
|
XML_PARSER_ERROR_NO_RESOURCE);
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// {{{ reset()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset the parser.
|
|
|
|
*
|
|
|
|
* This allows you to use one parser instance
|
|
|
|
* to parse multiple XML documents.
|
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @return boolean|object true on success, PEAR_Error otherwise
|
|
|
|
*/
|
|
|
|
function reset()
|
|
|
|
{
|
|
|
|
$result = $this->_create();
|
2012-05-11 22:25:00 +04:00
|
|
|
if ($this->isError($result)) {
|
2010-03-10 15:03:40 +03:00
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// {{{ setInputFile()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the input xml file to be parsed
|
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @param string $file Filename (full path)
|
|
|
|
*
|
|
|
|
* @return resource fopen handle of the given file
|
|
|
|
* @access public
|
|
|
|
* @throws XML_Parser_Error
|
|
|
|
* @see setInput(), setInputString(), parse()
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
function setInputFile($file)
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* check, if file is a remote file
|
|
|
|
*/
|
2012-05-11 22:25:00 +04:00
|
|
|
if (preg_match('/^(http|ftp):\/\//i', substr($file, 0, 10))) {
|
2010-03-10 15:03:40 +03:00
|
|
|
if (!ini_get('allow_url_fopen')) {
|
2012-05-11 22:25:00 +04:00
|
|
|
return $this->
|
|
|
|
raiseError('Remote files cannot be parsed, as safe mode is enabled.',
|
|
|
|
XML_PARSER_ERROR_REMOTE);
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
|
|
|
|
$fp = @fopen($file, 'rb');
|
2010-03-10 15:03:40 +03:00
|
|
|
if (is_resource($fp)) {
|
|
|
|
$this->fp = $fp;
|
|
|
|
return $fp;
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
return $this->raiseError('File could not be opened.',
|
|
|
|
XML_PARSER_ERROR_FILE_NOT_READABLE);
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// {{{ setInputString()
|
2012-05-11 22:25:00 +04:00
|
|
|
|
2010-03-10 15:03:40 +03:00
|
|
|
/**
|
|
|
|
* XML_Parser::setInputString()
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* Sets the xml input from a string
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* @param string $data a string containing the XML document
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* @return null
|
2012-05-11 22:25:00 +04:00
|
|
|
*/
|
2010-03-10 15:03:40 +03:00
|
|
|
function setInputString($data)
|
|
|
|
{
|
|
|
|
$this->fp = $data;
|
|
|
|
return null;
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
|
2010-03-10 15:03:40 +03:00
|
|
|
// }}}
|
|
|
|
// {{{ setInput()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the file handle to use with parse().
|
|
|
|
*
|
|
|
|
* You should use setInputFile() or setInputString() if you
|
2012-05-11 22:25:00 +04:00
|
|
|
* pass a string
|
2010-03-10 15:03:40 +03:00
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @param mixed $fp Can be either a resource returned from fopen(),
|
|
|
|
* a URL, a local filename or a string.
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
* @access public
|
|
|
|
* @see parse()
|
|
|
|
* @uses setInputString(), setInputFile()
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
function setInput($fp)
|
|
|
|
{
|
|
|
|
if (is_resource($fp)) {
|
|
|
|
$this->fp = $fp;
|
|
|
|
return true;
|
2012-05-11 22:25:00 +04:00
|
|
|
} elseif (preg_match('/^[a-z]+:\/\//i', substr($fp, 0, 10))) {
|
|
|
|
// see if it's an absolute URL (has a scheme at the beginning)
|
2010-03-10 15:03:40 +03:00
|
|
|
return $this->setInputFile($fp);
|
2012-05-11 22:25:00 +04:00
|
|
|
} elseif (file_exists($fp)) {
|
|
|
|
// see if it's a local file
|
2010-03-10 15:03:40 +03:00
|
|
|
return $this->setInputFile($fp);
|
2012-05-11 22:25:00 +04:00
|
|
|
} else {
|
|
|
|
// it must be a string
|
2010-03-10 15:03:40 +03:00
|
|
|
$this->fp = $fp;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-05-11 22:25:00 +04:00
|
|
|
return $this->raiseError('Illegal input format',
|
|
|
|
XML_PARSER_ERROR_INVALID_INPUT);
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// {{{ parse()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Central parsing function.
|
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @return bool|PEAR_Error returns true on success, or a PEAR_Error otherwise
|
|
|
|
* @access public
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
function parse()
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* reset the parser
|
|
|
|
*/
|
|
|
|
$result = $this->reset();
|
|
|
|
if ($this->isError($result)) {
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
// if $this->fp was fopened previously
|
|
|
|
if (is_resource($this->fp)) {
|
2012-05-11 22:25:00 +04:00
|
|
|
|
2010-03-10 15:03:40 +03:00
|
|
|
while ($data = fread($this->fp, 4096)) {
|
|
|
|
if (!$this->_parseString($data, feof($this->fp))) {
|
|
|
|
$error = &$this->raiseError();
|
|
|
|
$this->free();
|
|
|
|
return $error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2012-05-11 22:25:00 +04:00
|
|
|
// otherwise, $this->fp must be a string
|
2010-03-10 15:03:40 +03:00
|
|
|
if (!$this->_parseString($this->fp, true)) {
|
|
|
|
$error = &$this->raiseError();
|
|
|
|
$this->free();
|
|
|
|
return $error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->free();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* XML_Parser::_parseString()
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
|
|
|
* @param string $data data
|
|
|
|
* @param bool $eof end-of-file flag
|
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* @return bool
|
|
|
|
* @access private
|
|
|
|
* @see parseString()
|
|
|
|
**/
|
|
|
|
function _parseString($data, $eof = false)
|
|
|
|
{
|
|
|
|
return xml_parse($this->parser, $data, $eof);
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
|
2010-03-10 15:03:40 +03:00
|
|
|
// }}}
|
|
|
|
// {{{ parseString()
|
|
|
|
|
|
|
|
/**
|
|
|
|
* XML_Parser::parseString()
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* Parses a string.
|
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @param string $data XML data
|
|
|
|
* @param boolean $eof If set and TRUE, data is the last piece
|
|
|
|
* of data sent in this parser
|
|
|
|
*
|
|
|
|
* @return bool|PEAR_Error true on success or a PEAR Error
|
|
|
|
* @throws XML_Parser_Error
|
|
|
|
* @see _parseString()
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
function parseString($data, $eof = false)
|
|
|
|
{
|
|
|
|
if (!isset($this->parser) || !is_resource($this->parser)) {
|
|
|
|
$this->reset();
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
|
2010-03-10 15:03:40 +03:00
|
|
|
if (!$this->_parseString($data, $eof)) {
|
2012-05-11 22:25:00 +04:00
|
|
|
$error = &$this->raiseError();
|
|
|
|
$this->free();
|
|
|
|
return $error;
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($eof === true) {
|
|
|
|
$this->free();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
|
2010-03-10 15:03:40 +03:00
|
|
|
/**
|
|
|
|
* XML_Parser::free()
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* Free the internal resources associated with the parser
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* @return null
|
|
|
|
**/
|
|
|
|
function free()
|
|
|
|
{
|
|
|
|
if (isset($this->parser) && is_resource($this->parser)) {
|
|
|
|
xml_parser_free($this->parser);
|
|
|
|
unset( $this->parser );
|
|
|
|
}
|
|
|
|
if (isset($this->fp) && is_resource($this->fp)) {
|
|
|
|
fclose($this->fp);
|
|
|
|
}
|
|
|
|
unset($this->fp);
|
|
|
|
return null;
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
|
2010-03-10 15:03:40 +03:00
|
|
|
/**
|
|
|
|
* XML_Parser::raiseError()
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* Throws a XML_Parser_Error
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* @param string $msg the error message
|
|
|
|
* @param integer $ecode the error message code
|
2012-05-11 22:25:00 +04:00
|
|
|
*
|
|
|
|
* @return XML_Parser_Error reference to the error object
|
2010-03-10 15:03:40 +03:00
|
|
|
**/
|
2012-05-11 22:25:00 +04:00
|
|
|
function &raiseError($msg = null, $ecode = 0)
|
2010-03-10 15:03:40 +03:00
|
|
|
{
|
|
|
|
$msg = !is_null($msg) ? $msg : $this->parser;
|
2012-05-11 22:25:00 +04:00
|
|
|
$err = &new XML_Parser_Error($msg, $ecode);
|
2010-03-10 15:03:40 +03:00
|
|
|
return parent::raiseError($err);
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
|
2010-03-10 15:03:40 +03:00
|
|
|
// }}}
|
|
|
|
// {{{ funcStartHandler()
|
|
|
|
|
2012-05-11 22:25:00 +04:00
|
|
|
/**
|
|
|
|
* derives and calls the Start Handler function
|
|
|
|
*
|
|
|
|
* @param mixed $xp ??
|
|
|
|
* @param mixed $elem ??
|
|
|
|
* @param mixed $attribs ??
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2010-03-10 15:03:40 +03:00
|
|
|
function funcStartHandler($xp, $elem, $attribs)
|
|
|
|
{
|
|
|
|
$func = 'xmltag_' . $elem;
|
2012-05-11 22:25:00 +04:00
|
|
|
$func = str_replace(array('.', '-', ':'), '_', $func);
|
2010-03-10 15:03:40 +03:00
|
|
|
if (method_exists($this->_handlerObj, $func)) {
|
|
|
|
call_user_func(array(&$this->_handlerObj, $func), $xp, $elem, $attribs);
|
|
|
|
} elseif (method_exists($this->_handlerObj, 'xmltag')) {
|
2012-05-11 22:25:00 +04:00
|
|
|
call_user_func(array(&$this->_handlerObj, 'xmltag'),
|
|
|
|
$xp, $elem, $attribs);
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// {{{ funcEndHandler()
|
|
|
|
|
2012-05-11 22:25:00 +04:00
|
|
|
/**
|
|
|
|
* derives and calls the End Handler function
|
|
|
|
*
|
|
|
|
* @param mixed $xp ??
|
|
|
|
* @param mixed $elem ??
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2010-03-10 15:03:40 +03:00
|
|
|
function funcEndHandler($xp, $elem)
|
|
|
|
{
|
|
|
|
$func = 'xmltag_' . $elem . '_';
|
2012-05-11 22:25:00 +04:00
|
|
|
$func = str_replace(array('.', '-', ':'), '_', $func);
|
2010-03-10 15:03:40 +03:00
|
|
|
if (method_exists($this->_handlerObj, $func)) {
|
|
|
|
call_user_func(array(&$this->_handlerObj, $func), $xp, $elem);
|
|
|
|
} elseif (method_exists($this->_handlerObj, 'xmltag_')) {
|
|
|
|
call_user_func(array(&$this->_handlerObj, 'xmltag_'), $xp, $elem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// {{{ startHandler()
|
|
|
|
|
|
|
|
/**
|
2012-05-11 22:25:00 +04:00
|
|
|
* abstract method signature for Start Handler
|
|
|
|
*
|
|
|
|
* @param mixed $xp ??
|
|
|
|
* @param mixed $elem ??
|
|
|
|
* @param mixed &$attribs ??
|
2010-03-10 15:03:40 +03:00
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @return null
|
2010-03-10 15:03:40 +03:00
|
|
|
* @abstract
|
|
|
|
*/
|
2012-05-11 22:25:00 +04:00
|
|
|
function startHandler($xp, $elem, &$attribs)
|
2010-03-10 15:03:40 +03:00
|
|
|
{
|
2012-05-11 22:25:00 +04:00
|
|
|
return null;
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// {{{ endHandler()
|
|
|
|
|
|
|
|
/**
|
2012-05-11 22:25:00 +04:00
|
|
|
* abstract method signature for End Handler
|
|
|
|
*
|
|
|
|
* @param mixed $xp ??
|
|
|
|
* @param mixed $elem ??
|
2010-03-10 15:03:40 +03:00
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @return null
|
2010-03-10 15:03:40 +03:00
|
|
|
* @abstract
|
|
|
|
*/
|
|
|
|
function endHandler($xp, $elem)
|
|
|
|
{
|
2012-05-11 22:25:00 +04:00
|
|
|
return null;
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// }}}me
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* error class, replaces PEAR_Error
|
|
|
|
*
|
|
|
|
* An instance of this class will be returned
|
|
|
|
* if an error occurs inside XML_Parser.
|
|
|
|
*
|
|
|
|
* There are three advantages over using the standard PEAR_Error:
|
|
|
|
* - All messages will be prefixed
|
|
|
|
* - check for XML_Parser error, using is_a( $error, 'XML_Parser_Error' )
|
|
|
|
* - messages can be generated from the xml_parser resource
|
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @category XML
|
|
|
|
* @package XML_Parser
|
|
|
|
* @author Stig Bakken <ssb@fast.no>
|
|
|
|
* @author Tomas V.V.Cox <cox@idecnet.com>
|
|
|
|
* @author Stephan Schmidt <schst@php.net>
|
|
|
|
* @copyright 2002-2008 The PHP Group
|
|
|
|
* @license http://opensource.org/licenses/bsd-license New BSD License
|
|
|
|
* @version Release: @package_version@
|
|
|
|
* @link http://pear.php.net/package/XML_Parser
|
|
|
|
* @see PEAR_Error
|
2010-03-10 15:03:40 +03:00
|
|
|
*/
|
|
|
|
class XML_Parser_Error extends PEAR_Error
|
|
|
|
{
|
|
|
|
// {{{ properties
|
|
|
|
|
2012-05-11 22:25:00 +04:00
|
|
|
/**
|
2010-03-10 15:03:40 +03:00
|
|
|
* prefix for all messages
|
|
|
|
*
|
|
|
|
* @var string
|
2012-05-11 22:25:00 +04:00
|
|
|
*/
|
2010-03-10 15:03:40 +03:00
|
|
|
var $error_message_prefix = 'XML_Parser: ';
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// {{{ constructor()
|
2012-05-11 22:25:00 +04:00
|
|
|
/**
|
2010-03-10 15:03:40 +03:00
|
|
|
* construct a new error instance
|
|
|
|
*
|
|
|
|
* You may either pass a message or an xml_parser resource as first
|
|
|
|
* parameter. If a resource has been passed, the last error that
|
|
|
|
* happened will be retrieved and returned.
|
|
|
|
*
|
2012-05-11 22:25:00 +04:00
|
|
|
* @param string|resource $msgorparser message or parser resource
|
|
|
|
* @param integer $code error code
|
|
|
|
* @param integer $mode error handling
|
|
|
|
* @param integer $level error level
|
|
|
|
*
|
2010-03-10 15:03:40 +03:00
|
|
|
* @access public
|
2012-05-11 22:25:00 +04:00
|
|
|
* @todo PEAR CS - can't meet 85char line limit without arg refactoring
|
|
|
|
*/
|
2010-03-10 15:03:40 +03:00
|
|
|
function XML_Parser_Error($msgorparser = 'unknown error', $code = 0, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE)
|
|
|
|
{
|
|
|
|
if (is_resource($msgorparser)) {
|
2012-05-11 22:25:00 +04:00
|
|
|
$code = xml_get_error_code($msgorparser);
|
|
|
|
$msgorparser = sprintf('%s at XML input line %d:%d',
|
|
|
|
xml_error_string($code),
|
|
|
|
xml_get_current_line_number($msgorparser),
|
|
|
|
xml_get_current_column_number($msgorparser));
|
2010-03-10 15:03:40 +03:00
|
|
|
}
|
|
|
|
$this->PEAR_Error($msgorparser, $code, $mode, $level);
|
|
|
|
}
|
|
|
|
// }}}
|
|
|
|
}
|
2012-05-11 22:25:00 +04:00
|
|
|
?>
|