Jump to content

What are you using to generate your RSS feed? Is there a good php class?


Recommended Posts

I have a blog and photo gallery with entries in a MySQL database, and I have some procedural code that I use to generate a combined RSS feed containing new blog entries and photo albums.

 

However, I wanted to know if any of you could recommend a good php class to make this process easier?  Or, do you have an easier way of generating your RSS feed?

 

Thank you all in advance!

You just need to generate valid XML which conforms to the RSS specific standards. It's rather trivial and no different from generating (X)HTML. PHP has some built in classes which can deal with generation and parsing of XML documents such as SimpleXML and DOM.

For this tutorial which have been imported from the main site database I created a class which will do that. Here is the version from the database of the old site. It's formatted using HTML, but you should be able to read that.

<h1>Handling XML</h1>

<p>XML, E<u>x</u>tensible <u>M</u>arkup <u>L</u>anguage, is a general-purpose markup language which
can be used for storing arbitrary data in a structured way. It is often used for sharing data between
applications and a common usage of XML is for instance RSS feeds.</p>

<p>With the emerge of PHP 5, support for handling XML data has greatly improved and in this tutorial
we will take a look at the features in PHP 5 which we can use to parse, alter and create XML documents.
At the end of the tutorial we will also take a look at how you can create an <acronym title='Really Simple Syndication'>RSS</acronym>
feed without writing a single line of XML and then we will make it into a reusable class which you can
implement in your own applications. Additionally we'll create a <em>really</em> simple RSS reader.</p>

<p>Basic knowledge of XML is a prerequisite for this tutorial. Knowledge of XPath would be a good idea as
it will be used a bit in this tutorial, however, this is not entirely important. Furthermore, <acronym title='Object Oriented Programming'>OOP</acronym>
knowledge is a requirement as well.</p>

<p>Right, let's go to the next page and get started…</p>

[PAGEBREAK]
<style type='text/css'>tt { font-size: 120%; }</style>

<h1>Parsing XML</h1>

<p>PHP 5 has a class called <tt>SimpleXML</tt> which is… simple to use.</p>

<p>Throughout this tutorial we will use the file <tt>books.xml</tt> which I created using data from the
top three books on <a href='http://www.amazon.com/gp/feature.html/ref=amb_link_5358712_3?ie=UTF8&docId=1000158311&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-6&pf_rd_r=0D7BFNG1JWS3T589HQYZ&pf_rd_t=101&pf_rd_p=339467301&pf_rd_i=283155'>Amazon.com's Editor's Picks: Best Books of 2007</a>.
The content of the file is:</p>

<code><?xml version="1.0"?>
<books>
  <book isbn="978-1594489501">
    <title>A Thousand Splendid Suns</title>
    <author>Khaled Hosseini</author>
    <publisher>Riverhead Hardcover</publisher>
    <amazon_price>14.27</amazon_price>
  </book>
  <book isbn="978-1594489587">
    <title>The Brief Wondrous Life of Oscar Wao</title>
    <author>Junot Diaz</author>
    <publisher>Riverhead Hardcover</publisher>
    <amazon_price>14.97</amazon_price>
  </book>
  <book isbn="978-0545010221">
    <title>Harry Potter and the Deathly Hallows</title>
    <author>J. K. Rowling</author>
    <publisher>Arthur A. Levine Books</publisher>
    <amazon_price>19.24</amazon_price>
  </book>
</books></code>

<p>We can load our data into <tt>SimpleXML</tt> in two ways. Either we can pass a string to <tt>SimpleXML</tt>
or we can tell it where the file is:</p>

<code><?php
// Passing the XML
$data = file_get_contents('books.xml');
$books = SimpleXMLElement($data);
//-------------------
// Passing a filename
$books = SimpleXMLElement('books.xml', null, true);
?></code>

<p>If you have the file stored you should obviously use the latter approach as there is no reason to get
the file contents ourselves when we can get <tt>SimpleXML</tt> to do it for us. The first way could be used
if you already have some XML data which could for instance be retrieved from some web service. I only used
<tt>file_get_contents()</tt> for the purpose of that example.</p>

