Location: PHPKode > projects > Webgenerator-X content management system > wgx_rc1.5/WG-X/class.TiAX.php
<?
/*
* This file is part of Webgenerator-X,
* an object oriented website management engine working an top of
* Apache/PHP4/MySQL.
* http://www.webgenerator-x.com
* @2001 REGNI Giorgio
* hide@address.com
*
* Webgenerator-X is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Webgenerator-X 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*************************************************************************/
/* Today is December 12 2001
** Php Xpath is not reliable and too heavy
** so i am coding my own xml access functions
** for Webgenerator-X admin interface.
** The class is This is Approximative XPath
** TiAX
** The pupose is a fast class to parse XML code roughly using the XPath
** language.
** Warning: the xml tags must only contain those caracters:
** a-zA-Z0-9_:
** all tags are transformed to lower case
** REGNI Giorgio
*/

class TiAX
{
  var $xml_data;

  /**
   * Initialise the xml, parse $code if not null 
   */
  function TiAX($code="")
    {
      if ($code!="")
	$this->load_string($code);
    }

  /**
   * Parse a given xml code.
   * Must be called before any other function
   */
  function load_string($code)
    {
      global $my_xml_data;
      my_parse_xml($code);
      $this->xml_data = $my_xml_data;
      unset ($my_xml_data);            //free memory
    }

  /**
   * Return the data of a given node
   */
  function get_content($pointer)
    {
      return $this->xml_data[$pointer][data];
    }

  /**
   * Return the attributes of a given node
   */
  function get_attributes($pointer)
    {
      return $this->xml_data[$pointer][attributes];
    }

  /**
   * A false XPath interpreter
   * Run fast and provide this operations:
   * $expr=:
   *  - "/*" give all direct childs to the node
   *  - "//$tag" get all childs with tag name $tag 
   */
  function evaluate($expr,$node="")
    {
      if ($expr=='/*')
	{
	  if ($node=="")
	    $res = array($this->get_root_node());
	  else
	    $res = $this->get_child_nodes($node);
	}
      else if(ereg( "^//([a-zA-Z0-9:_]*)",$expr,$reg))
	{
	  $res = $this->get_child_nodes_where_tag_is($node,$reg[1]);
	}
      else 
	$res=array();

      return $res;
    }


  /**
   * Return the node of the root tag
   */
  function get_root_node()
    {
    // get to the end of the array
      reset($this->xml_data);

  
      return key($this->xml_data);
    }

  /**
   * Return the tag name of a node
   */
  function get_name($node)
    {
      $arry = explode("/",$node);
      end($arry);
      ereg( "([a-zA-Z0-9:_]*)\[[0-9]+\]$",current($arry),$reg);
      return $reg[1];
    }

  /**
   * Return an array of all direct child nodes to a given node
   * If their are childs with the same name, 
   * they are numbered from [0] to [n-1]
   */
  function get_child_nodes($pointer)
    {
      $childs = array();
      $keys = array_keys ($this->xml_data);
      $trans = array( '['=>"\[",']'=>"\]");
      $pointer = strtr($pointer,$trans);
      $regexp = $pointer.'/[^/]+$';
      foreach ($keys as $node)
	{
	  if (ereg($regexp,$node))
	    $childs[]=$node;
	}
      
      return $childs;
    }
  /**
   * Return an array of all direct child nodes whith xml tag=$tag
   * relative to a given node
   * If their are childs with the same name, 
   * they are numbered from [0] to [n-1]
   */
  function get_child_nodes_where_tag_is($pointer,$tag)
    {
      $childs = array();
      $keys = array_keys ($this->xml_data);
      $trans = array( '['=>"\[",']'=>"\]");
      $pointer = strtr($pointer,$trans);
      $regexp = $pointer."/$tag\[[0-9]+\]\$";
      foreach ($keys as $node)
	{
	  if (ereg($regexp,$node))
	    $childs[]=$node;
	}
      
      return $childs;
    }

}

/* The xml object is stored globaly to avoid bugs when using the sax
* xml parser from inside a class
$my_xml_data = array();
it's an array of nodes=>data
*/

