Web/PHP

xml_parser

aucd29 2013. 9. 26. 21:47
After going through all the examples of XML to data structure examples posted here and having problems will all of them I came up with my own. It's not thoroughly tested but works very well for me.

This example will not give any 'depricated pass by reference' errors and returns false on mal-formed XML.

Example of using the Classes:
<?
$myXMLParser = new XMLStructParser;
$cds_XMLTag = $myXMLParser->parse('<cd_list><cd title="Best of PBS"><track number="1">Sesame Street Theme</track></cd></cd_list>');
print $bookXMLTag->children['cd_list'][1]->children['track'][1]->cdata;
?>

Here are the two class files:
XMLStructParse.phpclass
<?

require_once("XMLTag.phpclass");
class XMLStructParser {
var $index;        // Tracks position in the stack
var $obj_data;    // Holds the root XMLTag object
var $stack;        // Stack to track where we are in the XML Hiarchy


// Constructor
function XMLStructParser() {
}

function parse($data) {
     // Prepare the Object Array
     $this->index = 0;
     $this->obj_data = new XMLTag("XML");
    
     // Prepare the Stack
     $this->stack[$this->index] = &$this->obj_data;
    
     // Setup the XML Parser        
     $xml_parser = xml_parser_create();
     xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false);
     xml_set_object($xml_parser, $this);
     xml_set_element_handler($xml_parser, "tag_open", "tag_close");
     xml_set_character_data_handler($xml_parser, "cdata");

     // Parse the XML
     $parse_results = xml_parse($xml_parser, $data);

     // Clean up
     xml_parser_free($xml_parser);

     if ($parse_results) {
         return $this->obj_data;
     } else {
         return false;
     }
}

function tag_open($parser, $tag, $attributes) {
     // Create the new Child tag
     $theTag = new XMLTag($tag);
     $theTag->addAttributes($attributes);

     // Add the child tag to the current tag. The & is necessary to get a pointer to the object child in the object. Not a Clone of it.
     $childTag = &$this->stack[$this->index]->addChild($theTag);
    
     // Make the new child tag now be the current tag
     $this->index++;
     $this->stack[$this->index] = &$childTag;
}

function cdata($parser, $cdata) {
     $this->stack[$this->index]->cdata = $cdata;
}

function tag_close($parser, $tag) {
     $this->index--;
}
}

?>

XMLTag.phpclass
<?

class XMLTag {
var $name;            // String
var $cdata;            // String
var $children;        // Array of children. array['tag'][0] is the tag count. [1] ... [n] reference each child tag object    

// Constructor
function XMLTag($name, $cdata="") {
     $this->name = $name;
     $this->cdata = $cdata;
}


// Addes attributes as children. An attribute is really just a quick way to do a child tag anyways
function addAttributes($attribute_array) {
     foreach ($attribute_array as $key => $value) {
         // If no children by this name exist then initialize it.
         if ( !isset($this->children[$key][0]) ) {
             $index = 1;
             $this->children[$key][0] = 0;    
         } else {
             $index = $this->children[$key][0] + 1;
         }
        
         // Assign the value and increment the tag count
         $this->children[$key][$index] = new XMLTag($key, $value);
         $this->children[$key][0]++;
     }
    
     return;
}

function addChild($XMLTag_obj) {
     $key = $XMLTag_obj->name;
    
     // If this tag *name* is not already a child initialize it.        
     if ( !isset($this->children[$key][0]) ) {
         $index = 1;
         $this->children[$key][0] = 0;    
     } else {
         $index = $$this->children[$key][0] + 1;
     }

     // Add the child and update the tag count
     $this->children[$key][$index] = $XMLTag_obj;
     $this->children[$key][0]++;

     // Return the Child Tag
     return $this->children[$key][$index];
}
}
?>