) - removed fancy printing crap - added method ConfigParse::getElement() and ConfigParse::getElements() - bugfix- added ConfigParse::$_lastEnd, to not add cdata right after a this means that in the case of: ... CDATA the CDATA will be ignored. Note: this could also be changed to add the CDATA to 's node - changed Node::add_data so it doesn't always add a space at the start - removed Node::$type variable - added ConfigParse::getElementData and ConfigParse:getElementAttrib - renamed back to XML() - pass xml data instead of filename */ class Node { var $name; var $attributes; var $ancestors = "/"; var $data; function Node($tree) { $this->name = array_pop($tree); $this->ancestors .= implode("/", $tree); } function add_data($value) { $this->data = (strlen($this->data) > 0 ? $this->data.' '.$value : $value); } function get_type() { if (strlen($this->data) > 0) { return "with CDATA"; } else { return "without CDATA"; } } function level() { if ($this->ancestors == "/") return 0; if (preg_match_all("/(\/{1})/", $this->ancestors, $result,PREG_PATTERN_ORDER)) { return (count($result[0])); } else { return 0; } } function has_attributes() { return (is_array($this->attributes)); } function print_name() { return "$this->name"; } function is_child($node) { $result = preg_match("/^$ancestors/", $node->ancestors, $match); if ($node->ancestors == $this->ancestors) $result = false; return $result; } } class XML { var $tree = array(); var $nodes = array(); var $PIs; var $error; var $_lastEnd; function XML($data) { $this->_error = false; $xml_parser = xml_parser_create(); xml_set_object($xml_parser,$this); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "characterData"); xml_set_processing_instruction_handler ($xml_parser, "process_instruction"); # Why should one want to use case-folding with XML? XML is case-sensitiv, I think this is nonsense xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false); if (!xml_parse($xml_parser, $data, true)) { $this->error = sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser)); } } function startElement($parser, $name, $attribs) { # Adding the additional element to the tree, including attributes $this->tree[] = $name; $node = new Node($this->tree); while (list($k, $v) = each($attribs)) { $node->attributes[$k] = $v; } $this->nodes[] = $node; $this->_lastEnd = false; } function endElement($parser, $name) { # Adding a new element, describing the end of the tag # But only, if the Tag has CDATA in it! # Check if (count($this->nodes) >= 1) { $prev_node = $this->nodes[count($this->nodes)-1]; if (strlen($prev_node->data) > 0 || $prev_node->name != $name) { $this->tree[count($this->tree)-1] = "/".$this->tree[count($this->tree)-1]; // gm 04/10/03 - dont add element for end node //$this->nodes[] = new Node($this->tree, NULL); } else { # Adding a slash to the end of the prev_node $prev_node->name = $prev_node->name."/"; $this->nodes[count($this->nodes)-1]->name = $this->nodes[count($this->nodes)-1]->name."/" ; } } # Removing the element from the tree array_pop($this->tree); $this->_lastEnd = true; } function characterData($parser, $data) { $data = ltrim($data); if (($data != "") && (!$this->_lastEnd)) { $this->nodes[count($this->nodes)-1]->add_data($data); } } function process_instruction($parser, $target, $data) { if (preg_match("/xml:stylesheet/", $target, $match) && preg_match("/type=\"text\/xsl\"/", $data, $match)) { preg_match("/href=\"(.+)\"/i", $data, $this->PIs); # print "found xls pi: $PIs[1]
\n" } } // gets the element specified by path (first match) // path is in the format "/Container/Of/Element" // if the element is single (ie, "") then include a trailing / ("/Container/Of/Element/") function &getElement($path) { // see if this is a single element (ie, ), if so, remove // trailing / so as not to mess up explode() etc $slash = false; if ($path[strlen($path)-1] == "/") { $path = substr($path, 0, -1); $slash = true; } // change into "/Container/Of" and "Element" $temp = explode("/", $path); $name = array_pop($temp).($slash ? "/" : ""); // add slash back, if it needs it $path = implode("/", $temp); foreach ($this->nodes as $node) { if ($node->ancestors == $path) { if ($node->name == $name) { return $node; } } } return false; } // get the CDATA for an element function getElementData($path) { $node = $this->getElement($path); if ($node) { return $node->data; } } // get a specific attribute for an element // NOTE: if calling this multiple times for the same element, its better to use getElement() // and access the attributes directly (otherwise you're seaching through the nodes many times) function getElementAttrib($path, $attrib) { $node = $this->getElement($path); if (isset($node->attributes[$attrib])) { return $node->attributes[$attrib]; } return false; } // gets the elements specified by path (into an array) // path is in the format "/Container/Of/Element" function getElements($path) { $return = array(); foreach ($this->nodes as $node) { if ($node->ancestors == $path) { $return[] = $node; } } return $return; } } ?>