Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Wed, Apr 30, 9:55 AM

in-portal

Index: branches/5.1.x/core/units/helpers/xml_helper.php
===================================================================
--- branches/5.1.x/core/units/helpers/xml_helper.php (revision 14000)
+++ branches/5.1.x/core/units/helpers/xml_helper.php (revision 14001)
@@ -1,395 +1,560 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kXMLHelper extends kHelper {
var $RootElement = null;
/**
* Enter description here...
*
* @var kXMLNode
*/
var $CurrentElement = null;
var $Mode;
+ var $XMLNodeClassName = 'kXMLNode';
+
+ function Init($prefix, $special, $event_params = null)
+ {
+ parent::Init($prefix, $special, $event_params);
+
+ if ( version_compare(PHP_VERSION, '5.0.0') === 1 ) {
+ $this->XMLNodeClassName = 'kXMLNode5';
+ k4_include_once( dirname(__FILE__) . DIRECTORY_SEPARATOR . 'xml_helper5.php' );
+ }
+ }
+
/**
* Parses XML data specified and returns root node
*
* @param string $xml
+ * @param int $mode
+ * @param bool $no_case_folding
* @return kXMLNode
*/
- function &Parse($xml = null, $mode = XML_NO_TEXT_NODES)
+ function &Parse($xml = null, $mode = null, $no_case_folding = false)
{
- $this->Mode = $mode;
+ $xml = trim($xml);
+ $this->Mode = !isset($mode) ? XML_NO_TEXT_NODES : $mode;
$this->Clear(); // in case if Parse method is called more then one time
$xml_parser = xml_parser_create();
+
+ if ($no_case_folding) {
+ xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0);
+ }
+
xml_set_element_handler( $xml_parser, Array(&$this, 'startElement'), Array(&$this, 'endElement') );
xml_set_character_data_handler( $xml_parser, Array(&$this, 'characterData') );
- if (!xml_parse($xml_parser, $xml, 1)) {
- $this->RootElement = new kXMLNode('ERROR', array('code'=>xml_get_error_code($xml_parser),'message'=>xml_error_string(xml_get_error_code($xml_parser))));
- trigger_error(sprintf('XML error: %s at line %d',
+
+ if ( !xml_parse($xml_parser, $xml, 1) ) {
+ $class_name = $this->XMLNodeClassName;
+ $byte = xml_get_current_byte_index($xml_parser);
+ $extract = '...' . mb_substr($xml, $byte-50, 50) . ' !!![' . mb_substr($xml, $byte, 1) . ']!!! '.mb_substr($xml, $byte+1, 50) . '...';
+
+ $message = sprintf(
+ 'XML error number %s: %s at line %d col %d, byte %d, extract: %s',
+ xml_get_error_code($xml_parser),
xml_error_string(xml_get_error_code($xml_parser)),
- xml_get_current_line_number($xml_parser)), E_USER_WARNING);
+ xml_get_current_line_number($xml_parser),
+ xml_get_current_column_number($xml_parser),
+ xml_get_current_byte_index($xml_parser),
+ $extract
+ );
+
+ $this->RootElement =& new $class_name(
+ 'ERROR',
+ array(
+ 'code' => xml_get_error_code($xml_parser),
+ 'message' => $message
+ )
+ );
+
+ trigger_error($message, E_USER_WARNING);
}
+
xml_parser_free($xml_parser);
$root_copy = $this->RootElement;
+ unset($this->RootElement);
+ unset($this->CurrentElement);
return $root_copy;
}
- function ConvertHTMLEntities($s){
+ function ConvertHTMLEntities($s)
+ {
//build first an assoc. array with the entities we want to match
$table1 = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES);
$patterns = array();
$replacements = array();
//now build another assoc. array with the entities we want to replace (numeric entities)
foreach ($table1 as $k=>$v){
$patterns[] = "/$v/";
// $c = htmlentities($k,ENT_QUOTES,"UTF-8");
$replacements[] = "&#".ord($k).";";
}
//now perform a replacement using preg_replace
//each matched value in array 1 will be replaced with the corresponding value in array 2
$s = preg_replace($patterns,$replacements,$s);
+
return $s;
}
function startElement(&$Parser, &$Elem, $Attrs)
{
$parent =& $this->CurrentElement; // 1. $parent is now reference to $this->CurrentElement
- $this->CurrentElement =& new kXMLNode($Elem, $Attrs); // 2. =& ensures, that new object won't be assigned to $parent as well (don't remove)
+ $class_name = $this->XMLNodeClassName;
+ $this->CurrentElement =& new $class_name($Elem, $Attrs); // 2. =& ensures, that new object won't be assigned to $parent as well (don't remove)
+
if (!isset($this->RootElement) || is_null($this->RootElement)) {
$this->RootElement =& $this->CurrentElement;
}
+
if (!is_null($parent)) {
$parent->AddChild($this->CurrentElement);
}
}
function characterData($Parser, $Line)
{
if ($this->Mode == XML_WITH_TEXT_NODES) {
- $text_node = new kXMLNode('_TEXT_');
+ $class_name = $this->XMLNodeClassName;
+ $text_node = new $class_name('_TEXT_');
$text_node->AppendData($Line);
$this->CurrentElement->AddChild( $text_node );
}
else {
$this->CurrentElement->AppendData($Line);
}
}
function endElement($Parser, $Elem)
{
if ($this->Mode == XML_WITH_TEXT_NODES) {
/*if (count($this->CurrentElement->Children) == 1 && $this->CurrentElement->firstChild->Name == '_TEXT_') {
$this->CurrentElement->Children = array();
}*/
}
+
if ($this->CurrentElement->Parent != null) {
$this->CurrentElement =& $this->CurrentElement->Parent;
}
}
function Clear()
{
unset($this->RootElement);
unset($this->CurrentElement);
}
+
+ function &CreateNode($name, $value=null, $attributes=array())
+ {
+ $class_name = $this->XMLNodeClassName;
+ $node = new $class_name($name, $attributes);
+ /* @var $node kXMLNode */
+
+ if ($value) {
+ $node->SetData($value);
+ }
+ return $node;
+ }
}
class kXMLNode {
+
/**
- * Name of this node
+ * Casefolded name of this node
*
* @var string
*/
var $Name = null;
/**
- * Attributes of this node
+ * Original name of this node
+ *
+ * @var string
+ */
+ var $OriginalName = null;
+
+ /**
+ * Casefolded attributes of this node
*
* @var Array
*/
var $Attributes = array();
/**
+ * Original attributes of this node
+ *
+ * @var Array
+ */
+ var $OriginalAttributes = array();
+
+ /**
* List of node childnodes
*
* @var Array
*/
var $Children = array();
/**
* Node content (usually text)
*
* @var string
*/
var $Data = null;
/**
- * First child of this node
+ * Reference to first child
*
* @var kXMLNode
*/
var $firstChild = null;
/**
* Last child of this node
*
* @var kXMLNode
*/
var $lastChild = null;
/**
* Parent node
*
* @var kXMLNode
*/
var $Parent = null;
/**
* Node position relative to other nodes of it's parent
*
* @var int
*/
var $Position = 0;
/**
* Node identifier
*
* @var int
*/
var $CRC = null;
function kXMLNode($name, $attrs = array())
{
$this->Name = strtoupper($name);
+ $this->OriginalName = $name;
+ $this->OriginalAttributes = $attrs;
+
foreach ($attrs as $attr => $value) {
- $this->Attributes[strtoupper($attr)] = $value;
+ $this->Attributes[ strtoupper($attr) ] = $value;
}
+
$this->CRC = crc32($this->Name.join(array_keys($this->Attributes)).join(array_values($this->Attributes)));
}
+ /**
+ * Returns attribute value, first checking it casesensitively, then caseinsensitively
+ * If attribute is not set returns default value (if passed), or false otherwise
+ *
+ * @param string $name
+ * @param mixed $default
+ * @return string
+ */
+ function GetAttribute($name, $default=false)
+ {
+ if (isset($this->OriginalAttributes[$name])) {
+ return $this->OriginalAttributes[$name];
+ }
+
+ return isset($this->Attributes[strtoupper($name)]) ? $this->Attributes[strtoupper($name)] : $default;
+ }
+
function SetParent(&$elem)
{
$this->Parent =& $elem;
}
/**
* Adds new child to current node
*
* @param kXMLNode $a_child
*/
function AddChild(&$a_child)
{
$node_count = count($this->Children);
$a_child->Position = $node_count;
if ($node_count == 0) {
$this->firstChild =& $a_child;
$this->lastChild =& $a_child;
}
else {
$this->lastChild =& $a_child;
}
$this->Children[] =& $a_child;
$a_child->SetParent($this);
}
/**
* Appends data to current node
*
* @param string $data
*/
function AppendData($data)
{
$this->Data .= $data;
}
/**
* Returns child node by given path
*
* @param string $path
* @return kXMLNode
*/
function &GetChild($path)
{
$entries = explode('/', strtoupper($path));
$cur = array_shift($entries);
if ($cur == $this->Name) $cur = array_shift($entries);
if (!$cur) return $this;
if (!isset($this->Children[$cur])) return false;
$left = implode('/', $entries);
if (!$left) return $this->Children[$cur];
return $this->Children[$cur]->GetChild($left);
}
+ function &GetFirstChild()
+ {
+ return $this->firstChild;
+ }
+
/**
* Returns node value by given path
*
* @param string $path
* @return string
*/
function GetChildValue($path)
{
$child =& $this->GetChild($path);
if ($child !== false) {
return $child->Data;
}
}
/**
* Returns child node by given position among it siblings
*
* @param int $position
* @return kXMLNode
*/
function &GetChildByPosition($position)
{
if ($position < count($this->Children) ) {
return $this->Children[$position];
}
else {
$false = false;
return $false;
}
}
/**
* Recursively searches for child with given name under current node
*
* @param string $name
* @return kXMLNode
*/
function &FindChild($name)
{
$name = strtoupper($name);
if ($this->Name == $name) return $this;
// if (isset($this->Children[$name])) return $this->Children[$name];
// $children = array_keys($this->Children);
foreach ($this->Children as $elem)
{
$child =& $elem->FindChild($name);
if ($child !== false)
{
return $child;
}
}
+ if (isset($child) && is_object($child)) {
+ $child->_destruct();
+ }
+ unset($child);
$false = false;
return $false;
}
/**
* Retruns value of given child or value of it's attribute
*
* @param string $name
* @param string $attr
* @return string
*/
function FindChildValue($name, $attr=null)
{
$child =& $this->FindChild($name);
+
if ($child !== false) {
if (isset($attr)) {
return $child->Attributes[strtoupper($attr)];
}
+
return $child->Data;
}
}
/**
* Returns next node to this, false in case of end list
*
* @return kXMLNode
*/
function &PrevSibling()
{
if (!is_null($this->Parent) && $this->Position > 0) {
$pos = $this->Position - 1;
do {
$ret =& $this->Parent->GetChildByPosition($pos--);
} while ($ret->Name == '_TEXT_' && $pos >= 0);
if ($ret->Name == '_TEXT_') $ret = false;
return $ret;
}
else {
$false = false;
return $false;
}
}
/**
* Returns next node to this, false in case of end list
*
* @return kXMLNode
*/
function &NextSibling()
{
if (!is_null($this->Parent)) {
$pos = $this->Position + 1;
do {
$ret =& $this->Parent->GetChildByPosition($pos++);
} while ($pos < count($this->Parent->Children) && ($ret->Name == '_TEXT_'));
if (is_object($ret) && ($ret->Name == '_TEXT_')) {
$ret = false;
}
return $ret;
}
else {
$false = false;
return $false;
}
}
/**
* Reconstructs XML of the node and subnodes
*
* $param bool $content_only
*/
function GetXML($content_only = false)
{
$xml = '';
+ $single = (!$this->Data && count($this->Children) == 0);
+
if (!$content_only) {
- $xml = '<'.$this->Name;
- if (count($this->Attributes)) {
+ $xml = '<'.$this->OriginalName;
+
+ if (count($this->OriginalAttributes)) {
$xml .= ' ';
$att_contents = array();
- foreach ($this->Attributes as $name => $value) {
- $att_contents[] = $name.'="'.$value.'"';
+ foreach ($this->OriginalAttributes as $name => $value) {
+ $att_contents[] = $name.'="'.htmlspecialchars($value).'"';
}
$xml .= implode(' ', $att_contents);
}
- $xml .= '>';
- }
- $xml .= $this->Data;
- foreach ($this->Children as $node) {
- /* @var $node kXMLNode */
- $xml .= $node->GetXML($node->Name == '_TEXT_' ? true : false);
+ $xml .= $single ? '/>' : '>';
}
- if (!$content_only) {
- $xml .= '</'.$this->Name.'>';
+ if (!$single) {
+ if ($content_only) {
+ $xml .= $this->Data;
+ }
+ else {
+ $xml .= preg_match('/&|</', $this->Data) ? '<![CDATA['.$this->Data.']]>' : $this->Data;
+ }
+
+ foreach ($this->Children as $node) {
+ /* @var $node kXMLNode */
+
+ $xml .= $node->GetXML($node->Name == '_TEXT_' ? true : false);
+ }
+
+ if (!$content_only) {
+ $xml .= '</'.$this->OriginalName.'>';
+ }
}
+
return $xml;
}
+
+ function RemoveChild($name)
+ {
+ $child =& $this->FindChild($name);
+ $parent =& $child->Parent;
+ $pos = $child->Position;
+ array_splice($parent->Children, $pos, 1);
+ for ($i=$pos; $i < count($parent->Children); $i++) {
+ $parent->Children[$i]->Position = $i;
+ }
+ $parent->firstChild =& $parent->Children[0];
+ $parent->lastChild =& $parent->Children[count($parent->Children)-1];
+ }
+
+ function ReplaceChild($name, &$replacement)
+ {
+ $child =& $this->FindChild($name);
+ $parent =& $child->Parent;
+ $pos = $child->Position;
+ array_splice($parent->Children, $pos, 1, array($replacement));
+ $replacement->Parent =& $parent;
+ $replacement->Position = $pos;
+ $parent->firstChild =& $parent->Children[0];
+ $parent->lastChild =& $parent->Children[count($parent->Children)-1];
+ }
+
+ function SetName($name)
+ {
+ $this->Name = strtoupper($name);
+ $this->OriginalName = $name;
+ }
+
+ function SetData($data)
+ {
+ $this->Data = $data;
+ }
+
+ function SetAttribute($name, $value)
+ {
+ $this->Attributes[strtoupper($name)] = $value;
+ $this->OriginalAttributes[$name] = $value;
+ }
}
\ No newline at end of file
Index: branches/5.1.x/core/units/helpers/xml_helper5.php
===================================================================
--- branches/5.1.x/core/units/helpers/xml_helper5.php (nonexistent)
+++ branches/5.1.x/core/units/helpers/xml_helper5.php (revision 14001)
@@ -0,0 +1,71 @@
+<?php
+
+class XMLIterator implements Iterator
+{
+ private $var = array();
+
+ public function __construct($array)
+ {
+ if (is_array($array)) {
+ $this->var = $array;
+ }
+ }
+
+ public function rewind() {
+ reset($this->var);
+ }
+
+ public function current() {
+ $var = current($this->var);
+ return $var;
+ }
+
+ public function key() {
+ $var = key($this->var);
+ return $var;
+ }
+
+ public function next() {
+ $var = next($this->var);
+ return $var;
+ }
+
+ public function valid() {
+ $var = $this->current() !== false;
+ return $var;
+ }
+
+}
+
+class kXMLNode5 extends kXMLNode implements IteratorAggregate {
+
+ public function getIterator() {
+ return new XMLIterator($this->Children);
+ }
+
+ public function __destruct()
+ {
+// echo number_format(memory_get_usage()). ' &lt;-- Entered destructor for '.$this->Name.'<br/>';
+ unset($this->Attributes);
+ if (is_array($this->Children)) {
+ foreach ($this->Children as $key => $child)
+ {
+ if ($this->Children[$key] instanceof kXMLNode5 ) {
+ $this->Children[$key]->__destruct();
+ }
+ unset($this->Children[$key]);
+ }
+ }
+ unset($this->Children);
+// echo number_format(memory_get_usage()). ' &lt;-- Destructed '.$this->Name.' Children <br/>';
+ unset($this->Name);
+ unset($this->Data);
+ unset($this->firstChild);
+ unset($this->lastChild);
+ unset($this->Parent);
+ unset($this->Position);
+ unset($this->CRC);
+ unset($this);
+ }
+}
+

Event Timeline