<p>The second argument is used to set certain options. We won't touch that in this tutorial, but you are free
to <a href='http://php.net/simplexml-element-construct'>research that yourself</a>. The third argument specifies
if the first argument is a filename (<tt>true</tt>) or actual XML data (<tt>false</tt>) and defaults to <tt>false</tt>.
If <tt>allow_url_fopen</tt> is set to <tt>true</tt> in <tt>php.ini</tt> then you can specify a URL as well.</tt></p>

<p>Now let's turn our XML data into an HTML table:</p>

<code><?php
// load SimpleXML
$books = new SimpleXMLElement('books.xml', null, true);

echo <<<EOF
<table>
<tr>
	<th>Title</th>
	<th>Author</th>
	<th>Publisher</th>
	<th>Price at Amazon.com</th>
	<th>ISBN</th>
</tr>

EOF;
foreach($books as $book) // loop through our books
{
echo <<<EOF
<tr>
	<td>{$book->title}</td>
	<td>{$book->author}</td>
	<td>{$book->publisher}</td>
	<td>\${$book->amazon_price}</td>
	<td>{$book['isbn']}</td>
</tr>

EOF;
}
echo '</table>';
?></code>

<p>This will result in a table looking like this:</p>

<table>
<tr>
	<th>Title</th>
	<th>Author</th>
	<th>Publisher</th>
	<th>Price at Amazon.com</th>
	<th>ISBN</th>
</tr>
<tr>
	<td>A Thousand Splendid Suns</td>
	<td>Khaled Hosseini</td>
	<td>Riverhead Hardcover</td>
	<td>$14.27</td>
	<td>978-1594489501</td>
</tr>
<tr>
	<td>The Brief Wondrous Life of Oscar Wao</td>
	<td>Junot Diaz</td>
	<td>Riverhead Hardcover</td>
	<td>$14.97</td>
	<td>978-1594489587</td>
</tr>
<tr>
	<td>Harry Potter and the Deathly Hallows</td>
	<td>J. K. Rowling</td>
	<td>Arthur A. Levine Books</td>
	<td>$19.24</td>
	<td>978-0545010221</td>
</tr>
</table>

<p style='margin-top: 1.5em;'>Right, so you say you wanted to display the title of the second book you'd do this (remember that array indices
start from 0):</p>

<code>echo $books->book[1]->title;</code>

<p>The <acronym title='International Standard Book Number'>ISBN</acronym> number of the same book is displayed
like this:</p>

<code>echo $books->book[1]['isbn'];</code>

<h2>XPath</h2>

<p>You can also run XPath queries. They are run using the <tt>SimpleXMLElement::xpath()</tt> method that method takes
a single argument, the XPath query. If we wanted to select all the book titles we could do something like this:</p>

<code><?php
$titles = $books->xpath('book/title');
foreach($titles as $title)
{
echo $title.PHP_EOL;
}
?></code>

<p>All ISBN numbers would be retrieved like this:</p>

<code><?php
$isbn = $books->xpath('book/@isbn');
foreach($isbn as $isbn)
{
echo $isbn.PHP_EOL;
}
?></code>

<p>You can of course use any valid XPath query. The method will always return an array.</p>

<h2>Parsing RSS feeds</h2>

<p>Now let's try to parse some real-world data. We'll use the <a href='http://www.phpfreaks.com/forums/index.php?type=rss;action=.xml'>RSS feed from the forums</a>.</p>

<code><?php
$rss = new SimpleXMLElement('http://www.phpfreaks.com/forums/index.php?type=rss;action=.xml', null, true);

echo "<h1><a href='{$rss->channel->link}'>{$rss->channel->title}</a></h1>".PHP_EOL.'<hr />'.PHP_EOL;

foreach($rss->xpath('channel/item') as $item)
{
echo <<<EOF
<h2><a href='{$item->link}'>{$item->title}</a></h2>
<div>Posted at: {$item->pubDate}</div>
{$item->description}
<hr />

EOF;
}
?></code>

