<?php
/*

$file = 'test.xml';
require_once('SofeeXmlParser.php');
$xml = new SofeeXmlParser();
$xml->parseFile($file);
$tree = $xml->getTree();
unset($xml);
print "<pre>";
print_r($tree);
print "</pre>";
*/
class xmltojson {

    public $parser;
    public $srcenc;
    public $dstenc;
    public $_struct = array();
    public function __construct($srcenc = null, $dstenc = null) {
	  $this->srcenc = $srcenc;
	  $this->dstenc = $dstenc;
	  $this->parser = null;
	  $this->_struct = array();
    }
    public function free() {
		  if (isset($this->parser) && is_resource($this->parser)) {
		      xml_parser_free($this->parser);
		      unset($this->parser);
		  }
    }

    /**
    * Parses the XML file
    *
    * @access  public
    * @param  string  [$file] the XML file name
    * @return  void
    * @since
    */
    public function parseFile($file) {
		  $data = file_get_contents($file);
		  $this->parseString($data);
    }
   public function parseString($data) {
	  if ($this->srcenc === null) {
	      $this->parser = @xml_parser_create();
	  } else {
	      $this->parser = @xml_parser_create($this->srcenc);
	  }

  if ($this->dstenc !== null) {
      @xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->dstenc);
  }
  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);    // lowercase tags
  xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1);  // skip empty tags
  if (!xml_parse_into_struct($this->parser, $data, $this->_struct)) {
      $this->free();
  }
  $this->_count = count($this->_struct);
  $this->free();
    }

    /**
    * return the data struction
    *
    * @access  public
    * @return  array
    */
     public function getTree() {
		  $i = 0;
		  $tree = array();
		  $tree = $this->addNode(
		      $tree,
		      $this->_struct[$i]['tag'],
		      (isset($this->_struct[$i]['value'])) ? $this->_struct[$i]['value'] : '',
		      (isset($this->_struct[$i]['attributes'])) ? $this->_struct[$i]['attributes'] : '',
		      $this->getChild($i)
		  );

		  unset($this->_struct);
		  return ($tree);
    }

    function getChild(&$i) {
  // contain node data
  $children = array();

  // loop
  while (++$i < $this->_count) {
      // node tag name
      $tagname = $this->_struct[$i]['tag'];
      $value = isset($this->_struct[$i]['value']) ? $this->_struct[$i]['value'] : '';
      $attributes = isset($this->_struct[$i]['attributes']) ? $this->_struct[$i]['attributes'] : '';

      switch ($this->_struct[$i]['type']) {
    case 'open':
        // node has more children
        $child = $this->getChild($i);
        // append the children data to the current node
        $children = $this->addNode($children, $tagname, $value, $attributes, $child);
        break;
    case 'complete':
        // at end of current branch
        $children = $this->addNode($children, $tagname, $value, $attributes);
        break;
    case 'cdata':
        // node has CDATA after one of it's children
        $children['value'] .= $value;
        break;
    case 'close':
        // end of node, return collected data
        return $children;
        break;
      }

  }
  //return $children;
    }

     public  function addNode($target, $key, $value = '', $attributes = '', $child = '') {
  if (!isset($target[$key]['value']) && !isset($target[$key][0])) {
      if ($child != '') {
    $target[$key] = $child;
      }
      if ($attributes != '') {
    foreach ($attributes as $k => $v) {
        $target[$key][$k] = $v;
    }
      }

      $target[$key]['value'] = $value;
  } else {
      if (!isset($target[$key][0])) {
    // is string or other
    $oldvalue = $target[$key];
    $target[$key] = array();
    $target[$key][0] = $oldvalue;
    $index = 1;
      } else {
    // is array
    $index = count($target[$key]);
      }

      if ($child != '') {
    $target[$key][$index] = $child;
      }

      if ($attributes != '') {
    foreach ($attributes as $k => $v) {
        $target[$key][$index][$k] = $v;
    }
      }
      $target[$key][$index]['value'] = $value;
  }
  return $target;
    }

}