From 8b85f096bff7ab9d4660e53815b9d6acd42794d2 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Mon, 1 Aug 2005 00:37:47 +0000 Subject: [PATCH] Fixed XML parsing framework; it now returns much more useful results :) --- xml.php | 213 ++++++++++++++++++++++++++------------------------------ 1 file changed, 99 insertions(+), 114 deletions(-) diff --git a/xml.php b/xml.php index e29a73d..a04267b 100644 --- a/xml.php +++ b/xml.php @@ -41,12 +41,6 @@ class XML_Parser */ var $parser = null; - /** - * Array of all parsed tag data - * @var array - */ - var $taginfo = array(); - /** * An array of function names that are to be executed for each tag name (name => function) * @var array() @@ -55,42 +49,28 @@ class XML_Parser var $taghandler = array(); /** - * Whether we should trim CDATA elements - * @var bool - * @see parse() + * Current CDATA value + * @var string */ - var $trimdata = true; + var $cdata = ''; /** - * Attribute data parsed from the tags + * Tag stack of all open nodes * @var array - * @see _tag_start() - */ - var $attrdata = array(); - - /** - * Internal tracker for the current tag - * @var int; */ - var $tagid = -1; + var $stack = array(); /** - * Internal tracker for the name of the current tag - * @var str - */ - var $tagname = ''; - - /** - * An internal tree to sort out the nesting of elements + * Node list for all open tag attributes * @var array */ - var $tree = array(); + var $attribs = array(); /** - * Internal tracker for the tag above the current one - * @var int + * Resulting parsed array + * @var array */ - var $parent = -1; + var $result = array(); /** * Parse an XML file @@ -101,22 +81,19 @@ class XML_Parser */ function parse($data) { - global $_isso; - - // reset all the parser data before starting - $this->taginfo = array(); - $this->attrdata = array(); - $this->tagid = -1; - $this->tagname = ''; - $this->tree = array(); - $this->parentid = -1; - + $this->stack = array(); + $this->attribs = array(); + $this->result = array(); + $this->cdata = ''; + // create a new parser $this->parser = xml_parser_create(); xml_set_object($this->parser, $this); xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); - xml_set_element_handler($this->parser, '_tag_start', '_tag_end'); - xml_set_character_data_handler($this->parser, '_cdata'); + xml_set_element_handler($this->parser, 'handle_tag_start', 'handle_tag_end'); + xml_set_character_data_handler($this->parser, 'handle_cdata'); + + $this->attach_node($this->result); // parse the data and check for errors if (!xml_parse($this->parser, $data)) @@ -125,54 +102,15 @@ class XML_Parser $error['string'] = xml_error_string($error['code']); $error['line'] = xml_get_current_line_number($this->parser); $error['column'] = xml_get_current_column_number($this->parser); - trigger_error(sprintf("XML Error: %s at line %d colunn %d", $error['string'], $error['line'], $error['column']), E_USER_ERROR); + trigger_error('XML Error: $error[string] at line $error[line] colunn $error[column]', E_USER_ERROR); exit; } // destroy the parser xml_parser_free($this->parser); - // data manipulation -- kind of resource intensive :-/ - foreach ($this->taginfo AS $tagname => $parents) - { - foreach ($parents AS $parentid => $ids) - { - foreach ($ids AS $tagid => $data) - { - // trim data if necessary - if ($this->trimdata) - { - $_isso->debug("data trim: on"); - if (($trimmed = trim($data)) != '') - { - $data = $trimmed; - } - } - - // if we have a data handler, operate it now - if (isset($this->taghandler["$tagname"])) - { - $_isso->debug("handler: " . $this->taghandler["$tagname"]); - if (function_exists($this->taghandler["$tagname"])) - { - $data = $this->taghandler["$tagname"]($data, $this); - } - else - { - trigger_error('Could not find the function [' . $this->taghandler["$tagname"] . '()] for the XML tag "' . $tagname . '"', E_USER_ERROR); - } - } - - $return["$tagid"] = array('tagid' => $tagid, 'tagname' => $tagname, 'parentid' => $parentid, 'attributes' => $this->attrdata["$tagid"], 'data' => $data); - } - } - } - - // place the normal order on things - ksort($return); - // done... send the results back - return $return; + return $this->result; } /** @@ -182,28 +120,30 @@ class XML_Parser * @param str Tag name * @param array Tag attributes */ - function _tag_start($parser, $name, $attributes) + function handle_tag_start(&$parser, $name, $attrs) { - // we're opening a new tag - $this->tagid++; - $this->tagname = $name; - - // copy all tag attributes - array_walk($attributes, 'trim'); - $this->attrdata[ $this->tagid ] = $attributes; - - // refocus the array - end($this->tree); - - // calculate the parent - $this->parent = current($this->tree); - $this->parent = (($this->parent === false) ? -1 : $this->parent); - - // add the current element onto the array - array_push($this->tree, $this->tagid); - - // initialize the data set - $this->taginfo["$name"][ $this->parent ][ $this->tagid ] = ''; + // trim attributes + array_walk($attrs, 'trim'); + + // existing node set + if (isset($this->attribs["$name"])) + { + // node set has < 1 child nodes + if (!isset($this->attribs["$name"][0])) + { + $tmp = $this->attribs["$name"]; + unset($this->attribs["$name"]); + $this->attribs["$name"][0] = $tmp; + } + + // create a new child node + $this->attach_node($this->attribs["$name"][] = (array)$attrs); + } + // node set doesn't exist, so create it + else + { + $this->attach_node($this->attribs["$name"] = (array)$attrs); + } } /** @@ -212,14 +152,9 @@ class XML_Parser * @param res XML parser * @param str CDATA from tag */ - function _cdata($parser, $data) + function handle_cdata(&$parser, $data) { - // read in the CDATA - if ($this->parent == $this->tagid AND !isset($this->taginfo[ $this->tagname ][ $this->parent ][ $this->tagid ])) - { - $this->taginfo[ $this->tagname ][ $this->parent ][ $this->tagid ] = ''; - } - $this->taginfo[ $this->tagname ][ $this->parent ][ $this->tagid ] .= $data; + $this->cdata .= $data; } /** @@ -228,10 +163,60 @@ class XML_Parser * @param res XML parser * @param str Tag name */ - function _tag_end($parser, $name) + function handle_tag_end(&$parser, $name) + { + global $_isso; + + // attach data to the node + if (($this->cdata = trim($this->cdata)) != '') + { + // if we have a data handler, operate it now + if (isset($this->taghandler["$name"])) + { + $_isso->debug("handler: " . $this->taghandler["$name"]); + if (function_exists($this->taghandler["$name"])) + { + $this->cdata = $this->taghandler["$name"]($this->cdata, $this); + } + else + { + trigger_error('Could not find the function [' . $this->taghandler["$name"] . '()] for the XML tag "' . $name . '"', E_USER_ERROR); + } + } + + $this->attribs['value'] = $this->cdata; + } + + $this->cdata = ''; + + // remove the node + $this->detach_node(); + } + + /** + * Shifts the node tree + * + * @param array Node to place into the stack + */ + function attach_node(&$node) + { + // create a new node + $this->stack[ count($this->stack) ] =& $node; + + // new attributes to work with + $this->attribs =& $node; + } + + /** + * Unshifts the node tree + */ + function detach_node() { - // pop off the end element - array_pop($this->tree); + // drop the newest node + unset($this->stack[ count($this->stack) - 1 ]); + + // assign the attributes to the next newest node + $this->attribs =& $this->stack[ count($this->stack) - 1 ]; } } -- 2.43.5