<?php
/*
* CXml2Array.php
* $Header: d:\cvs/classistd/sptpl/CXml2Array.php,v 2.9 2005/03/17 12:47:01 Darvin Exp $
*
* Class to convert an XML file into array
*
* Copyright (C) 2003-2005 Andrioli Darvin <darvin at andrioli.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
class CXml2Array
{
/**
* Array containg the file XML
* structure:
* ['text'] -> text inside the tag
* ['attrib'][attribname] -> tag's attribute
* ['child'][] -> child tag information. It holds many child with the
* same name
*
* @var array
*/
var $TheArray;
/**
* Temporary arrays
*/
var $tmpAttrib;
var $tmpTag;
var $AttribFirstTime;
var $TagFirstTime;
var $IntTmpTag;
/**
* Which PHP extension the module uses to parse the XML data
* @var string
* @see _WhichExtension()
*/
var $Extension;
/**
* Class initializer
* @param mixed object DOM XML or array returned by GetTag
* @access public
* @see GetTag()
*/
function CXml2Array($node='')
{
$this->Extension=$this->_WhichExtension();
if(!is_string($node))
{
//
if(is_array($node))
$this->LoadFromArray($node);
else
{
if(is_object($node))
$this->TheArray=$this->Parse($node);
else
trigger_error('Invalid parameter',E_USER_ERROR);
}
$this->tmpAttrib=$this->TheArray['attrib'];
$this->tmpTag=$this->TheArray['child'];
$this->AttribFirstTime=true;
$this->TagFirstTime=true;
}
}
/**
* Load data from filename
* @param string filename
* @return bool true if the file is successfully parsed
* @access public
*/
function LoadFromFile($FileName)
{
if($this->Extension=='DOM')
{
$doc = new DOMDocument; // require zend.ze1_compatibility_mode = off
if(!$doc->load(realpath($FileName)))
trigger_error('Error parsing the file '.$FileName,E_USER_ERROR);
$root=$doc->documentElement;
}
else
{
if(!$this->TplDom = domxml_open_file(realpath($FileName)))
trigger_error('Error parsing the file '.$FileName,E_USER_ERROR);
$root = $this->TplDom->document_element();
}
$this->TheArray=$this->Parse($root);
$this->tmpAttrib=$this->TheArray['attrib'];
$this->tmpTag=$this->TheArray['child'];
$this->AttribFirstTime=true;
$this->TagFirstTime=true;
}
/**
* Load data from xml string
* @param string XML text
* @return bool true if the file is successfully parsed
* @access public
*/
function LoadFromString($XmlStr)
{
if($this->Extension=='DOM')
{
$dom = new DOMDocument();
$dom->loadXML($XmlStr);
$root = $dom->documentElement;
}
else
{
if(!$dom = domxml_open_mem($XmlStr))
trigger_error("Internal Error while creating standard font",E_USER_ERROR);
$root = $dom->document_element();
}
$this->TheArray=$this->Parse($root);
$this->tmpAttrib=$this->TheArray['attrib'];
$this->tmpTag=$this->TheArray['child'];
$this->AttribFirstTime=true;
$this->TagFirstTime=true;
}
/**
* Evaluate which PHP extension the module should use to parse the XML data
* PHP4 -> DOMXML
* PHP5 -> DOM
* @access private
* @return string The extension name
*/
function _WhichExtension()
{
return(($this->__php5())?'DOM':'DOMXML');
}
/**
* Return True if the current PHP version is 5
* False if is PHP4
* @return boolean
* @access public
*/
function __php5()
{
return((version_compare(phpversion(), "5.0.0", "<")==-1)?false:true);
}
/**
* Parse one XML node. With PHP4 it uses DOMXML extension, with PHP it
* uses DOM extension.
* @param object DOMXML/DOM
* @param integer Nesting level
* @access private
*/
function Parse($Node,$level=0,$NodeName='')
{
if($this->Extension=='DOM')
$ret=$this->ParseDOM($Node,$level,$NodeName);
else
$ret=$this->ParseDOMXML($Node,$level,$NodeName);
return($ret);
}
/**
* Parse one XML node.
* @param object DOMXML
* @param integer Nesting level
* @access private
*/
function ParseDOMXML($Node,$level=0,$NodeName='')
{
$type=array( 1 =>'XML_ELEMENT_NODE',
2 =>'XML_ATTRIBUTE_NODE',
3 =>'XML_TEXT_NODE',
4 =>'XML_CDATA_SECTION_NODE',
5 =>'XML_ENTITY_REF_NODE',
6 =>'XML_ENTITY_NODE',
17 =>'XML_ENTITY_DECL_NODE'
);
// print_r($Node);
$Text='';
//$NodeName='';
$Contents=array();
$Attrib=array();
// load the attribs
$AttrTbl=$Node->attributes();
if($AttrTbl) {
// First I'm looking for the attrib Id
foreach($AttrTbl as $Att)
{
$AttribName=strtolower($Att->name());
$Attrib[$AttribName]=$Att->value();
}
}
// childs parse
$child = $Node->first_child();
while($child) {
//echo '<br>child:';
// echo '<br>['.$level.']'.$type[$child->node_type()];
switch($child->node_type())
{
case XML_ENTITY_REF_NODE :
$ret=$this->Parse($child,$level+1);
// var_dump($ret);
foreach($ret['child'] as $key => $value)
{
$Contents[]=$value;
}
//return($ret);
break;
case XML_ENTITY_DECL_NODE :
$ret=$this->Parse($child,$level+1);
return($ret);
break;
case XML_TEXT_NODE:
$Text.=rtrim($child->node_value());
break;
case XML_CDATA_SECTION_NODE:
$Text.=rtrim($child->node_value());
break;
case XML_ELEMENT_NODE:
$NName=strtolower($child->node_name());
$Contents[]=$this->Parse($child,$level+1,$NName);
break;
} // switch node type
$child = $child->next_sibling();
}
return(array('child' => $Contents,
'text' => $Text,
'attrib' => $Attrib,
'nodename' => $NodeName)
);
}
/**
* Parse one XML node.DOM version (PHP5)
* @param object DOM
* @param integer Nesting level
* @access private
*/
function ParseDOM($Node,$level=0,$NodeName='')
{
$type=array( 1 =>'XML_ELEMENT_NODE',
2 =>'XML_ATTRIBUTE_NODE',
3 =>'XML_TEXT_NODE',
4 =>'XML_CDATA_SECTION_NODE',
5 =>'XML_ENTITY_REF_NODE',
6 =>'XML_ENTITY_NODE',
17 =>'XML_ENTITY_DECL_NODE'
);
// print_r($Node);
$Text='';
//$NodeName='';
$Contents=array();
$Attrib=array();
// load the attribs
$AttrTbl=$Node->attributes;
if($AttrTbl) {
// First I'm looking for the attrib Id
foreach($AttrTbl as $Att)
{
$AttribName=strtolower($Att->name);
$Attrib[$AttribName]=$Att->value;
}
}
// childs parse
$child = $Node->firstChild;
while($child) {
//echo '<br>child:';
// echo '<br>['.$level.']'.$type[$child->node_type()];
switch($child->nodeType)
{
case XML_ENTITY_REF_NODE :
$ret=$this->Parse($child,$level+1);
// var_dump($ret);
foreach($ret['child'] as $key => $value)
{
//if(array_key_exists($key,$Contents))
// {
// $t=array_merge($Contents[$key],$value);
// $Contents[$key]=$t;
// }
// else
// {
$Contents[]=$value;
// }
}
//return($ret);
break;
case XML_ENTITY_DECL_NODE :
$ret=$this->Parse($child,$level+1);
return($ret);
break;
case XML_TEXT_NODE:
$Text.=rtrim($child->nodeValue);
break;
case XML_CDATA_SECTION_NODE:
$Text.=rtrim($child->nodeValue);
//$Text.=ereg_replace(' ',' ',$passo1);
//$Text.=htmlentities(trim($child->node_value()));
break;
case XML_ELEMENT_NODE:
$NName=strtolower($child->nodeName);
$Contents[]=$this->Parse($child,$level+1,$NName);
break;
} // switch node type
$child = $child->nextSibling;
}
return(array('child' => $Contents,
'text' => $Text,
'attrib' => $Attrib,
'nodename' => $NodeName)
);
}
/**
* Load the array from another array retrieved from this class.
* It is usefull to apply the module's function to the deepest part of the
* original array
* @param array
*/
function LoadFromArray($data)
{
$this->TheArray=$data;
// if(!array_key_exists('attrib',$this->TheArray))
// $this->TheArray['attrib']=array();
if(!array_key_exists('text',$this->TheArray))
$this->TheArray['text']='';
}
/**
* Dump the array contents in human format.
* Usefull for debug purpose
* @access public
*/
function ArrayDump()
{
// var_dump($this->TheArray);
//echo '<hr>';
$this->_dump($this->TheArray);
}
/**
* Internal function used to dump the array
* @param array data to dump
* @param integer
* @access private
*/
function _dump($data,$level=0)
{
$ta=20;
$c='.';
echo str_repeat($c,$level*$ta).'[text]:'.$data['text'].'<br>';
echo str_repeat($c,$level*$ta).'[nodename]:'.$data['nodename'].'<br>';
echo str_repeat($c,$level*$ta).'[attrib]:'.'<br>';
foreach($data['attrib'] as $key => $value)
{
echo str_repeat($c,$level*$ta).'.........['.$key.']:'.$value.'<br>';
}
echo str_repeat($c,$level*$ta).'[child]:'.'<br>';
foreach($data['child'] as $key => $value)
{
//var_dump($data['tag']);
echo str_repeat($c,$level*$ta).'.........['.$key.']:'.'<br>';
// foreach($data['child'][$key] as $key1 => $value1)
// {
//var_dump($value1);
// echo str_repeat($c,($level+1)*$ta-4).'['.$key1.']';
$this->_dump($value,$level+1);
// }
}
}
/************************************
* Retrieve functions
************************************/
/**
* Does exist the request tag? The function looks only if the tag exists
* as child of the root element.
* @param string
* @return bool
* @access public
*/
function ExistTag($TagName)
{
$noItem=count($this->TheArray['child']);
$Found=FALSE;
for($i=0;$i<$noItem&&!$Found;$i++)
{
if($this->TheArray['child'][$i]['nodename']==$TagName)
$Found=TRUE;
}
return($Found);
}
/**
* Does exist the request attribute? The function looks only if the attribute exists
* as child of the root element.
* @param string
* @return bool
* @access public
*/
function ExistAttribute($AttribName)
{
return(array_key_exists($AttribName,$this->TheArray['attrib']));
}
/**
* Return the XML as array
* @access public
*/
function GetArray()
{
return($this->TheArray);
}
/**
* The function return all childs of the root element named $TagName
* @param string
* @return array
* @access public
*/
function GetTag($TagName)
{
$noItem=count($this->TheArray['child']);
$ret=array();
$Found=FALSE;
for($i=0;$i<$noItem;$i++)
{
if($this->TheArray['child'][$i]['nodename']==$TagName)
{
$ret[]=$this->TheArray['child'][$i];
$Found=TRUE;
}
}
if($Found)
return($ret);
else
return(FALSE);
}
/**
* The function return all childs of the root element named $TagName
* @param string
* @return array
* @access public
*/
function GetTagPos($TagName,$Position=0)
{
$count=0;
$noItem=count($this->TheArray['child']);
for($i=0;$i<$noItem;$i++)
{
if($this->TheArray['child'][$i]['nodename']==$TagName)
{
if($count==$Position)
return($this->TheArray['child'][$i]);
$count++;
}
}
return(FALSE);
}
/**
* The function return all childs of $TagName. Note $TagName should be a child of the
* root element
* @param string
* @param integer Select from which child retrieve the information, if more child of
* root element have the same name
* @return array
* @access public
*/
function GetTagChilds($TagName,$Position=0)
{
$noItem=count($this->TheArray['child']);
$count=0;
for($i=0;$i<$noItem;$i++)
{
if($this->TheArray['child'][$i]['nodename']==$TagName)
{
if($count==$Position)
return($this->TheArray['child'][$i]['child']);
$count++;
}
}
return(FALSE);
}
/**
* The function return all attributes of $TagName. Note $TagName should be a child of the
* root element
* @param string
* @param integer Select from which child retrieve the information, if more child of
* root element have the same name
* @return array
* @access public
*/
function GetTagAttributes($TagName,$Position=0)
{
$noItem=count($this->TheArray['child']);
$count=0;
for($i=0;$i<$noItem;$i++)
{
if($this->TheArray['child'][$i]['nodename']==$TagName)
{
if($count==$Position)
return($this->TheArray['child'][$i]['attrib']);
$count++;
}
}
return(FALSE);
}
/**
* Return value of the named attribute
* @param string
* @return string
* @access public
*/
function GetAttribute($AttribName)
{
if($this->ExistAttribute($AttribName))
return($this->TheArray['attrib'][$AttribName]);
else
return(FALSE);
}
/**
* Return value of the root tag
* @return string
* @access public
*/
function GetText()
{
return($this->TheArray['text']);
}
/**
* Return the name of the root tag
* @return string
* @access public
*/
function GetNodeName()
{
return($this->TheArray['nodename']);
}
/**
* The function iterate over attribute's array of the root element
* @param bool Set to TRUE to reset the internal pointer
* @return array
* @access public
*/
function EachAttribute($reset=FALSE)
{
// var_dump($this->TheArray);
// var_dump($this->tmpAttrib);
if(!is_array($this->tmpAttrib))
return(FALSE);
if($reset)
{
$this->AttribFirstTime=TRUE;
return(TRUE);
}
if($this->AttribFirstTime)
{
reset($this->tmpAttrib);
$this->AttribFirstTime=false;
}
else
if(!next($this->tmpAttrib))
return(FALSE);
$value=current($this->tmpAttrib);
$key=key($this->tmpAttrib);
return(array($key,$value));
}
/**
* The function iterate over tag's array of the root element
* Public method
* @param bool Set to TRUE to reset the internal pointer
* @return object CXml2Array
* @access public
* @see _ChildLoop()
*/
function EachChild($reset=FALSE)
{
return($this->_ChildLoop($reset,TRUE));
}
/**
* The function iterate over tag's array of the root element
* Public method
* @param bool Set to TRUE to reset the internal pointer
* @return array
* @access public
* @see _ChildLoop()
*/
function EachChildArray($reset=FALSE)
{
return($this->_ChildLoop($reset,FALSE));
}
/**
* The function iterate over tag's array of the root element
* @param bool Set to TRUE to reset the internal pointer (return TRUE)
* @param bool Set to TRUE to return an object CXml2Array, o FALSE to return tha
* child's value as array
* @return object CXml2Array
* @access public
* @see _EachChild()
* @see _EachChildArray()
*/
function _ChildLoop($reset,$ReturnObj)
{
if(!is_array($this->tmpTag))
return(FALSE);
if(count($this->tmpTag)==0)
return(FALSE);
if($reset)
{
$this->TagFirstTime=TRUE;
return(TRUE);
}
if($this->TagFirstTime)
{
reset($this->tmpTag);
// $this->IntTmpTag=current($this->tmpTag);
if(!is_array($this->tmpTag))
return(FALSE);
// reset($this->IntTmpTag);
$this->TagFirstTime=false;
}
else
// if(!next($this->IntTmpTag))
// {
if(!next($this->tmpTag))
return(FALSE);
// else
// {
// $this->IntTmpTag=current($this->tmpTag);
// reset($this->IntTmpTag);
// }
// }
$value=current($this->tmpTag);
$key=$value['nodename'];
if($ReturnObj)
{
if(!is_array($value))
{
print_r($this->tmpTag);
die();
}
$tmpObj=new CXml2Array($value);
return(array($key,$tmpObj));
}
else
return(array($key,$value));
}
}
?>
|