<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>output stream &#187; PHP</title>
	<atom:link href="http://duncanandmeg.org/blogs/code/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://duncanandmeg.org/blogs/code</link>
	<description>riotous events in amateur development</description>
	<lastBuildDate>Fri, 18 Feb 2011 21:28:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Rendering XML as valid RSS with XSLT</title>
		<link>http://duncanandmeg.org/blogs/code/2007/08/13/rendering-xml-as-valid-rss-with-xslt/</link>
		<comments>http://duncanandmeg.org/blogs/code/2007/08/13/rendering-xml-as-valid-rss-with-xslt/#comments</comments>
		<pubDate>Mon, 13 Aug 2007 21:30:02 +0000</pubDate>
		<dc:creator>dtjohnso</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[XML & XSL]]></category>

		<guid isPermaLink="false">http://duncanandmeg.org/blogs/code/2007/08/13/rendering-xml-as-valid-rss-with-xslt/</guid>
		<description><![CDATA[I&#8217;ve been using a simple XML file to store updates to the main duncanandmeg.org website, and wanted to use XSL to transform that data into a valid RSS feed. This took a little more work than most of my XSL templates to date, so I thought I&#8217;d log the details here. XML data The following [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using a simple XML file to store updates to the <a href="/" class="liinternal">main duncanandmeg.org website</a>, and wanted to use XSL to transform that data into a <a href="http://www.feedvalidator.org/" class="liexternal">valid RSS feed</a>. This took a little more work than most of my XSL templates to date, so I thought I&#8217;d log the details here.<span id="more-5"></span></p>
<h3>XML data</h3>
<p>The following is the structure of my XML file. I&#8217;ve been storing dates in the file in short date format. The detail element is optional, and since is the only element where I embed raw HTML, I encapsulate the contents in CDATA elements.<br />
Also, since I&#8217;m updating this file manually at this point, I add new entries to the top of the file rather than worry about using more automated date sorting.</p>
<pre><code class=\'prettyprint\'  class="prettyprint">&amp;lt;news&amp;gt;
  &amp;lt;entry&amp;gt;
    &amp;lt;headline&amp;gt;headline&amp;lt;/headline&amp;gt;
     &amp;lt;date&amp;gt;mm/dd/yy&amp;lt;/date&amp;gt;
    &amp;lt;detail&amp;gt;&amp;lt;![CDATA[more details (if applicable)]]&amp;gt;&amp;lt;/detail&amp;gt;
  &amp;lt;/entry&amp;gt;
&amp;lt;/news&amp;gt;</code></pre>
<h3>XSL transform</h3>
<p>Because RSS is a more complex standard than my simple XML file, the XSL transform is necessarily complex.</p>
<pre><code class=\'prettyprint\'  class="prettyprint">&amp;lt;xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&amp;gt;

  &amp;lt;xsl:output method="xml"/&amp;gt;

  &amp;lt;xsl:template match="/news"&amp;gt;
  &amp;lt;rss version="2.0"&amp;gt;
    &amp;lt;channel&amp;gt;
      &amp;lt;title&amp;gt;hard-coded title&amp;lt;/title&amp;gt;
      &amp;lt;link&amp;gt;hard-coded url&amp;lt;/link&amp;gt;
      &amp;lt;description&amp;gt;hard-coded description&amp;lt;/description&amp;gt;
      &amp;lt;ttl&amp;gt;60&amp;lt;/ttl&amp;gt;
      &amp;lt;xsl:apply-templates select="entry[position() &amp;lt; 6]" /&amp;gt;
    &amp;lt;/channel&amp;gt;
  &amp;lt;/rss&amp;gt;
  &amp;lt;/xsl:template&amp;gt;

  &amp;lt;xsl:template match="entry"&amp;gt;
    &amp;lt;item&amp;gt;
      &amp;lt;title&amp;gt;&amp;lt;xsl:value-of select="headline" /&amp;gt;&amp;lt;/title&amp;gt;
      &amp;lt;link&amp;gt;&amp;lt;xsl:text&amp;gt;http://www.duncanandmeg.org/news.php#&amp;lt;/xsl:text&amp;gt;
        &amp;lt;xsl:value-of select="position()" /&amp;gt;&amp;lt;/link&amp;gt;
      &amp;lt;guid&amp;gt;&amp;lt;xsl:text&amp;gt;http://www.duncanandmeg.org/news.php#&amp;lt;/xsl:text&amp;gt;
        &amp;lt;xsl:value-of select="position()" /&amp;gt;&amp;lt;/guid&amp;gt;
      &amp;lt;pubDate&amp;gt;&amp;lt;xsl:value-of select="date" /&amp;gt;&amp;lt;/pubDate&amp;gt;
      &amp;lt;description&amp;gt;
        &amp;lt;xsl:if test="detail"&amp;gt;
          &amp;lt;xsl:value-of disable-output-escaping="no" select="detail" /&amp;gt;
        &amp;lt;/xsl:if&amp;gt;
      &amp;lt;/description&amp;gt;
    &amp;lt;/item&amp;gt;
   &amp;lt;/xsl:template&amp;gt;

&amp;lt;/xsl:stylesheet&amp;gt;</code></pre>
<p>This produces <b>almost</b> valid RSS feed for the top 5 items in the feed.</p>
<p>The generated RSS includes dates in short date format (mm/dd/yy), which violates the RSS standard which calls for the <a href="http://feedvalidator.org/docs/error/InvalidRFC2822Date.html" class="liexternal">RFC-822 date-time format</a>. Since all the implementations I could find on the web for doing date conversions in XSL were far too complex for my taste, I proceeded to do that with PHP when I actually transform the XML file into RSS.</p>
<h3>PHP code</h3>
<p>The following PHP represents a minimalist approach to executing the XSL transform and returning RSS as output. This script doesn&#8217;t handle caching, and there are issues with the &lt;link&gt; and &lt;guid&gt; elements in the template for each &lt;entry&gt;.</p>
<p>The consequence of these weaknesses is that some feed readers don&#8217;t properly update when a new post is added to the news.xml file. This is something I&#8217;ll perhaps address in another post.</p>
<pre><code class=\'prettyprint\'  class="prettyprint">&amp;lt;?php
  //Optional. Sets default time zone to something other than GMT
  date_default_timezone_set('EST');

  //Load XML data and transform to RSS
  $xslt = new xsltprocessor;
  $xslt-&gt;importStyleSheet(DomDocument::load('rss.xsl'));
  $xmlResult = $xslt-&gt;transformToXML(DomDocument::load('news.xml'));

  //Load resulting data into the SimpleXML processor
  $xml=simplexml_load_string($xmlResult);

  //Loop through RSS data in SimpleXML
  //Replace each short date with an RFC-822 date-time
  $count = 0;
  foreach($xml-&gt;xpath('//pubDate') as $dates){
    $newDates = date(DATE_RFC822, strtotime($dates));
    $xml-&gt;channel-&gt;item[$count]-&gt;pubDate = $newDates;
    $count++;
  }

  //Optional. These lines insert RFC-822 values
  //for channel/lastBuildDate and channel/pubDate
  $xml-&gt;channel-&gt;addChild("lastBuildDate",$xml-&gt;channel-&gt;item[0]-&gt;pubDate);
  $xml-&gt;channel-&gt;addChild("pubDate",$xml-&gt;channel-&gt;item[0]-&gt;pubDate);

  //Set output content-type to XML
  header('Content-type: application/rss+xml; charset=utf-8');
  print $xml-&gt;asXML(); //Return as XML
?&amp;gt;</code></pre>
<p><!--header('Cache-Control: no-cache');<br />
      header('Pragma: no-cache');--></p>
]]></content:encoded>
			<wfw:commentRss>http://duncanandmeg.org/blogs/code/2007/08/13/rendering-xml-as-valid-rss-with-xslt/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