<p>This was in fact the RSS reader I promised you on page 1. If you expected something fancy I suppose I've disappointed you.
If you want to make it fancy then just get started, add some AJAX, a spiffy interface and soon you'll be competing with
<a href='http://reader.google.com'>Google Reader</a>.</p>

<h2>Parsing data of unknown structure</h2>

<p>As you see, parsing XML data is simple with <tt>SimpleXML</tt> when you already know the structure of the XML data,
but what if you want to parse something which you don't already know the structure of? We'll take a look at that now,
but we'll still use our <tt>books.xml</tt> file.</p>

<code><?php
function parse_recursive(SimpleXMLElement $element, $level = 0)
{
$indent     = str_repeat("\t", $level); // determine how much we'll indent

$value      = trim((string) $element);  // get the value and trim any whitespace from the start and end
$attributes = $element->attributes();   // get all attributes
$children   = $element->children();     // get all children

echo "{$indent}Parsing '{$element->getName()}'...".PHP_EOL;
if(count($children) == 0 && !empty($value)) // only show value if there is any and if there aren't any children
{
	echo "{$indent}Value: {$element}".PHP_EOL;
}

// only show attributes if there are any
if(count($attributes) > 0)
{
	echo $indent.'Has '.count($attributes).' attribute(s):'.PHP_EOL;
	foreach($attributes as $attribute)
	{
		echo "{$indent}- {$attribute->getName()}: {$attribute}".PHP_EOL;
	}
}

// only show children if there are any
if(count($children))
{
	echo $indent.'Has '.count($children).' child(ren):'.PHP_EOL;
	foreach($children as $child)
	{
		parse_recursive($child, $level+1); // recursion 
	}
}

echo $indent.PHP_EOL; // just to make it "cleaner"
}

$xml = new SimpleXMLElement('books.xml', null, true);

parse_recursive($xml);
?></code>

<p><strong>Note:</strong> If you wish run that through your browser make sure to add <tt>header('Content-type: text/plain');</tt>
before anything is output so the browser will know it's plain text and not HTML we are serving.</p>

<p>We've used recursion which means that we theoretically will be able to parse any XML document
no matter how many times nested data there is (this is of course not possible due to script execution
time etc.).</p>

<p>In the script I decided that if there are any children then we won't display any possible value.
This is because of the way I've decided to output it. Had you chosen to use HTML to output it or chosen
to put it in an array then you could have taken the value as well.</p>

<p>That's it for parsing XML documents. Next we'll change documents.</p>

[PAGEBREAK]
<style type='text/css'>tt { font-size: 120%; }</style>

<h1>Altering XML data with PHP DOM</h1>

<p>Another thing I would like to introduce you to is PHP DOM. It's much more powerful than SimpleXML
and we'll be using this for the remainder of the tutorial.</p>

<h2>Adding nodes</h2>

<p>Still using <tt>books.xml</tt> we now want to add a new how many pages there are in each book and save
it as <tt>books2.xml</tt>.</p>

<code><?php
// isbn => pages
$page_numbers = array(
	'978-1594489501' => '384', // A Thousand Splendid Suns
	'978-1594489587' => '352', // The Brief Wondrous Life of Oscar Wao
	'978-0545010221' => '784', // Harry Potter and the Deathly Hallows
);

$dom = new DOMDocument();
$dom->load('books.xml');
$xpath = new DOMXPath($dom);

$books = $xpath->query('book');
foreach($books as $book)
{
$book->appendChild($dom->createElement('pages', $page_numbers[$book->getAttribute('isbn')]));
}

$dom->save('books2.xml');
?></code>

<p>First we have an array of ISBN numbers and page numbers. Then we create a new instance of <tt>DOMDocument</tt>
and load our file into it. Next we'll create an instance of DOMXPath and pass our <tt>$dom</tt> object to it.
Then we run an XPath query saying "select all nodes elements called 'book'". This will return an instance
of <tt>DOMNodelist</tt>. If you want to access a specific item then you can use <tt>DOMNodelist::item()</tt>. That
method takes one argument, the index of the element you wish to retrieve. The indices are named similarly to the
indices of an array (starting from 0).</p>

