Файл: upload/include/library/phpfox/xml/parser.class.php
Строк: 197
<?php
/**
* [PHPFOX_HEADER]
*/
defined('PHPFOX') or exit('NO DICE!');
/**
* XML Parser
* Class is used to convert an XML STRING into a ARRAY.
*
* Sample XML code we are working with:
* <code>
* <foo var="value">
* <sample extra="info">
* This is some value.
* </sample>
* </foo>
* </code>
*
* PHP code to parse XML STRING:
* <code>
* $aXmlData = Phpfox::getLib('xml.parser')->parse($sXml);
* </code>
*
* The variable $aXmlData will output the following array:
* <code>
* $aXmlData = array(
* 'foo' => array(
* 'var' => 'value',
* 'sample' => array(
* 'extra' => 'info',
* 'value' => 'This is some value'
* )
* )
* );
* </code>
*
* @copyright [PHPFOX_COPYRIGHT]
* @author Raymond Benc
* @package Phpfox
* @version $Id: parser.class.php 2525 2011-04-13 18:03:20Z Raymond_Benc $
*/
class Phpfox_Xml_Parser
{
/**
* XML object.
*
* @see xml_parser_create()
* @var object
*/
private $_oXml = null;
/**
* XML string to parse.
*
* @var string
*/
private $_sXml;
/**
* ARRAY of data we picked up and parsed from the XML string.
*
* @var array
*/
private $_aData = array();
/**
* Error ID#.
*
* @var int
*/
private $_iError = 0;
/**
* Stack XML.
*
* @var array
*/
private $_aStack = array();
/**
* CDATA string.
*
* @var string
*/
private $_sCdata;
/**
* Check to include the first tag.
*
* @var bool
*/
private $_bIncludeFirstTag = false;
/**
* Total number of tags.
*
* @var int
*/
private $_iTagCnt = 0;
/**
* Error code.
*
* @var int
*/
private $_iErrorCode = 0;
/**
* Error line.
*
* @var int
*/
private $_iErrorLine = 0;
/**
* Class constructor.
*
*/
public function __construct()
{
}
/**
* Get the XML content.
*
* @param string $mFile XML data or XML file.
* @return string XML data.
*/
public function getXml($mFile)
{
if (!preg_match("/<(.*?)>/i", $mFile) && file_exists($mFile))
{
return file_get_contents($mFile);
}
return $mFile;
}
/**
* Parse XML code and convert into an ARRAY.
*
* @param string $mFile XML data or XML file name.
* @param string $sEncoding Encoding.
* @param bool $bEmptyData TRUE to empty XML data.
* @return mixed FALSE if errors were found, ARRAY if no errors and XML was converted into an ARRAY.
*/
public function parse($mFile, $sEncoding = 'ISO-8859-1', $bEmptyData = true)
{
$this->_sXml = $this->getXml($mFile);
if (empty($this->_sXml) || $this->_iError > 0)
{
return false;
}
if (!($this->_oXml = xml_parser_create($sEncoding)))
{
return false;
}
xml_parser_set_option($this->_oXml, XML_OPTION_SKIP_WHITE, 0);
xml_parser_set_option($this->_oXml, XML_OPTION_CASE_FOLDING, 0);
xml_set_character_data_handler($this->_oXml, array(&$this, '_handleCdata'));
xml_set_element_handler($this->_oXml, array(&$this, '_handleElementStart'), array(&$this, '_handleElementEnd'));
xml_parse($this->_oXml, $this->_sXml);
$bError = xml_get_error_code($this->_oXml);
if ($bEmptyData)
{
$this->_sXml = '';
$this->_aStack = array();
$this->_sCdata = '';
}
if ($bError)
{
$this->_iErrorCode = @xml_get_error_code($this->_oXml);
$this->_iErrorLine = @xml_get_current_line_number($this->_oXml);
xml_parser_free($this->_oXml);
return Phpfox_Error::trigger($this->errorString(), E_USER_ERROR);
}
xml_parser_free($this->_oXml);
return $this->_aData;
}
/**
* Error phrase.
*
* @return string
*/
public function errorString()
{
if ($sError = xml_error_string($this->_iErrorCode))
{
return $sError;
}
else
{
return 'unknown';
}
}
/**
* Error line.
*
* @return int
*/
public function errorLine()
{
if ($this->_iErrorLine)
{
return $this->_iErrorLine;
}
else
{
return 0;
}
}
/**
* Error code.
*
* @return int
*/
public function errorCode()
{
if ($this->_iErrorCode)
{
return $this->_iErrorCode;
}
else
{
return 0;
}
}
/**
* Handle CDATA by storing it in a variable.
*
* @param object $oParser Object parser.
* @param string $sData CDATA string we parsed.
*/
private function _handleCdata(&$oParser, $sData)
{
$this->_sCdata .= $sData;
}
/**
* Handle the start of an element.
*
* @param object $oParser Object parser.
* @param string $sName Name of the element.
* @param array $aAttributes List of attributes.
*/
private function _handleElementStart(&$oParser, $sName, $aAttributes)
{
$this->_sCdata = '';
foreach ($aAttributes AS $sKey => $sValue)
{
if (preg_match('#&[a-z]+;#i', $sValue))
{
$aAttributes[$sKey] = Phpfox::getLib('parse.format')->unhtmlspecialchars($sValue);
}
}
array_unshift($this->_aStack, array(
'name' => $sName,
'attributes' => $aAttributes,
'tag_count' => ++$this->_iTagCnt
));
}
/**
* Handle the end of an element.
*
* @param unknown_type $oParser Object parser.
* @param unknown_type $sName Name of the element.
*/
private function _handleElementEnd(&$oParser, $sName)
{
$aTag = array_shift($this->_aStack);
if ($aTag['name'] != $sName)
{
return;
}
$sOutput = $aTag['attributes'];
if (trim($this->_sCdata) !== '' || $aTag['tag_count'] == $this->_iTagCnt)
{
if (sizeof($sOutput) == 0)
{
$sOutput = $this->_unescapeCdata($this->_sCdata);
}
else
{
$this->_addNode($sOutput, 'value', $this->_unescapeCdata($this->_sCdata));
}
}
if (isset($this->_aStack[0]))
{
$this->_addNode($this->_aStack[0]['attributes'], $sName, $sOutput);
}
else
{
if ($this->_bIncludeFirstTag)
{
$this->_aData = array($sName => $sOutput);
}
else
{
$this->_aData = $sOutput;
}
}
$this->_sCdata = '';
}
/**
* Add children.
*
* @param array $aChildrens Child ARRAY.
* @param string $sName Name of the tag.
* @param string $sValue Value of the tag.
*/
private function _addNode(&$aChildrens, $sName, $sValue)
{
if (!is_array($aChildrens) || !in_array($sName, array_keys($aChildrens)))
{
$aChildrens[$sName] = $sValue;
}
elseif (is_array($aChildrens[$sName]) && isset($aChildrens[$sName][0]))
{
$aChildrens[$sName][] = $sValue;
}
else
{
$aChildrens[$sName] = array($aChildrens[$sName]);
$aChildrens[$sName][] = $sValue;
}
}
/**
* Unescape CDATA.
*
* @param string $sXml XML code to parse.
* @return string Converted XML unescaped CDATA.
*/
private function _unescapeCdata($sXml)
{
static $sFind, $sReplace;
if (!is_array($sFind))
{
$sFind = array('�![CDATA[', ']]�', "rn", "n");
$sReplace = array('<![CDATA[', ']]>', "n", "rn");
}
return str_replace($sFind, $sReplace, $sXml);
}
}
?>