<?php /* * XmlParser.class.php -- Version 14-Jan-2006 * * Copyright (c) 2004-2006 Jochen Kupperschmidt * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * The above license is the MIT License. It was copied from the website of the * Open Source Initiative: http://www.opensource.org/licenses/mit-license.php * _ _ * | |_ ___ _____ ___ _ _ _ ___ ___| |_ * | | . | | ._| | | | . | _| . / * |_|_|___|_|_|_|___|_____|___|_| |_|_\ * http://homework.nwsnet.de/ * * This can be seen as XML SAX parser framework. With it, you can easily create * parsers for your custom XML tags. * * To create a parser, write a subclass of the XmlParser class and add methods * which names start with 'handle_', followed by the tag name it should react * to. When the parser reaches a closing tag, the corresponding method will be * called. Its parameters will be an associative array containing the * attributes firstly and a string containing the character data (the data * enclosed by start and end tag of an element) secondly. * * Example usage: * * # Include the parser framework. * require_once('XmlParser.class.php'); * * # Subclass it. * class XmlLinkParser extends XmlParser { * * # This would react on * # <link href="http://www.example.com/">Example.com</link> * # and return * # <a href="http://www.example.com/" * # target="_blank" * # title="Visit Example.com" * # >Example.com (http://www.example.com/)</a> * function handle_link($attr, $cdata) { * return sprintf( * '<a href="%s" target="_blank" title="Visit %s">%s (%s)</a>', * $attr['href'], $cdata, $cdata, $attr['href']); * } * } * * # Instanciate the custom parser. * $parser = new XmlLinkParser(); * * # Parse a file with XML content and display the result. * echo $parser->parseFile('example.xml'); * * # Parse a string and display the result. * echo $parser->parseString('<div> * <h1>Some links</h1> * <ul> * <li><link href="http://www.example.com/one/">Example #1</link></li> * <li><link href="http://www.example.com/two/">Example #2</link></li> * <li><link href="http://www.example.com/three/">Example #3</link></li> * </ul> * </div> * '); */ # A stack. # # Elements can be pushed upon or popped off the top. class Stack { var $stack = array(); # Place an element on the stack. function push($data) { array_push($this->stack, $data); } # Take an element off the stack. function pop() { if (! $this->stack) { trigger_error('Stack buffer underrun.', E_USER_ERROR); } return array_pop($this->stack); } } # The basic SAX parser. # # Subclasses may implement methods which names begin with "handle_", followed # by the tag name to be reacted to. # # Example: # function handle_something($attr, $cdata) { ... } # It will be invoked when the closing part of the <something> element is found. class XmlParser { var $stack; # Read XML from file. function parseFile($filename) { if (! file_exists($filename)) { trigger_error('File not found.', E_USER_WARNING); return False; } return $this->parseString(implode('', file($filename))); } # Read XML from string. function parseString($data) { $this->stack = new Stack(); $this->stack->push(array('content' => '')); $parser = xml_parser_create('iso-8859-1'); xml_set_object($parser, &$this); xml_set_element_handler($parser, 'startElement', 'endElement'); xml_set_character_data_handler($parser, 'characters'); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); if (! xml_parse($parser, $data)) { $errorCode = xml_get_error_code($parser); $errorString = xml_error_string($errorCode); $error = sprintf('Error parsing XML data (#%d: %s).', $errorCode, $errorString); trigger_error($error, E_USER_WARNING); } xml_parser_free($parser); $first = $this->stack->pop(); return $first['content']; } # ---------------------------------------------------------------- # # Called when an element starts. function startElement($parser, $tag, $attributes) { $this->stack->push(array( 'attributes' => $attributes, 'content' => '' )); } # Called when character data is found. function characters($parser, $cdata) { $data = $this->stack->pop(); $data['content'] .= $cdata; $this->stack->push($data); } # Called when an element ends. function endElement($parser, $tag) { $elementHandler = 'handle_' . strtolower($tag); $data = $this->stack->pop(); if (method_exists($this, $elementHandler)) { $buffer = call_user_func(array($this, $elementHandler), $data['attributes'], $data['content']); } else { $buffer = '<' . $tag; foreach ($data['attributes'] as $attr => $value) { $buffer .= sprintf(' %s="%s"', $attr, $value); } if (0 == strlen($data['content'])) { $buffer .= '/>'; } else { $buffer .= sprintf('>%s</%s>', $data['content'], $tag); } } $sublevel = $this->stack->pop(); $sublevel['content'] .= $buffer; $this->stack->push($sublevel); } } ?>