<p>You can iterate through <tt>DOMNodelist</tt> and that is what we're doing using the foreach loop. An instance
of <tt>DOMElement</tt> is stored in <tt>$book</tt>.</p>

<p>Inside the loop we do the following:</p>

<ol>
<li>Get the ISBN number (an attribute)</li>
<li>Get the number of pages using the ISBN number from our array</li>
<li>Create a new <tt>DOMElement</tt> with the value we just retrieved</li>
<li>Append the new element as a child to <tt>$book</tt></li>
</ol>

<p>Finally we save the file as <tt>books2.xml</tt>. We could have chosen to output it instead, and then the last
line should have been replaced with:</p>

<code>echo $dom->saveXML();</code>

<p>When selecting all the book elements we could also have used <tt>DOMDocument::getElementsByTagName()</tt>:</p>

<code>$books = $dom->getElementsByTagName('book');</code>

<h2>Changing data</h2>

<p>Now we'd like to change the author names so it's in a "Last name, First name" format instead of
"First name Last name". In our small file it would be easy to just change it, but suppose we had an
XML file with thousands of entries, it would be tedious having to change it all manually. Luckily we can again use PHP
for this purpose as we will now be looking at how you change data. The new data will be stored in <tt>books3.xml</tt>.</p>

<code><?php
$dom = new DOMDocument();
$dom->load('books.xml');
$xpath = new DOMXPath($dom);

$authors = $xpath->query('book/author');
foreach($authors as $author)
{
$a          = $author->nodeValue; // shortcut
$last_name  = substr($a, strrpos($a, ' ')+1);
$first_name = substr($a, 0, strrpos($a, ' '));
$author->nodeValue = "{$last_name}, {$first_name}";
}

$dom->save('books3.xml');
?></code>

<p>We start the same way as before. The XPath query this time says "get all elements called 'author' which are
children of an element called 'book'".</p>

<p>The value of a node can be accessed through its property <tt>nodeValue</tt>. We do some simple switching around
and change the node value for each author element. Finally we save again.</p>

<h2>Deleting data</h2>

<p>This time we want to make elements called <tt>author_firstname</tt> and <tt>author_lastname</tt> and then delete
<tt>author</tt>. We'll save it in <tt>books4.xml</tt>.</p>

<code><?php
$dom = new DOMDocument();
$dom->load('books.xml');
$xpath = new DOMXPath($dom);

$books = $xpath->query('book');
foreach($books as $book)
{
$author     = $book->getElementsByTagName('author')->item(0);
$a          = $author->nodeValue; // shortcut
$last_name  = substr($a, strrpos($a, ' ')+1);
$first_name = substr($a, 0, strrpos($a, ' '));

$book->removeChild($author);
$book->appendChild($dom->createElement('author_firstname', $first_name));
$book->appendChild($dom->createElement('author_lastname', $last_name));
}

$dom->save('books4.xml');
?></code>

<p>I believe the code is pretty self-explanatory. <tt>DOMElement::removeChild()</tt> removes a child and <tt>DOMElement::appendChild()</tt>
appends a child. Note that you need an instance of an element in order to remove it from another element.</p>

<p>There is another method called <tt>DOMElement::replaceChild()</tt> which takes two elements: the new and the old element.</p>

<h1>Parsing data with DOM</h1>

<p>You can use DOM to parse data as well, but it is easier to use SimpleXML. I'll show you anyways though. We'll use <tt>books4.xml</tt> to create
a table similar to the one we created using SimpleXML with <tt>books.xml</tt>.</p>

<code><?php
$dom = new DOMDocument();
$dom->load('books4.xml');
$xpath = new DOMXPath($dom);

