New file |
0,0 → 1,304 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
|
/** |
* Key gateway class for XML_Feed_Parser package |
* |
* PHP versions 5 |
* |
* LICENSE: This source file is subject to version 3.0 of the PHP license |
* that is available through the world-wide-web at the following URI: |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of |
* the PHP License and are unable to obtain it through the web, please |
* send a note to license@php.net so we can mail you a copy immediately. |
* |
* @category XML |
* @package XML_Feed_Parser |
* @author James Stewart <james@jystewart.net> |
* @copyright 2005 James Stewart <james@jystewart.net> |
* @license http://www.gnu.org/copyleft/lesser.html GNU LGPL |
* @version CVS: $Id: Parser.php 304308 2010-10-11 12:05:50Z clockwerx $ |
* @link http://pear.php.net/package/XML_Feed_Parser/ |
*/ |
|
/** |
* This is the core of the XML_Feed_Parser package. It identifies feed types |
* and abstracts access to them. It is an iterator, allowing for easy access |
* to the entire feed. |
* |
* @author James Stewart <james@jystewart.net> |
* @version Release: @package_version@ |
* @package XML_Feed_Parser |
*/ |
class XmlFeedParser implements Iterator { |
/** |
* This is where we hold the feed object |
* @var Object |
*/ |
private $feed; |
|
/** |
* To allow for extensions, we make a public reference to the feed model |
* @var DOMDocument |
*/ |
public $model; |
|
/** |
* A map between entry ID and offset |
* @var array |
*/ |
protected $idMappings = array(); |
|
/** |
* A storage space for Namespace URIs. |
* @var array |
*/ |
private $feedNamespaces = array( |
'rss2' => array( |
'http://backend.userland.com/rss', |
'http://backend.userland.com/rss2', |
'http://blogs.law.harvard.edu/tech/rss')); |
/** |
* Detects feed types and instantiate appropriate objects. |
* |
* Our constructor takes care of detecting feed types and instantiating |
* appropriate classes. For now we're going to treat Atom 0.3 as Atom 1.0 |
* but raise a warning. I do not intend to introduce full support for |
* Atom 0.3 as it has been deprecated, but others are welcome to. |
* |
* @param string $feed XML serialization of the feed |
* @param bool $strict Whether or not to validate the feed |
* @param bool $suppressWarnings Trigger errors for deprecated feed types? |
* @param bool $tidy Whether or not to try and use the tidy library on input |
*/ |
function __construct($feed, $strict = false, $suppressWarnings = true, $tidy = true) { |
$this->model = new DOMDocument; |
if (! $this->model->loadXML($feed)) { |
if (extension_loaded('tidy') && $tidy) { |
$tidy = new tidy; |
$tidy->parseString($feed, array('input-xml' => true, 'output-xml' => true)); |
$tidy->cleanRepair(); |
if (! $this->model->loadXML((string) $tidy)) { |
throw new XmlFeedParserException("Entrée invalide : le flux n'est pas du XML valide"); |
} |
} else { |
throw new XmlFeedParserException("Entrée invalide : le flux n'est pas du XML valide"); |
} |
} |
|
/* detect feed type */ |
$doc_element = $this->model->documentElement; |
$error = false; |
|
switch (true) { |
case ($doc_element->namespaceURI == 'http://www.w3.org/2005/Atom'): |
$class = 'XmlFeedParserAtom'; |
break; |
case ($doc_element->namespaceURI == 'http://purl.org/atom/ns#'): |
$class = 'XmlFeedParserAtom'; |
$error = "Atom 0.3 est déprécié, le parseur en version 1.0 sera utilisé mais toutes les options ne seront pas disponibles."; |
break; |
case ($doc_element->namespaceURI == 'http://purl.org/rss/1.0/' |
|| ($doc_element->hasChildNodes() && $doc_element->childNodes->length > 1 |
&& $doc_element->childNodes->item(1)->namespaceURI == 'http://purl.org/rss/1.0/')): |
$class = 'XmlFeedParserRss1'; |
break; |
case ($doc_element->namespaceURI == 'http://purl.org/rss/1.1/' |
|| ($doc_element->hasChildNodes() |
&& $doc_element->childNodes->length > 1 |
&& $doc_element->childNodes->item(1)->namespaceURI == 'http://purl.org/rss/1.1/')): |
$class = 'XmlFeedParserRss11'; |
break; |
case (($doc_element->hasChildNodes() |
&& $doc_element->childNodes->length > 1 |
&& $doc_element->childNodes->item(1)->namespaceURI == 'http://my.netscape.com/rdf/simple/0.9/') |
|| $doc_element->namespaceURI == 'http://my.netscape.com/rdf/simple/0.9/'): |
$class = 'XmlFeedParserRss09'; |
break; |
case ($doc_element->tagName == 'rss' |
and $doc_element->hasAttribute('version') |
&& $doc_element->getAttribute('version') == 0.91): |
$error = 'RSS 0.91 has been superceded by RSS2.0. Using RSS2.0 parser.'; |
$class = 'XmlFeedParserRss2'; |
break; |
case ($doc_element->tagName == 'rss' |
and $doc_element->hasAttribute('version') |
&& $doc_element->getAttribute('version') == 0.92): |
$error = 'RSS 0.92 has been superceded by RSS2.0. Using RSS2.0 parser.'; |
$class = 'XmlFeedParserRss2'; |
break; |
case (in_array($doc_element->namespaceURI, $this->feedNamespaces['rss2']) |
|| $doc_element->tagName == 'rss'): |
if (! $doc_element->hasAttribute('version') || $doc_element->getAttribute('version') != 2) { |
$error = 'RSS version not specified. Parsing as RSS2.0'; |
} |
$class = 'XmlFeedParserRss2'; |
break; |
default: |
throw new XmlFeedParserException('Type de flux de syndicaton inconnu'); |
break; |
} |
|
if (! $suppressWarnings && ! empty($error)) { |
trigger_error($error, E_USER_WARNING); |
} |
|
/* Instantiate feed object */ |
$this->feed = new $class($this->model, $strict); |
} |
|
/** |
* Proxy to allow feed element names to be used as method names |
* |
* For top-level feed elements we will provide access using methods or |
* attributes. This function simply passes on a request to the appropriate |
* feed type object. |
* |
* @param string $call - the method being called |
* @param array $attributes |
*/ |
function __call($call, $attributes) { |
$attributes = array_pad($attributes, 5, false); |
list($a, $b, $c, $d, $e) = $attributes; |
return $this->feed->$call($a, $b, $c, $d, $e); |
} |
|
/** |
* Proxy to allow feed element names to be used as attribute names |
* |
* To allow variable-like access to feed-level data we use this |
* method. It simply passes along to __call() which in turn passes |
* along to the relevant object. |
* |
* @param string $val - the name of the variable required |
*/ |
function __get($val) { |
return $this->feed->$val; |
} |
|
/** |
* Provides iteration functionality. |
* |
* Of course we must be able to iterate... This function simply increases |
* our internal counter. |
*/ |
function next() { |
if (isset($this->current_item) && |
$this->current_item <= $this->feed->numberEntries - 1) { |
++$this->current_item; |
} else if (! isset($this->current_item)) { |
$this->current_item = 0; |
} else { |
return false; |
} |
} |
|
/** |
* Return XML_Feed_Type object for current element |
* |
* @return XML_Feed_Parser_Type Object |
*/ |
function current() { |
return $this->getEntryByOffset($this->current_item); |
} |
|
/** |
* For iteration -- returns the key for the current stage in the array. |
* |
* @return int |
*/ |
function key() { |
return $this->current_item; |
} |
|
/** |
* For iteration -- tells whether we have reached the |
* end. |
* |
* @return bool |
*/ |
function valid() { |
return $this->current_item < $this->feed->numberEntries; |
} |
|
/** |
* For iteration -- resets the internal counter to the beginning. |
*/ |
function rewind() { |
$this->current_item = 0; |
} |
|
/** |
* Provides access to entries by ID if one is specified in the source feed. |
* |
* As well as allowing the items to be iterated over we want to allow |
* users to be able to access a specific entry. This is one of two ways of |
* doing that, the other being by offset. This method can be quite slow |
* if dealing with a large feed that hasn't yet been processed as it |
* instantiates objects for every entry until it finds the one needed. |
* |
* @param string $id Valid ID for the given feed format |
* @return XML_Feed_Parser_Type|false |
*/ |
function getEntryById($id) { |
if (isset($this->idMappings[$id])) { |
return $this->getEntryByOffset($this->idMappings[$id]); |
} |
|
/* |
* Since we have not yet encountered that ID, let's go through all the |
* remaining entries in order till we find it. |
* This is a fairly slow implementation, but it should work. |
*/ |
return $this->feed->getEntryById($id); |
} |
|
/** |
* Retrieve entry by numeric offset, starting from zero. |
* |
* As well as allowing the items to be iterated over we want to allow |
* users to be able to access a specific entry. This is one of two ways of |
* doing that, the other being by ID. |
* |
* @param int $offset The position of the entry within the feed, starting from 0 |
* @return XML_Feed_Parser_Type|false |
*/ |
function getEntryByOffset($offset) { |
if ($offset < $this->feed->numberEntries) { |
if (isset($this->feed->entries[$offset])) { |
return $this->feed->entries[$offset]; |
} else { |
try { |
$this->feed->getEntryByOffset($offset); |
} catch (Exception $e) { |
return false; |
} |
$id = $this->feed->entries[$offset]->getID(); |
$this->idMappings[$id] = $offset; |
return $this->feed->entries[$offset]; |
} |
} else { |
return false; |
} |
} |
|
/** |
* Retrieve version details from feed type class. |
* |
* @return void |
* @author James Stewart |
*/ |
function version() { |
return $this->feed->version; |
} |
|
/** |
* Returns a string representation of the feed. |
* |
* @return String |
**/ |
function __toString() { |
return $this->feed->__toString(); |
} |
} |
?> |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |