; * @author Akili AS ; * @copyright Akili AS, February 2003 * @version 0.8 * @access public * @package XML */ class XmlParser { //{{{ Class variables /** * Reference to the rootnode of the parsed XML tree. * @access private */ var $rootNode; /** * The documents processing instruction * @access public */ var $doctype = ''; /** * An instance of the expat parser. * @access private */ var $xmlParser; /** * The parsing stack. * @access private */ var $stack; /** * Index of current top level element in the stack * @access private */ var $stackIndex = 0; //}}} //{{{ Constructor /** * Class constructor * * @access public */ function XmlParser( ) {} //}}}end constructor //{{{ setEncoding( String ) - US-ASCII, ISO-8859-1 and UTF-8 supported /** * Set the character encoding the parser should use. * * This function creates a new instance of the expat parser object, so it's not * possible to change the character encoding after parsing. * US-ASCII, ISO-8859-1 and UTF-8 supported * * @todo implement a wrapper for the utf8_enocde/decode functions in the * expat parser * @param string $encoding * Which character encoding the parser should use. Ie ISO-8859-1 * (default), US-ASCII, UTF-8 * @access public */ function setEncoding( $encoding ) { $this->_createParser($encoding); } //}}}end method setEncoding //{{{ parseString(String) /** * Parse the content of xmlDoc as a XML document. * * @param string $xmlDoc * The XML document to be parsed. * @access public */ function parseString( $xmlDoc ) { if (!isset($this->xmlParser)) $this->_createParser(); xml_parse($this->xmlParser, $xmlDoc); if (!assert ('XML_ERROR_NONE == xml_get_error_code($this->xmlParser)')) { $errorMsg = xml_error_string(xml_get_error_code($this->xmlParser)); echo 'An error occured while parsing this XML document in XmlParser::parseString:
'; echo htmlspecialchars($xmlDoc); echo '

The error was: '.$errorMsg.'

'; $this->_printStackTrace(); } } //}}}end method parseString //{{{ parseFile(String) /** * Parse the content of the file named in $filename as a XML document. * * @param string $filename * Filename of XML document to be parsed. * @access public */ function parseFile( $filename ) { if (!assert ('is_file($filename)')) { $errorMsg = xml_error_string(xml_get_error_code($this->xmlParser)); echo 'File '.$filename.' does not exist in call to XmlParser::parseFile:
'; $this->_printStackTrace(); return; } $fp = fopen($filename, 'r'); $file = fread($fp, filesize($filename)); fclose($fp); $this->parseString($file); } //}}}end method parseFile //{{{ getRootNode /** * Get a reference to the rootnode of the XML tree after parsing a XML document. * * @return object XmlNode * A reference to the rootnode of the XML tree. * @access public */ function &getRootNode( ) { return $this->rootNode; } //}}}end method getRootNode //{{{ getNodeAt(String) /** * Get the node at the location given in the $path parameter. * * The parameter to this function should be formated according to the W3C's * XPath specification. http://www.w3.org/TR/xpath for more information. * Only simple paths can be used. * Some examples:
* /
.
childOfRoot/aNode[2]/childNode
childOfRoot/anode/childNode
etc. * NOTE: You can not specify the name of the root node in the path. ie * /root/node/node2 will not work, but node/node2/ will. * * @param string $path * The path to the node to retrieve. * @access public */ function &getNodeAt( $path ) { return $this->rootNode->getChild($path); } //}}}end method getNodeAt //{{{ _characterHandler(Expat parser, String) /** * Character handler. See expat docs for details. * * @param resource $parser * A reference to teh XML parser calling the handler * @param string $data * The character data as a string * @see http://www.php.net/xml * @access private */ function _characterHandler( $parser, $data ) { if (trim($data) != '' || trim($this->stack[$this->stackIndex]->getValue()) != '') $this->stack[$this->stackIndex]->appendValue($data); } //}}}end method _characterHandler //{{{ _startElementHandler(Expat parser, String, Array) /** * Start element handler. See expat docs for details. * * @param resource $parser * A reference to the XML parser calling this handler. * @param string $name * Name of the element for which this handler is called. * @param array $attribs * An associative array with the elements attributes (if any). The keys of this * array are the attribute names, the values are the attribute values. * @see http://www.php.net/xml * @access private */ function _startElementHandler( $parser, $name, $attribs ) { ++$this->stackIndex; unset($this->stack[$this->stackIndex]); $this->stack[$this->stackIndex] = new XmlNode($name, $attribs); if (!isset($this->rootNode)) { $this->rootNode = &$this->stack[$this->stackIndex]; } else { $this->stack[$this->stackIndex-1]->addChild('.', $this->stack[$this->stackIndex]); } } //}}}end method _startElementHandler //{{{ _endElementHandler(Expat parser, String) /** * End element handler. See expat docs for details. * @param resource $parser * A reference to the XML parser calling the handler * @param string $name * Contains the name of the closing element which this handler is called for. * @see http://www.php.net/xml * @access private */ function _endElementHandler( $parser, $name ) { if (!assert ('$this->stackIndex > -1')) { echo 'Stack underflow in XmlParser::_endElementHandler:
'; $this->_printStackTrace(); return; } --$this->stackIndex; } //}}}end method _endElementHandler //{{{ _piHandler(Expat parser, String) /** * FIXME: NOT IMPLEMENTED */ function _piHandler( $parser, $target, $data ) { /*echo "This is output from an unimplemented method (_piHandler) in class.XmlParser.php
\n"; print_r($target); print_r($data);*/ }//}}}end method _piHandler //{{{ _notDeclHandler(Expat parser, String) /** * End element handler. See expat docs for details.(This method is not yet supported) * @param $parser * The first parameter, parser, is a reference to the XML parser calling the handler. * @param $notation_name * This is the notation's name * @param $base * This is the base for resolving the system identifier (system_id) of the * notation declaration. Currently this parameter will always be set to an * empty string. * @ param $system_id System identifier of the external notation declaration. * @ param $public_id Public identifier of the external notation declaration. * @see http://www.php.net/xml * @access private */ function _notDeclHandler( $parser, $notation_name, $base, $system_id, $public_id) { /*echo "This is output from an unimplemented method (_notDeclHandler) in class.XmlParser.php
\n"; print_r($notation_name); print_r($base); print_r($system_id); print_r($public_id);*/ }//}}}end method _notDeclHandler //{{{ _defaultHandler(Expat parser, String) /** * End element handler. See expat docs for details. * @param resource $parser * The first parameter, parser, is a reference to the XML parser calling the handler. * @param string $data * @see http://www.php.net/xml * @access private */ function _defaultHandler( $parser, $data ) { if ($this->stackIndex == 0) { $this->doctype .= $data; } else { if (trim($data) != '') { $this->stack[$this->stackIndex]->appendValue($data); } } }//}}}end method _defaultHandler //{{{ _createParser(String) /** * Create an expat XML parser, using the supplied characterset * * @param string $encoding The characterset of the document to be parsed. */ function _createParser( $encoding='ISO-8859-1' ) { $this->xmlParser = xml_parser_create($encoding); xml_set_object($this->xmlParser, &$this); xml_parser_set_option($this->xmlParser, XML_OPTION_CASE_FOLDING, 0); xml_set_element_handler($this->xmlParser, '_startElementHandler', '_endElementHandler'); xml_set_character_data_handler($this->xmlParser, '_characterHandler'); xml_set_processing_instruction_handler( $this->xmlParser, '_piHandler'); xml_set_notation_decl_handler( $this->xmlParser, '_notDeclHandler'); xml_set_default_handler ( $this->xmlParser, '_defaultHandler'); } //}}}end method _createParser //{{{ reset /** * Remove the contents of this class, and make it ready for reuse. */ function reset() { $this->rootNode = null; $this->stack = null; $this->xmlParser = null; $stackIndex = 0; } //}}}end method reset //{{{_printStackTrace /** * Prints a stacktrace of the callstack * * @access private */ function _printStackTrace( ) { $dbt = debug_backtrace(); echo 'Complete trace of callstack:
'; array_shift($dbt); foreach($dbt as $eachCall) { echo $eachCall['function'].' called from '.$eachCall['file'].':'; echo $eachCall['line'].'
'; } echo '

'; }//}}}end function _printStackTrace } ?>