$books = $xpath->query('book');
echo <<<EOF
<h1>Book listing</h1>
<table>
<tr>
	<th>Title</th>
	<th>Author</th>
	<th>Publisher</th>
	<th>Price at Amazon.com</th>
	<th>ISBN</th>
</tr>

EOF;
foreach($books as $book)
{
echo <<<EOF
<tr>
	<td>{$book->getElementsByTagName('title')->item(0)->nodeValue}</td>
	<td>{$book->getElementsByTagName('author_firstname')->item(0)->nodeValue} {$book->getElementsByTagName('author_lastname')->item(0)->nodeValue}</td>
	<td>{$book->getElementsByTagName('publisher')->item(0)->nodeValue}</td>
	<td>\${$book->getElementsByTagName('amazon_price')->item(0)->nodeValue}</td>
	<td>{$book->getAttribute('isbn')}</td>
</tr>

EOF;
}
echo '</table>';
?></code>

<p>As you see, SimpleXML is easier to use for parsing XML data. Where we could get the title like this in SimpleXML:</p>
<code>$book->title;</code> <p>We have to use this with DOM:</p> <code>$book->getElementsByTagName('title')->item(0)->nodeValue;</code>

<p>On the next page I'll show you how to tidy up your XML code.</p>

[PAGEBREAK]
<style type='text/css'>tt { font-size: 120%; }</style>

<h1>Tidying up the code</h1>

<p>If we take a look at the code generated for <tt>books4.xml</tt> then it doesn't look very nice:</p>

<code><?xml version="1.0"?>
<books>
  <book isbn="978-1594489501">
    <title>A Thousand Splendid Suns</title>
    
    <publisher>Riverhead Hardcover</publisher>
    <amazon_price>14.27</amazon_price>
  <author_firstname>Khaled</author_firstname><author_lastname>Hosseini</author_lastname></book>
  <book isbn="978-1594489587">
    <title>The Brief Wondrous Life of Oscar Wao</title>
    
    <publisher>Riverhead Hardcover</publisher>
    <amazon_price>14.97</amazon_price>
  <author_firstname>Junot</author_firstname><author_lastname>Diaz</author_lastname></book>
  <book isbn="978-0545010221">
    <title>Harry Potter and the Deathly Hallows</title>
    
    <publisher>Arthur A. Levine Books</publisher>
    <amazon_price>19.24</amazon_price>
  <author_firstname>J. K.</author_firstname><author_lastname>Rowling</author_lastname></book>
</books></code>

<p>Maybe you don't mind it looking like that, but now we'll see how to make it look nice, like the one
I hand-coded, <tt>books.xml</tt>. We'll use tidy functions in PHP. These functions are <em>not</em> enabled
by default (if I remember correctly).</p>

<p>Using tidy is extremely simple:</p>

<code><?php
$tidy_options = array(
	'input-xml'    => true,
	'output-xml'   => true,
	'indent'       => true,
	'wrap'         => false,
);

$tidy = new tidy();
$tidy->parseFile('books4.xml', $tidy_options);
$tidy->cleanRepair();

echo $tidy;
?></code>

<p>This results in:</p>

<code><?xml version="1.0"?>
<books>
  <book isbn="978-1594489501">
    <title>A Thousand Splendid Suns</title>
    <publisher>Riverhead Hardcover</publisher>
    <amazon_price>14.27</amazon_price>
    <author_firstname>Khaled</author_firstname>
    <author_lastname>Hosseini</author_lastname>
  </book>
  <book isbn="978-1594489587">
    <title>The Brief Wondrous Life of Oscar Wao</title>
    <publisher>Riverhead Hardcover</publisher>
    <amazon_price>14.97</amazon_price>
    <author_firstname>Junot</author_firstname>
    <author_lastname>Diaz</author_lastname>
  </book>
  <book isbn="978-0545010221">
    <title>Harry Potter and the Deathly Hallows</title>
    <publisher>Arthur A. Levine Books</publisher>
    <amazon_price>19.24</amazon_price>
    <author_firstname>J. K.</author_firstname>
    <author_lastname>Rowling</author_lastname>
  </book>
