Location: PHPKode > projects > Ps and Qs: Processing QTI using PHP > qti-eb/qti-eb.php
<?php

class xmlElement
{
  var $name = '';
  var $attributes = array();
  var $content = array();

  function xmlElement($myname = '', $myattributes = array(), $mycontent = array())
  {
    $this->name = $myname;
	$this->attributes = $myattributes;
	$this->content = $mycontent;
  }
}


$file = $_REQUEST['file'];
$elements = $stack = array();
$total_elements = $total_chars = 0;

$submitted = $_REQUEST; // The "$submitted" parameter normally comes from POST/GET data
                        //   but can be used in other ways

$internalqtielementstack = array(); // Use push and pop to maintain a context list in this array

function processQtiFile($file)
{
  global $internalqtielementstack;

  // Initialise variables
  $internalqtielementstack = array();

  // Initialise the XML parser
  $parser = xml_parser_create();
  xml_set_element_handler($parser, 'qtiparser_start_element', 'qtiparser_stop_element');
  xml_set_character_data_handler($parser, 'qtiparser_char_data');
  xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
  
  //Parse the file
  qtiEbVeryStart();
  $ret = parseQtiXmlFromFile($parser, $file);
  qtiEbVeryEnd();
  if(!$ret)
    die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($parser)),
	                                        xml_get_current_line_number($parser)));
  
  // Free the parser
  xml_parser_free($parser);
}

// The function which pushes all the data through the Expat parser
function parseQtiXmlFromFile($parser, $file)
{
  if(!file_exists($file))
    die("Can't find file \"$file\".");
  elseif(!($fp = @fopen($file, 'r')))
    die("Can't find file \"$file\".");
  
  while($data = fread($fp, 4096))
    if(!xml_parse($parser, $data, feof($fp)))
	  return false;
  fclose($fp);
  return true;
}

// Expat calls this when it finds an opening tag
function qtiparser_start_element($parser, $name, $attrs)
{
  global $internalqtielementstack;
  
  $element = new xmlElement;
  $element->name = $name;
  $element->attributes = $attrs;
  
  // Add it to the context list
  array_push($internalqtielementstack, $element);
  
  // Call the start function for this tag (which MUST be defined elsewhere!)
  $eval='qtiebStart' . preg_replace('/\W/','',$name);
//  echo "<p>$eval</p>";
  if(strlen($eval)>0)
    if(function_exists($eval))
      $eval($attrs, $internalqtielementstack);
	else
	  echo "\n\n<p>UNEXPECTED ELEMENT WARNING: $name</p>\n\n";
}

// Expat calls this when it finds a closing tag
function qtiparser_stop_element($parser, $name)
{
  global $internalqtielementstack;

  if(sizeof($internalqtielementstack)>1)
  {
    // Remove it from the context list
    array_pop($internalqtielementstack);
  }
  // Call the stop function for this tag (which MUST be defined elsewhere!)
  $eval='qtiebStop' . preg_replace('/\W/','',$name);
//  echo "<p>$eval</p>";
  if(strlen($eval)>0)
    if(function_exists($eval))
      $eval($internalqtielementstack);
	else
	  echo "\n\n<p>End of unexpected element: $name</p>\n\n";
}

// Expat calls this when it finds character data
function qtiparser_char_data($parser, $data)
{
  global $internalqtielementstack;
  if(trim($data)!='')
  {
    $internalqtielementstack[sizeof($internalqtielementstack)-1]->content[] = $data;
    $name = $internalqtielementstack[sizeof($internalqtielementstack)-1]->name;
    // Call the data function for this tag (which MUST be defined elsewhere!)
    $eval='qtiebData' . preg_replace('/\W/','',$name);
//  echo "<p>$eval</p>";
    if(strlen($eval)>0)
      if(function_exists($eval))
        $eval($internalqtielementstack, $data);
  }
}


// Function used during processing, to check whether an element should be returned or not,
// according to the attributes criteria
function attributesMatchTest($criteria, $test)
{
  if(sizeof($criteria)==0)
    return true;

  foreach($criteria as $k=>$v)
    if($test[$k]!=$v)
	  return false;
  return true;
}

?>
Return current item: Ps and Qs: Processing QTI using PHP