Source for file parser.php

Documentation is available at parser.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  Feed
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. /**
  13.  * Feed Parser class.
  14.  *
  15.  * @package     Joomla.Platform
  16.  * @subpackage  Feed
  17.  * @since       12.3
  18.  */
  19. abstract class JFeedParser
  20. {
  21.     /**
  22.      * The feed element name for the entry elements.
  23.      *
  24.      * @var    string 
  25.      * @since  12.3
  26.      */
  27.     protected $entryElementName = 'entry';
  28.  
  29.     /**
  30.      * Array of JFeedParserNamespace objects
  31.      *
  32.      * @var    array 
  33.      * @since  12.3
  34.      */
  35.     protected $namespaces = array();
  36.  
  37.     /**
  38.      * The XMLReader stream object for the feed.
  39.      *
  40.      * @var    XMLReader 
  41.      * @since  12.3
  42.      */
  43.     protected $stream;
  44.  
  45.     /**
  46.      * Constructor.
  47.      *
  48.      * @param   XMLReader  $stream  The XMLReader stream object for the feed.
  49.      *
  50.      * @since   12.3
  51.      */
  52.     public function __construct(XMLReader $stream)
  53.     {
  54.         $this->stream  = $stream;
  55.     }
  56.  
  57.     /**
  58.      * Method to parse the feed into a JFeed object.
  59.      *
  60.      * @return  JFeed 
  61.      *
  62.      * @since   12.3
  63.      */
  64.     public function parse()
  65.     {
  66.         $feed new JFeed;
  67.  
  68.         // Detect the feed version.
  69.         $this->initialise();
  70.  
  71.         // Let's get this party started...
  72.         do
  73.         {
  74.             // Expand the element for processing.
  75.             $el new SimpleXMLElement($this->stream->readOuterXml());
  76.  
  77.             // Get the list of namespaces used within this element.
  78.             $ns $el->getNamespaces(true);
  79.  
  80.             // Get an array of available namespace objects for the element.
  81.             $namespaces array();
  82.  
  83.             foreach ($ns as $prefix => $uri)
  84.             {
  85.                 // Ignore the empty namespace prefix.
  86.                 if (empty($prefix))
  87.                 {
  88.                     continue;
  89.                 }
  90.  
  91.                 // Get the necessary namespace objects for the element.
  92.                 $namespace $this->fetchNamespace($prefix);
  93.  
  94.                 if ($namespace)
  95.                 {
  96.                     $namespaces[$namespace;
  97.                 }
  98.             }
  99.  
  100.             // Process the element.
  101.             $this->processElement($feed$el$namespaces);
  102.  
  103.             // Skip over this element's children since it has been processed.
  104.             $this->moveToClosingElement();
  105.         }
  106.         while ($this->moveToNextElement());
  107.  
  108.         return $feed;
  109.     }
  110.  
  111.     /**
  112.      * Method to register a namespace handler object.
  113.      *
  114.      * @param   string                $prefix     The XML namespace prefix for which to register the namespace object.
  115.      * @param   JFeedParserNamespace  $namespace  The namespace object to register.
  116.      *
  117.      * @return  JFeed 
  118.      *
  119.      * @since   12.3
  120.      */
  121.     public function registerNamespace($prefixJFeedParserNamespace $namespace)
  122.     {
  123.         $this->namespaces[$prefix$namespace;
  124.  
  125.         return $this;
  126.     }
  127.  
  128.     /**
  129.      * Method to initialise the feed for parsing.  If child parsers need to detect versions or other
  130.      * such things this is where you'll want to implement that logic.
  131.      *
  132.      * @return  void 
  133.      *
  134.      * @since   12.3
  135.      */
  136.     abstract protected function initialise();
  137.  
  138.     /**
  139.      * Method to parse a specific feed element.
  140.      *
  141.      * @param   JFeed             $feed        The JFeed object being built from the parsed feed.
  142.      * @param   SimpleXMLElement  $el          The current XML element object to handle.
  143.      * @param   array             $namespaces  The array of relevant namespace objects to process for the element.
  144.      *
  145.      * @return  void 
  146.      *
  147.      * @since   12.3
  148.      */
  149.     protected function processElement(JFeed $feedSimpleXMLElement $elarray $namespaces)
  150.     {
  151.         // Build the internal method name.
  152.         $method 'handle' ucfirst($el->getName());
  153.  
  154.         // If we are dealing with an item then it is feed entry time.
  155.         if ($el->getName(== $this->entryElementName)
  156.         {
  157.             // Create a new feed entry for the item.
  158.             $entry new JFeedEntry;
  159.  
  160.             // First call the internal method.
  161.             $this->processFeedEntry($entry$el);
  162.  
  163.             foreach ($namespaces as $namespace)
  164.             {
  165.                 if ($namespace instanceof JFeedParserNamespace)
  166.                 {
  167.                     $namespace->processElementForFeedEntry($entry$el);
  168.                 }
  169.             }
  170.  
  171.             // Add the new entry to the feed.
  172.             $feed->addEntry($entry);
  173.         }
  174.         // Otherwise we treat it like any other element.
  175.         else
  176.         {
  177.             // First call the internal method.
  178.             if (is_callable(array($this$method)))
  179.             {
  180.                 $this->$method($feed$el);
  181.             }
  182.  
  183.             foreach ($namespaces as $namespace)
  184.             {
  185.                 if ($namespace instanceof JFeedParserNamespace)
  186.                 {
  187.                     $namespace->processElementForFeed($feed$el);
  188.                 }
  189.             }
  190.         }
  191.     }
  192.  
  193.     /**
  194.      * Method to get a namespace object for a given namespace prefix.
  195.      *
  196.      * @param   string  $prefix  The XML prefix for which to fetch the namespace object.
  197.      *
  198.      * @return  mixed  JFeedParserNamespace or false if none exists.
  199.      *
  200.      * @since   12.3
  201.      */
  202.     protected function fetchNamespace($prefix)
  203.     {
  204.         if (isset($this->namespaces[$prefix]))
  205.         {
  206.             return $this->namespaces[$prefix];
  207.         }
  208.  
  209.         $className get_class($thisucfirst($prefix);
  210.  
  211.         if (class_exists($className))
  212.         {
  213.             $this->namespaces[$prefixnew $className;
  214.  
  215.             return $this->namespaces[$prefix];
  216.         }
  217.  
  218.         return false;
  219.     }
  220.  
  221.     /**
  222.      * Method to move the stream parser to the next XML element node.
  223.      *
  224.      * @param   string  $name  The name of the element for which to move the stream forward until is found.
  225.      *
  226.      * @return  boolean  True if the stream parser is on an XML element node.
  227.      *
  228.      * @since   12.3
  229.      */
  230.     protected function moveToNextElement($name null)
  231.     {
  232.         // Only keep looking until the end of the stream.
  233.         while ($this->stream->read())
  234.         {
  235.             // As soon as we get to the next ELEMENT node we are done.
  236.             if ($this->stream->nodeType == XMLReader::ELEMENT)
  237.             {
  238.                 // If we are looking for a specific name make sure we have it.
  239.                 if (isset($name&& ($this->stream->name != $name))
  240.                 {
  241.                     continue;
  242.                 }
  243.  
  244.                 return true;
  245.             }
  246.         }
  247.  
  248.         return false;
  249.     }
  250.  
  251.     /**
  252.      * Method to move the stream parser to the closing XML node of the current element.
  253.      *
  254.      * @return  void 
  255.      *
  256.      * @since   12.3
  257.      * @throws  RuntimeException  If the closing tag cannot be found.
  258.      */
  259.     protected function moveToClosingElement()
  260.     {
  261.         // If we are on a self-closing tag then there is nothing to do.
  262.         if ($this->stream->isEmptyElement)
  263.         {
  264.             return;
  265.         }
  266.  
  267.         // Get the name and depth for the current node so that we can match the closing node.
  268.         $name  $this->stream->name;
  269.         $depth $this->stream->depth;
  270.  
  271.         // Only keep looking until the end of the stream.
  272.         while ($this->stream->read())
  273.         {
  274.             // If we have an END_ELEMENT node with the same name and depth as the node we started with we have a bingo. :-)
  275.             if (($this->stream->name == $name&& ($this->stream->depth == $depth&& ($this->stream->nodeType == XMLReader::END_ELEMENT))
  276.             {
  277.                 return;
  278.             }
  279.         }
  280.  
  281.         throw new RuntimeException('Unable to find the closing XML node.');
  282.     }
  283. }

Documentation generated on Tue, 19 Nov 2013 15:10:17 +0100 by phpDocumentor 1.4.3