</books></code>

<p>Much nicer...</p>

<p>You can also load a string instead using <tt>tidy::parseString()</tt>. You can see all the options <a href='http://tidy.sourceforge.net/docs/quickref.html'>here</a>.</p>

<p>On the next page we'll create the RSS feed class which I promised you earlier.</p>

[PAGEBREAK]
<style type='text/css'>tt { font-size: 120%; }</style>

<h1>Creating an RSS feed class</h1>

<p>I'll first give you the entire class. Then we'll talk a bit about it. I written comments many places which explain
what the code is doing and we've been going through most of the functionality which is utilized in the class in the
previous pages so I won't go into great detail explaining it.</p>

<code><?php
class RSSFeed
{
private $title;
private $link;
private $description;
private $language;

private $items = array();

private $dom;
private $xpath;

public function __construct($title, $link, $description, $language = 'en-us')
{
	$this->set_title($title);
	$this->set_link($link);
	$this->set_description($description);
	$this->set_language($language);
}

public function add_item(array $data = array())
{
	if((array_key_exists('title', $data)       && empty($data['title'])) ||
	   (array_key_exists('link', $data)        && empty($data['link'])) ||
	   (array_key_exists('description', $data) && empty($data['description'])))
	{
		throw new Exception('Every item must have at least a title, link and description');
	}

	if(array_key_exists('pubDate', $data) && !is_integer($data['pubDate']))
	{
		throw new Exception('pubDate must be a UNIX timestamp');
	}
	else if(array_key_exists('pubDate', $data) && is_integer($data['pubDate'])) {
		$data['pubDate'] = gmdate('D, j M Y H:i:s T', $data['pubDate']);
	}

	$this->items[] = $data;

	return $this; // enables chaining
}

// various "set" functions
public function set_title($data)       { $this->title       = $data; }
public function set_link($data)        { $this->link        = $data; }
public function set_description($data) { $this->description = $data; }
public function set_language($data)    { $this->language    = $data; }

// various "get" functions
public function get_title()       { return $this->title;       }
public function get_link()        { return $this->link;        }
public function get_description() { return $this->description; }
public function get_language()    { return $this->language;    }

public function parse($tidy = false, $tidy_options = null)
{
	// create our DOM and XPath objects
	$this->dom   = new DOMDocument();
	$this->xpath = new DOMXPath($this->dom);

	$rss = $this->dom->createElement('rss');
	$rss->setAttribute('version', '2.0'); // sorry, hardcoded - if you wish another version then you're out of luck
	$this->dom->appendChild($rss);        // or, well... you could just change it

	$channel = $this->dom->createElement('channel');           // create the <channel> element
	$channel->appendChild($this->dom->createElement('title', $this->get_title())); // ... and add some children to it
	$channel->appendChild($this->dom->createElement('language', $this->get_language()));
	$channel->appendChild($this->dom->createElement('link', $this->get_link()));
	$channel->appendChild($this->dom->createElement('description', $this->get_description()));
	$rss->appendChild($channel); // finally append it to our root element (<rss>)

	// add the feeds
	foreach($this->items as $item)
	{
		$this->parse_item($item);
	}

	$xml = $this->dom->saveXML(); // generate XML

	// just in case somebody doesn't like the lack of newlines and indention in the generated output
	if(extension_loaded('tidy') && $tidy == true)
	{
		if(!is_array($tidy_options))
		{
			$tidy_options = array(
					'input-xml'    => true,
					'output-xml'   => true,
					'indent'       => true,
					'indent-cdata' => true,
					'wrap'         => false,
				);
		}
		$tidy_options['input-xml'] = true; // MUST be true

		$tidy = new tidy();
		$tidy->parseString($xml, $tidy_options);
		$tidy->cleanRepair();

		return (string) $tidy; // by using typecasting we'll ensure it's a string and not an object that is returned
	}
	else {
		return $xml;
	}
}

private function parse_item($item)
{
	$channel = $this->xpath->query('channel')->item(0); // first we'll retrieve the <channel> element
	$item_node = $this->dom->createElement('item'); // create our new element
	$channel->appendChild($item_node);              // ... and append it to <channel>

	// create the children elements our <item> element
	foreach($item as $name => $value)
	{
		if(empty($value)) continue; // no use for empty tags

		if(strcasecmp($name, 'pubDate') == 0) $name = 'pubDate'; // ensure proper name. not pubdate or something else

		$f = $this->dom->createElement($name);
		switch($name)
		{
			default:
				$text_node = $this->dom->createTextNode($value);
				break;
			case 'description':
				$text_node = $this->dom->createCDATASection($value);
				break;
		}

		$f->appendChild($text_node);
		$item_node->appendChild($f);
	}
}

public function __toString()
{
	return $this->parse();
}
}

