Location: PHPKode > projects > RSS Framework for PHP > src/classes/parser/loader.php
<?php error_reporting(E_ALL);
/**
 * This file is part of the Dynamic Networks RSS Framework for PHP
 * 
 * @author Gordon Oheim (hide@address.com)
 * @copyright Copyright 2005, Dynamic Networks
 * @link http://www.dynamicnetworks.de
 * @license http://creativecommons.org/licenses/GPL/2.0/ GNU General Public License
 * @filesource
 * @version 1.0.0
 */
  require_once("parser.php");

/**
 * This class is a parser for reading RSS dump files into the framework
 * 
 * The class inherits from parser.
 *  
 * @package rssFramework
 * @author Gordon Oheim (hide@address.com)
 * @see transformer
 * @see parser
 */
  class loader extends parser {

		var $verbose;

		/**
		 * Loads an RSS feed and transforms it into the dump notation
		 * 
		 * This function will try to load the file specified by the param $path.
		 * On success, the function will try to transform the loaded file into
		 * the dump format needed by the loader class to import the feed into
		 * the framework. The function will return the DomDocument of the dump
		 * then. You can specify a remote path if fopen_wrappers are enabled in
		 * your php.ini and if the remote server supports this.
		 * 
		 * @param string $path
		 * @return DomDocument
		 * @see parser::tranform()
		 * @access public
		 */
		function load_feed($path) {
			$feed = null;
			if (!$feed = implode('', file($path))) {
				echo "FATAL ERROR: could not read input file";
				exit;
			}
			if (!$this->dom = domxml_open_mem($feed, DOMXML_LOAD_DONT_KEEP_BLANKS)) {
  				echo "Error while parsing the RSS document\n";
  				exit;
			} 
			return $this->transform($this->dom, './src/xslt/RSS20/to_dump.xslt');
		}

		/**
		 * Loads a dump file into memory
		 * 
		 * This function will try to load the dump file specified by the param
		 * $path. The result is a DomDocument containing the dump file needed by
		 * the loader class to import a feed into the framework. This function
		 * does not work with remote files.
		 * 
		 * @param string $path
		 * @return DomDocument
		 * @access public
		 */
		function load_dump($path) {
			if (!$this->dom = domxml_open_file($path, DOMXML_LOAD_DONT_KEEP_BLANKS)) {
  				echo "Error while parsing the DUMP document\n";
  				exit;
			} 
			$root = $this->dom->document_element();
			if (strtolower($root->node_name()) != "dump") {
				echo "FATAL ERROR: the file you specifed is not a dump document";
				exit;
			} else {			
				return $this->dom;
			}
		}

		/**
		 * Starts the import of a dump document into the framework
		 * 
		 * This function will parse the document held in $dom recursively and
		 * create objects from the framework from the nodes encountered. The
		 * result is a completely filled feed object. If $verbose is set to
		 * true, progress will be sent to the browser. Set this to true if you
		 * should encounter problems parsing your dump. It wil help you in
		 * debugging.
		 * 
		 * @param bool $verbose
		 * @return feed
		 * @access public
		 */
		function parse_dump($verbose = false) {
			if ($verbose == true) {
				$this->verbose = true;
			}
			$root = $this->dom->document_element();
			if (strtolower($root->node_name()) != "dump") {
				echo "FATAL ERROR: root node must be 'dump'";
				exit;
			} else {	
				return $this->process_node($root->first_child());
			}
		}

		/**
		 * Decides what to do with a DomNode
		 * 
		 * This function will decide what to do with a DomNode. The function
		 * takes two arguments $node and $parent. $node is the DomNode to be
		 * parsed and $parent is the object from the framework that the DomNode
		 * applies to. By default this param is null. Note that this function is
		 * considered private. It is called by parse_dump() and should not be
		 * called as a standalone function.
		 * 
		 * @param DomNode $node
		 * @param object $parent.
		 * @return object
		 * @see parse_dump()
		 * @access private
		 */
		function process_node($node, $parent = null) {
			$object = null;
			// there is only attribute and object in the dump notation
			switch ($node->node_name()) {
				// if $node is object, try to create one 
				case "object": {
					$object = $this->make_object($node);
					break;
				}
				// if $node is attribute, try to set the attribute to $parent 
				case "attribute": {
					if ($this->verbose == true) {
						echo "trying to set attribute " . $node->get_attribute('name') .
							" for " . get_class($parent)."<br>";
					}
					$this->set_attribute($node, &$parent);
					break;
				}
			}
			// if the node has children, send them to this function
			// if the current node is an object, pass it as parent
			if ($node->has_child_nodes()) {
				foreach ($node->child_nodes() as $child_node) {
					$this->process_node($child_node, &$object);
				}
			}
			return $object;
		}
		
		/**
		 * Calls a set method of an object
		 * 
		 * This function will try to set the DomNode value of the DomNode passed
		 * in the param $node to the object passed in the param $parent. The
		 * function will recognize the type attribute of $node and will decide
		 * what to do with it. See the sourcecode for more details on the
		 * decision process. Note that this function is considered private. It
		 * is called by process_node() or by itself and should not be called as
		 * a standalone function.
		 * 
		 * @param DomNode $node
		 * @param object $parent.
		 * @return mixed
		 * @see process_node()
		 * @access private
		 */
		function set_attribute($node, $parent) {
			$type = $node->get_attribute('type');
			$name = $node->get_attribute('name');
			$child = $node->first_child();
			$content = null; 
			// start the decision process
			switch (true) {
				case ($type == 'array'): {
					// if node is an array, make the return value an array
					$content = array();
					// process the child nodes and add them to that array
					foreach ($node->child_nodes() as $child) {
						if ($child->node_name() == "object") {
							// nodes that hold objects must be send to process_node()
							// to create those objects before adding them to the array
							$content[] = $this->process_node($child, &$node);
						} else {
							// nodes that hold attributes will simply be added to the
							// array by calling this nodes parent object 
							$content[] = $this->set_attribute($child, &$node);
						}
					}
					break;
				}
				case (class_exists($type)): {
					// if there is a class that corresponds to the type of the 
					// current node, parse the child node of the current node and
					// set the result as content
					$content = $this->process_node($child, &$node);
					break;
				}
				default: {
					// if nothing of the above occurs, assume the current node is 
					// a text node and get the nodes content. The result is typecasted
					// into the type specified by the nodes attribute type.
					$content = html_entity_decode($child->get_content());
					settype($content, $type); 
					break;
				}
			}
			
			// now the function will to try to set content to the parent 
			// object by calling the set method corresponding to the attributes
			// name and 
			$method = "set_$name";
			if ($this->verbose == true) {
				echo get_class($parent)."::$method($content)";
			}
			// if there is a set() method defined for the passed object
			// set the determined content call this function
			if (method_exists($parent, $method)) {
				 if ($this->verbose == true) {
				 	echo "- true <br/>";
				 }
				$parent->$method($content);
			// if there is no set() method defined, do nothing
			} elseif ($this->verbose == true) {
				echo " - false<br/>";
			}	
			return $content;
		}

		/**
		 * creates a new instance of an object in the framework
		 * 
		 * this function reads the attribute type of the passed $node and
		 * creates a new object from it. If the class type of the node requires
		 * params to be passed to the constructor, the function will try to find
		 * the wrapper method in $this and call that method instead of simply
		 * calling a new instance.
		 * 
		 * @param DomNode $node
		 * @return object
		 * @access private
		 */
		function make_object($node) {
			$class = $node->get_attribute('type');
			if ($this->verbose == true) {
				echo "made $class <br/>";
			}
			if (method_exists($this, $class)) {
				return $this->$class($node);
			}
			else {
				return new $class();
			}
		}

		// -------------------------------------------------------
		// the following methods are rssFramework specific to call
		// class constructors that require params.
		// -------------------------------------------------------
		// if you want to use the loader to parse non-rssFramework
		// dumps, make sure to have your constructors down here.
		// -------------------------------------------------------

		/**
		 * creates a new url object
		 * 
		 * This function creates a new url object from the child nodes found in
		 * $node. Because there are no set methods in the url class, the
		 * attributes of url are set directly. This is only possible if the
		 * attributes are public. The description for the vars in url label all
		 * attributes as private, so in PHP5 you should either make them public
		 * or create set methods for each attribute and rewrite this function.
		 * If you rewrite this function, you only need to return a url with a
		 * fake URI, because if set methods are present, they will be called by
		 * the loader just right after the url object from this method is
		 * returned.
		 * 
		 * @param DomNode $node
		 * @return url
		 * @see url::url()
		 * @access private
		 */
		function url($node) {
			$child = $node->first_child();
			if ($child->node_name() == "string") {
				return new url(html_entity_decode($child->get_content()));
			}
			else {
				$url = new url("http://www.example.com");			
				foreach ($node->child_nodes() as $element) {
					$name = $element->get_attribute('name');
					$text = $element->first_child();
					$text = $text->get_content();
					$url->$name = html_entity_decode($text);
				}
				return new url($url->get_url());
			}
		}
		
		/**
		 * creates a new textInput object
		 * 
		 * This function returns a dummy textInput object. Because there are
		 * set methods for textInput, the attributes for the object will be set
		 * by the loader in the next step of the recursion, so there is no need
		 * to process the passed param $node.
		 * 
		 * @param DomNode $node
		 * @return textInput
		 * @see textInput::textInput()
		 * @access private
		 */
		function textInput($node) {
			// dummy function.
			return new textInput("",new url("http:/example.com"),"","");
		}

		/**
		 * creates a new email object
		 * 
		 * This function returns a dummy email object. Because there are set
		 * methods for email, the attributes for the object will be set by the
		 * loader in the next step of the recursion, so there is no need to
		 * process the passed param $node.
		 * 
		 * @param DomNode $node
		 * @return email
		 * @see email::email()
		 * @access private
		 */
		function email($node) {
			$child = $node->first_child();
			if ($child->node_name() == "string") {
				$child = $child->get_content();
				$recipient = strstr($child, " ");
				$address = str_replace($recipient, "", $child);
				$recipient = str_replace("(", "", $recipient);
				$recipient = html_entity_decode(str_replace(")", "", $recipient));
				return new email(trim($address), trim($recipient));
			}
			else {
				return new email("hide@address.com","Jane Doe");
			}
		}

		/**
		 * creates a new category object
		 * 
		 * This function returns a dummy categoryobject. Because there are set
		 * methods for category, the attributes for the object will be set by
		 * the loader in the next step of the recursion, so there is no need to
		 * process the passed param $node.
		 * 
		 * @param DomNode $node
		 * @return category
		 * @see category::category()
		 * @access private
		 */
		function category($node) {
			// dummy function.
			return new category("");
		}

		/**
		 * creates a new enclosure object
		 * 
		 * This function returns a dummy enclosure object. Because there are set
		 * methods for enclosure, the attributes for the object will be set by
		 * the loader in the next step of the recursion, so there is no need to
		 * process the passed param $node.
		 * 
		 * @param DomNode $node
		 * @return enclosure
		 * @see enclosure::enclosure()
		 * @access private
		 */
		function enclosure($node) {
			// dummy function.
			return new enclosure(new url("http://www.example.com"),0,"dummy");
		}

		/**
		 * creates a new guid object
		 * 
		 * This function returns a dummy guid object. Because there are set
		 * methods for guid, the attributes for the object will be set by the
		 * loader in the next step of the recursion, so there is no need to
		 * process the passed param $node.
		 * 
		 * @param DomNode $node
		 * @return guid
		 * @see guid::guid()
		 * @access private
		 */
		function guid($node) {
			// dummy function.
			return new guid("dummy");
		}

		/**
		 * creates a new skipHours array
		 * 
		 * This function returns an empty array. The array values are filled by
		 * the loader in the next step of the recursion, so there is no need to
		 * process the passed param $node.
		 * 
		 * @param DomNode $node
		 * @return array
		 * @see channel::set_skipHours()
		 * @access private
		 */
		function skipHours($node) {
			// dummy function.
			return array();
		}

		/**
		 * creates a new skipDays array
		 * 
		 * This function returns an empty array. The array values are filled by
		 * the loader in the next step of the recursion, so there is no need to
		 * process the passed param $node.
		 * 
		 * @param DomNode $node
		 * @return array
		 * @see channel::set_skipDays()
		 * @access private
		 */	
		 function skipDays($node) {
			// dummy function.
			return array();
		}
 }
?>
Return current item: RSS Framework for PHP