initialize(); // Read the entire file contents in to memory. // If file sizes get too large, we'll have to be smarter here. $file = fopen($file_name, "r"); $xml = fread($file, filesize($file_name)); fclose($file); parse_xml_string($xml, $file_handler); } function parse_xml_string($xml, & $file_handler) { $GLOBALS['handler'] = $file_handler; $parser = xml_parser_create(); xml_set_element_handler($parser, 'sax_start_handler', 'sax_end_handler'); xml_set_character_data_handler($parser, 'sax_data_handler'); xml_parse($parser, $xml); if (xml_get_error_code($parser)) throw new SaxParsingException(xml_error_string($parser)); } class SaxParsingException extends Exception { public function __construct($message, $code = 0) { parent::__construct($message, $code); } } /* * The $handler variable is global. It manages all the call backs * that come (indirectly) from the SAX parser. */ $handler = null; /* * SAX parser callback method to handle the start of an element. * This method just defers to the global handler to do the actual * work. */ function sax_start_handler($parser, $name, $attributes) { global $handler; $handler->start($name, $attributes); } /* * SAX parser callback method to handle the text for an element. * This method just defers to the global handler to do the actual * work. */ function sax_data_handler($parser, $data) { global $handler; $handler->data($data); } /* * SAX parser callback method to handle the end of an element. * This method just defers to the global handler to do the actual * work. */ function sax_end_handler($parser, $name) { global $handler; $handler->end($name); } /* * The XmlHandler class is the focal point of the SAX parser callbacks. * It keeps track of a stack of element handlers. The element handlers * are used to handle whatever elements come in. */ class XmlFileHandler { var $stack; function XmlFileHandler() { $this->stack = array (); } function initialize() { $element_handler = $this->get_root_element_handler(); array_push($this->stack, $element_handler); } function get_root_element_handler() { return new DoNothingHandler(); } function end_root_element_handler($handler) { } /* * Handle the start callback. Here, we get the current element handler * from the top of the stack and ask it what to do. The element handler * is asked to provide a new handler to handle the new element. That new * handler is put on the top of the stack and will handle all future * callbacks until it is removed (by the end method). */ function start($name, $attributes) { $handler = & array_last($this->stack); $next = & $handler->get_next($name, $attributes); array_push($this->stack, $next); } /* * Data has been encountered, send the data to the current element handler * to sort out what needs to be done. */ function data($data) { $handler = & array_last($this->stack); $handler->data($data); } /* * The end of an element has occurred. Pop the current element handler * from the top of the stack and tell it that it's work is done. */ function end($name) { $handler = & array_pop($this->stack); $handler->end($name); $next_handler = & array_last($this->stack); $next_handler->end_handler($name, $handler); // If we've just popped off the last actual element handler, leaving // only the root handler at the top of the stack, send it the end message. if (count($this->stack) == 1) $this->end_root_element_handler($handler); } } class XmlElementHandler { function & get_next($name, $attributes) { $method_name = "get_" . str_replace("-", "_", $name) . "_handler"; if (method_exists($this, $method_name)) { return $this->$method_name($attributes); } else { return new DoNothingHandler(); } } function end_handler($name, $handler) { $method_name = "end_" . str_replace("-", "_", $name) . "_handler"; if (method_exists($this, $method_name)) { return $this->$method_name($handler); } } function initialize() { } /* * Ignore data for this element. */ function data($data) { } function start($name) { } /* * Ignore data for this element. */ function end($name) { } } class SimpleTextHandler extends XmlElementHandler { var $text; function & get_next($name, $attributes) { return new DoNothingHandler(); } function data($data) { $this->text .= $data; } function end($name) { $this->text = html_entity_decode($this->text); } } class SimplePropertyHandler extends SimpleTextHandler { var $owner; var $property; function SimplePropertyHandler(& $owner, $property) { $this->owner = & $owner; $this->property = $property; } function end($name) { parent::end($name); $this->set_property_value($this->text); } function set_property_value(& $value) { $property = $this->property; $this->owner-> $property = $value; } } class DoNothingHandler extends XmlElementHandler { function & get_next($name, $attributes) { return $this; } } function & array_last(& $array) { return $array[count($array) - 1]; } ?>