header('Content-type: application/xml');

$rss = new RSSFeed('Test RSS Feed', 'http://localhost/rss_feed.php', 'Test RSS Feed generated using PHP DOM.');

$rss->add_item(array(
	'title'       => 'Test entry',
	'link'        => 'http://localhost/test.php?item=1',
	'description' => 'First test item <br /><strong>Testing</strong>',
	'pubDate'     => mktime(12,0,0,12,18,2007),
	'author'      => 'Daniel',
))->add_item(array(
	'title'       => 'Second test entry',
	'link'        => 'http://localhost/test.php?item=2',
	'description' => 'Second test item <br /><em>YAY </em>',
	'pubDate'     => mktime(11,38,22,10,17,2007),
	'author'      => 'Daniel',
))->add_item(array(
	'title'       => 'testing bla bla',
	'link'        => 'http://localhost/test.php?item=3',
	'description' => 'just testing again. <code><?php echo "hello world"; ?>',
	'pubDate'     => mktime(11,11,35,10,15,2007),
	'author'      => 'Daniel',
));

echo $rss->parse(true);
?></code>

<p>The reason why I chose to use the <tt>get_*()</tt> and <tt>set_*()</tt> methods inside the class even though the
properties are accessible as well is because if one later wanted to change how to retrieve or set the data only those
functions would have to be updated and not everything using them.</p>

<p><tt>RSSFeed::add_item()</tt> adds items to the RSS feed. It checks that the data is okay and throws some exceptions
if it isn't. It also converts a possible pubDate from a UNIX timestamp to a formatted date. It returns <tt>$this</tt> to
enable the usage of chaining—something which we've used quite a lot in this tutorial actually.</p>

<p>The switch in <tt>RSSFeed::parse_item()</tt> is there to make the contents of <content> CDATA. Any parser worth
using will not parse CDATA and therefore it is not neccessary to convert special characters to HTML entities.</p>

<p>Now we've generated an RSS feed without writing a single line of XML. It is guaranteed to be 100% well-formed
and it's easy to add a new item to the feed. In a real application you would get the items from some sort of database
and add them to the feed.</p>

[PAGEBREAK]

<h1>Conclusion</h1>

<p>Hopefully you've learned a lot about XML and PHP during this tutorial. We've covered the following things:</p>

<ul>
<li>SimpleXML</li>
<ul>
	<li>Parsing data of known structure</li>
	<li>Parsing data of unknown structure</li>
	<li>Using XPath with SimpleXML</li>
</ul>
<li>PHP DOM</li>
<ul>
	<li>Adding new data</li>
	<li>Changing existing data</li>
	<li>Deleting data</li>
	<li>Parsing XML documents</li>
	<li>Using XPath with PHP DOM</li>
</ul>
<li>How to create a simple RSS reader</li>
<li>How to create RSS feeds</li>
<li>How to tidy up your code</li>
</ul>

<p>If you have any suggestions feel free to comment here or PM <a href='http://www.phpfreaks.com/forums/index.php?action=profile;u=35570'>me at the forums</a>. I probably won't check if there are any comments here pretty often so if you want to ensure that I read it I would suggest you to send me a PM.</p>

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.