Critique - XML Parser

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
User avatar
infolock
DevNet Resident
Posts: 1708
Joined: Wed Sep 25, 2002 7:47 pm

Critique - XML Parser

Post by infolock »

Code: Select all

 
<?php
/**
 * @author Jonathon Hibbard
 * 
 * Parses an XML file and returns a multidimentional array..
 * 
 */
 
class jxml {
  public $debug = false;
  public $_xml = "";
  public function jxml($debug = false) {
    $this->_xml = '';
    if($debug === true) {
      $this->debug = true;
    }
  }
 
  
  
  /**
   * Loads the XML string data into the $_xml private var.
   *
   * @param  string $xml_data // String of XML data..
   * @return boolean          // Returns true
   */
  public function loadXML($xml_data = '') {
    $this->_xml = trim($xml_data);
    if($this->debug == true) echo "\n XML IS : ".$this->_xml." \n";
    return true;
  }
 
  /**
   * Reads the file passed in and creates an array to be used with $this->_xml private var.
   *
   * @param  file     $xml_file // A file that contains the XML information.
   * @return boolean  true/fall // Returns TRUE on success, FALSE on error.
   */
  public function loadFile($xml_file = '') {
    if(!$fp = fopen($xml_file, 'r')) return false;
    $xml = '';
    while (!feof($fp)) $xml .= fread($fp, 4096);
    fclose($fp);
 
    if($this->debug == true) echo "\n\n XML DATA IS AS FOLLOWS : \n $xml \n\n";
 
    $this->_xml = trim($xml);
    return true;
  }
 
  /**
   * Creates a multi-dimensional array for the contents of the XML.
   *
   * @param  boolean $white_space   // When set to TRUE, it will skip whitespace when called.
   * @param  boolean $die_on_error  // If set to TRUE, function will die and clear all XML data on error.
   * @return mixed   $array         // A multi-dimensional array containing the XML data.
   */
  public function toArray($white_space = 1, $die_on_error = 1) {
    $vals = $index = $array = array();
    $parser = xml_parser_create();
 
    xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
    xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, $white_space);
 
    if(!xml_parse_into_struct($parser, $this->_xml, $vals, $index)) {
      xml_parser_free($parser);
      return false;
    }
    xml_parser_free($parser);
    $i = 0;
    $tagname              = $vals[$i]['tag'];
    $array[$tagname]['@'] = (isset($vals[$i]['attributes']) ? $vals[$i]['attributes'] : array());
    $array[$tagname]["#"] = $this->_xml_depth($vals, $i);
 
    if($this->debug == true) echo "\n\n tagname composition : \n ".print_r($tagname,1)."\n\n array[tagname] composition: \n".print_r($array,1)."\n\n";
 
    return $array;
  }
 
  /**
   * Recursive function to create children in each parent node.
   *
   * @param unknown_type $vals
   * @param unknown_type $i
   * @return unknown
   */
  public function _xml_depth($vals, &$i) {
    $children = array();
 
    if(isset($vals[$i]['value'])) array_push($children, $vals[$i]['value']);
 
    while (++$i < count($vals)) {
      switch ($vals[$i]['type']) {
        case 'open':
          $tagname = (isset($vals[$i]['tag']) ? $vals[$i]['tag'] : '');
          $size    = (isset($children[$tagname]) ? sizeof($children[$tagname]) : 0);
 
          if(isset($vals[$i]['attributes'])) $children[$tagname][$size]['@'] = $vals[$i]["attributes"];
          $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i);
        break;
 
        case 'cdata':
          array_push($children, $vals[$i]['value']);
        break;
 
        case 'complete':
          $tagname                        = $vals[$i]['tag'];
          $size                           = (isset($children[$tagname]) ? sizeof($children[$tagname]) : 0);
          $children[$tagname][$size]["#"] = (isset($vals[$i]['value']) ? $vals[$i]['value'] : '');
 
          if (isset($vals[$i]['attributes'])) $children[$tagname][$size]['@'] = $vals[$i]['attributes'];
        break;
 
        case 'close':
          return $children;
        break;
      }
    }
 
    return $children;
  }
 
  /**
   * Easy way to keep track of where we are in the stack.
   *
   * @param unknown_type $array
   * @param unknown_type $arrName
   * @param unknown_type $level
   * @return unknown
   */
  public function traverse_xmlize($array, $arrName = "array", $level = 0) {
    foreach($array as $key => $val) {
      if(is_array($val)) {
        traverse_xmlize($val, $arrName . "[" . $key . "]", $level + 1);
      } else {
        $GLOBALS['traverse_array'][] = '$' . $arrName . '[' . $key . '] = "' . $val . "\"\n";
      }
    }
    return 1;
  }
}
?>
 
Usage

Code: Select all

 
$xml = new jxml();
$xml->loadFile($xml_file);
$xml_array = $xml->toArray();
echo "<pre>";
print_r($xml_array);
echo "</pre>";
?>
 
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Re: Critique - XML Parser

Post by John Cartwright »

Code: Select all

$xml = new SimpleXMLElement(file_get_contents('http://www.w3schools.com/XML/note.xml'));
 
echo '<pre>';
print_r($xml);
For those of us with SimpleXML extension :)
User avatar
infolock
DevNet Resident
Posts: 1708
Joined: Wed Sep 25, 2002 7:47 pm

Re: Critique - XML Parser

Post by infolock »

Yeah, I know about SimpleXML. I use it actually with PHP 5 as I had originally written this class for PHP 4 (added the new OOP crap for 5) :lol:

Guess it's time to retire this class :(
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Critique - XML Parser

Post by josh »

I was going to say the same thing but I still think its neat you wrote this. Did you know you can't call print_r within an ob_start() callback? Something about ob_start callbacks can't use output buffering and print_r uses it "under the hood", I'm sure someone could find obscure uses.
Post Reply