361 Zeilen
Kein EOL
9,4 KiB
PHP
361 Zeilen
Kein EOL
9,4 KiB
PHP
<?php
|
||
/**
|
||
* Project:
|
||
* Contenido Content Management System
|
||
*
|
||
* Description:
|
||
* Class XML_doc
|
||
*
|
||
* Requirements:
|
||
* @con_php_req 5.0
|
||
*
|
||
*
|
||
* @package Contenido_XML
|
||
* @version 0.9.7
|
||
* @author Jan Lengowski
|
||
* @copyright four for business AG <www.4fb.de>
|
||
* @license http://www.contenido.org/license/LIZENZ.txt
|
||
* @link http://www.4fb.de
|
||
* @link http://www.contenido.org
|
||
* @since file available since contenido release <= 4.6
|
||
*
|
||
* {@internal
|
||
* created unknown
|
||
* modified unknown, Martin Horwath <horwath@dayside.net>
|
||
* modified 2008-06-30, Dominik Ziegler, add security fix
|
||
*
|
||
* $Id: class.xml.php 374 2015-11-09 15:59:28Z oldperl $:
|
||
* }}
|
||
*
|
||
*/
|
||
|
||
if(!defined('CON_FRAMEWORK')) {
|
||
die('Illegal call');
|
||
}
|
||
|
||
/**
|
||
* Class XML_doc
|
||
*
|
||
* Simple class for extracting values
|
||
* from a XML document. Uses a simplified
|
||
* XPath syntax to access the elements.
|
||
* For example: 'root/person/name' would
|
||
* return the value of the 'name' node in
|
||
* 'root/person' node. You have to specify
|
||
* the root node name. Can't access node
|
||
* attributes yet.
|
||
*
|
||
*/
|
||
class XML_doc {
|
||
|
||
/**
|
||
* @var array $errors
|
||
*/
|
||
var $errors = array();
|
||
|
||
/**
|
||
* @var string xml
|
||
*/
|
||
var $xml;
|
||
|
||
/**
|
||
* @var parsed array
|
||
*/
|
||
var $parsearray;
|
||
|
||
/**
|
||
* @var help array
|
||
*/
|
||
var $itemname;
|
||
|
||
/**
|
||
* XML Parser Object
|
||
*/
|
||
var $parser;
|
||
|
||
/**
|
||
* XML encoding
|
||
*/
|
||
var $encoding;
|
||
|
||
var $sys_encoding;
|
||
|
||
/**
|
||
* Class Construcor
|
||
*/
|
||
function XML_doc() {
|
||
global $encoding, $lang;
|
||
|
||
$this->sys_encoding = $encoding[$lang];
|
||
} // end function
|
||
|
||
|
||
/**
|
||
* load()
|
||
*
|
||
* Load the XML file
|
||
*
|
||
* @param string XML document filename
|
||
* @return boolean true if the load was successful
|
||
*/
|
||
function load($filename) {
|
||
|
||
if (file_exists($filename) && !is_dir($filename)) {
|
||
$fp = fopen ($filename, "rb");
|
||
|
||
if ($fp === false)
|
||
{
|
||
return (false);
|
||
}
|
||
|
||
unset($this->xml);
|
||
$iFilesize = filesize ($filename);
|
||
// check for 0 filesize
|
||
if($iFilesize > 0) {
|
||
$this->xml = fread ($fp, $iFilesize);
|
||
fclose ($fp);
|
||
} else {
|
||
fclose ($fp);
|
||
return (false);
|
||
}
|
||
|
||
|
||
// useful if entities are found in xml file
|
||
$this->xml = $this->_translateLiteral2NumericEntities($this->xml);
|
||
|
||
// get source encoding from file
|
||
if (preg_match('/<\?xml.*encoding=[\'"](.*?)[\'"].*\?>/m', $this->xml, $m)) {
|
||
$this->encoding = strtoupper($m[1]);
|
||
} else {
|
||
$this->encoding = "UTF-8";
|
||
}
|
||
|
||
//print_r($this->xml);
|
||
unset($this->parsearray);
|
||
return (true);
|
||
|
||
} else {
|
||
//die('no XML file ('.$filename.')');
|
||
return (false);
|
||
|
||
}
|
||
|
||
} // end function
|
||
|
||
|
||
/**
|
||
* valueOf()
|
||
*
|
||
* Extract one node value from the XML document.
|
||
* Use simplified XPath syntax to specify the node.
|
||
* F.e. 'root/test/firstnode'
|
||
*
|
||
* @return String Value of XML node
|
||
*/
|
||
function valueOf($xpath) {
|
||
|
||
if(!isset($this->parsearray) || !is_array($this->parsearray)) { // build tree once
|
||
$this->parse(false);
|
||
}
|
||
|
||
$aCombination = explode("/", $xpath);
|
||
|
||
$keynode = "['language']";
|
||
|
||
foreach ($aCombination as $key => $value) {
|
||
$keynode .= "['".$value."']";
|
||
}
|
||
//echo '<pre>';
|
||
//print_r($this->parsearray);
|
||
eval('if(isset($this->parsearray'.$keynode.')) $value = $this->parsearray'.$keynode.';');
|
||
|
||
|
||
if ($value == NULL)
|
||
{
|
||
$aLoosePath = $this->findLoosePath($aCombination);
|
||
|
||
if (is_array($aLoosePath))
|
||
{
|
||
$keynode = "";
|
||
foreach ($aLoosePath as $key => $value) {
|
||
$keynode .= "['".$value."']";
|
||
}
|
||
|
||
eval('if(isset($this->parsearray'.$keynode.')) $value = $this->parsearray'.$keynode.';');
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if ($value == NULL) { return "Not found: $xpath"; }
|
||
|
||
if (is_array($value)) { return "Has children"; }
|
||
|
||
if($this->sys_encoding == "utf-8") {return utf8_encode($value);}
|
||
return $value;
|
||
} // end function
|
||
|
||
/**
|
||
* findLoosePath: Finds a path in the XML array which
|
||
* ends with the given keys
|
||
*
|
||
* @param aCombination array of keys to test for
|
||
* @return false if nothing was found, or the array with the found keys
|
||
*/
|
||
function findLoosePath ($aCombination, $aScope = true)
|
||
{
|
||
if (count($aCombination) == 0)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
$keynode = "";
|
||
foreach ($aCombination as $key => $value) {
|
||
$keynode .= "['".$value."']";
|
||
}
|
||
|
||
if ($aScope===true) {
|
||
$aScope = $this->parsearray;
|
||
}
|
||
|
||
if (!is_array ($aScope)) {
|
||
return false;
|
||
}
|
||
|
||
$found = false;
|
||
foreach($aScope as $aScopeKey => $aScopeValue) {
|
||
if (!is_array ($aScope[$aScopeKey])) {
|
||
return false;
|
||
}
|
||
|
||
eval('if (isset ($aScope[\''.$aScopeKey.'\']'.$keynode.') ) { $found = true; }');
|
||
if ($found) {
|
||
$rCombination = array_merge(Array($aScopeKey), $aCombination);
|
||
break;
|
||
}
|
||
|
||
$rCombination = $this->findLoosePath($aCombination, $aScopeValue);
|
||
if (is_array($rCombination)) {
|
||
$rCombination = array_merge(Array($aScopeKey), $rCombination);
|
||
break;
|
||
}
|
||
}
|
||
|
||
return $rCombination;
|
||
}
|
||
|
||
|
||
/**
|
||
* parse()
|
||
*
|
||
* Parse the xml file in an array
|
||
*
|
||
*
|
||
*
|
||
* @return array parsearray
|
||
*/
|
||
|
||
function parse($send=true) {
|
||
global $lang, $aLanguageEncodings;
|
||
// set up a new XML parser to do all the work for us
|
||
$this->parser = xml_parser_create($this->encoding);
|
||
|
||
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
|
||
xml_set_object($this->parser, $this);
|
||
xml_set_element_handler($this->parser, "startElement", "endElement");
|
||
xml_set_character_data_handler($this->parser, "characterData");
|
||
|
||
// parse the data and free the parser...
|
||
xml_parse($this->parser, $this->xml);
|
||
xml_parser_free($this->parser);
|
||
if ($send) return $this->parsearray;
|
||
} // end function
|
||
|
||
/**
|
||
*
|
||
*
|
||
*
|
||
*/
|
||
function startElement($parser, $name, $attrs) {
|
||
// Start a new Element. This means we push the new element onto
|
||
// store the name of this element
|
||
$this->itemname[]="$name";
|
||
} // end function
|
||
|
||
/**
|
||
*
|
||
*
|
||
*
|
||
*/
|
||
function endElement($parser, $name) {
|
||
// End an element. This is done by popping the last element from
|
||
// the stack and adding it to the previous element on the stack.
|
||
// delete the old element from itemname
|
||
array_pop($this->itemname);
|
||
} // end function
|
||
|
||
/**
|
||
*
|
||
*
|
||
*
|
||
*/
|
||
function characterData($parser, $data) {
|
||
// Collect the data onto the end of the current chars it dont collect whitespaces.
|
||
|
||
$data = preg_replace ( "/[[:space:]]+/i", " ", $data );
|
||
|
||
if(trim($data)){
|
||
$pos = "";
|
||
//search for the element path
|
||
foreach($this->itemname as $value){
|
||
$value = str_replace("'", "\'", $value);
|
||
$pos.="['$value']";
|
||
}
|
||
|
||
// looks stupid but is useful to take care of entities, this corrects the line break issue
|
||
eval("if (isset(\$this->parsearray$pos)) { \$data = \$this->parsearray$pos.trim(\$data); }");
|
||
|
||
//set the new data in the parsearray
|
||
eval("\$this->parsearray$pos=trim(\$data);");
|
||
|
||
}
|
||
|
||
} // end function
|
||
|
||
/**
|
||
* Translate literal entities to their numeric equivalents and vice versa.
|
||
*
|
||
* PHP's XML parser (in V 4.1.0) has problems with entities! The only one's that are recognized
|
||
* are &, < > and ". *ALL* others (like © a.s.o.) cause an
|
||
* XML_ERROR_UNDEFINED_ENTITY error. I reported this as bug at http://bugs.php.net/bug.php?id=15092
|
||
* The work around is to translate the entities found in the XML source to their numeric equivalent
|
||
* E.g. to / © to <20> a.s.o.
|
||
*
|
||
* NOTE: Entities &, < > and " are left 'as is'
|
||
*
|
||
* @author Sam Blum bs_php@users.sourceforge.net
|
||
* @param string $xmlSource The XML string
|
||
* @param bool $reverse (default=FALSE) Translate numeric entities to literal entities.
|
||
* @return The XML string with translated entities.
|
||
*/
|
||
function _translateLiteral2NumericEntities($xmlSource, $reverse = FALSE) {
|
||
static $literal2NumericEntity;
|
||
|
||
if (empty($literal2NumericEntity)) {
|
||
$transTbl = clGetHtmlTranslationTable(HTML_ENTITIES);
|
||
foreach ($transTbl as $char => $entity) {
|
||
if (strpos('&"<>', $char) !== FALSE) continue;
|
||
$literal2NumericEntity[$entity] = '&#'.ord($char).';';
|
||
}
|
||
}
|
||
|
||
if ($reverse) {
|
||
return strtr($xmlSource, array_flip($literal2NumericEntity));
|
||
} else {
|
||
return strtr($xmlSource, $literal2NumericEntity);
|
||
}
|
||
}
|
||
|
||
|
||
} // end class XML_doc
|
||
?>
|