$xml_debug_mode = 0;

/* global vars used by the script to control it
$xml_debug_mode isset => debug mode on, print the received code during parsing
*/

/* Global vars used during the parsing
$my_tag_stack = array();
$my_current_node ="";
$my_current_data=""
*/

/* Local functions outside the class because xml functions are unsafe to call
* within an object. 
*/

/**
* Parse the given xml code
* return boolean
* update the global var $my_xml_data
*/
function my_parse_xml( $code)
{
  global $my_xml_data,$my_tag_stack,$xml_debug_mode,$my_current_node;
  
  $my_xml_data = array();
  $my_tag_stack = array();
  $my_current_node ="";

  if ($xml_debug_mode)
    echo nl2br(htmlentities( $code));

  // create our parser
  $xml_parser = xml_parser_create();
	
  // set some parser options
  xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 1);
  xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false);
  xml_parser_set_option($xml_parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
	
  // this tells PHP what functions to call when it finds an element
  // these functions also handle the element's attributes
  xml_set_element_handler($xml_parser, 'my_startElement','my_endElement');
  
  // this tells PHP what function to use on the character data
  xml_set_character_data_handler($xml_parser, 'my_characterData');

  $res = xml_parse($xml_parser, $code, true) ;

  return $res;
}


/**
* called by the xml parser functions to set the data 
* on a certain element
* the element must have been already created by my_set_node_attributes !
*/
function my_set_node_data($node,$data)
{
  global $my_xml_data;
  /*
  if (isset($my_xml_data[$node]))
    $my_xml_data[$node][data] .=$data;
  else*/
    $my_xml_data[$node][data]= $data;
}

/**
* called by the xml parser functions to set the  attributes
* on a certain element
* the element is created here !
*/
function my_set_node_attributes($node,$attr)
{
  global $my_xml_data;
  
   $my_xml_data[$node] = array(attributes=>$attr);
}

/**
* called by the xml parser functions to create a node 
* according to the array stack of all tags opened with the current one
* being $tag
* All nodes are added [n] at the end of their name
* where n is their number of occurence
*/
function my_get_node_from_stack($stack,$tag)
{
  global $my_xml_data;


  $pre = implode("/",$stack);
  $name ="";
  $i = 1;
  while( $name == "")
    { 
      if (!isset($my_xml_data[$pre.'/'.$tag."[$i]"]))
        $name = $tag."[$i]";
      else
	$i++;
    }

  return $name;
}
/**
* called by the xml parser functions to create a full node
* according to a stack.
*/
function my_get_full_path_node_from_stack($stack)
{
  return implode("/",$stack);
}

// for the xml parser
// handles the attributes for opening tags
// $attrs is a multidimensional array keyed by attribute
// name and having the value of that attribute
function my_startElement($parser, $name, $attrs=''){
    global $my_tag_stack,$my_current_node,$my_current_data,$my_xml_data;

    $current_tag = strtolower($name);
    $my_tag_stack[] = my_get_node_from_stack($my_tag_stack,$current_tag);
    $my_current_node = my_get_full_path_node_from_stack($my_tag_stack);
    
    if ($attrs!='')
      my_set_node_attributes($my_current_node,$attrs);
    else
      my_set_node_attributes($my_current_node,array());

    $my_current_data ="";
}

// this function is passed data between elements
// the $data would equal 'Title Here'
// in the line <TITLE>Title Here</TITLE>
function my_characterData($parser, $data){
  global $my_current_data;

  $my_current_data.=$data;

}

// $current_tag lets us know what tag we are currently
// dealing with - we use that later in the characterData
// function.
function my_endElement($parser, $name, $attrs='')
{
  global $my_tag_stack,$my_current_node,$my_current_data;

  my_set_node_data($my_current_node,$my_current_data);
  $my_current_data="";
  array_pop( $my_tag_stack );
  $my_current_node = my_get_full_path_node_from_stack($my_tag_stack);
}
Return current item: Webgenerator-X content management system