atom2rss.xsl 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!-- This file was taken from http://atom.geekhood.net and was modified a bit to handle Github feeds properly (search for "Github" in this file and see "utils/al-gnus.el" for the verbose explanation. -->
  3. <!-- Released under CC lincense http://creativecommons.org/licenses/by/2.5/ -->
  4. <!-- Feeds generated using this stylesheet (or it's derivatives) must put http://atom.geekhood.net in <generator> element -->
  5. <x:stylesheet version="1.0"
  6. exclude-result-prefixes="atom xhtml php"
  7. xmlns:php="http://php.net/xsl"
  8. xmlns:x="http://www.w3.org/1999/XSL/Transform"
  9. xmlns:atom="http://www.w3.org/2005/Atom"
  10. xmlns:dc="http://purl.org/dc/elements/1.1/"
  11. xmlns:xhtml="http://www.w3.org/1999/xhtml">
  12. <x:output encoding="utf-8" indent="yes" method="xml" media-type="application/rss+xml" />
  13. <x:template match="/atom:feed">
  14. <rss version="2.0">
  15. <channel>
  16. <x:if test="//@xml:lang">
  17. <language><x:value-of select="//@xml:lang[1]" /></language>
  18. </x:if>
  19. <description>
  20. <x:choose>
  21. <x:when test="atom:subtitle"><x:apply-templates select="atom:subtitle" mode="asHTML"/></x:when>
  22. <x:otherwise>
  23. <!-- this sucks -->
  24. <x:apply-templates select="atom:title" mode="asHTML"/> (converted from Atom 1.0)
  25. </x:otherwise>
  26. </x:choose>
  27. </description>
  28. <x:choose>
  29. <x:when test="atom:logo"><image><x:apply-templates select="atom:logo" mode="image"/></image></x:when>
  30. <x:when test="atom:icon"><image><x:apply-templates select="atom:icon" mode="image"/></image></x:when>
  31. </x:choose>
  32. <x:apply-templates />
  33. <generator><x:if test="atom:generator"><x:apply-templates select="atom:generator" mode="gen"/> + </x:if>Atom 1.0 XSLT+PHP Transform v1.1 (http://atom.geekhood.net)</generator>
  34. </channel>
  35. </rss>
  36. </x:template>
  37. <!-- simple losless conversions -->
  38. <x:template match="atom:contributor">
  39. <dc:contributor><x:call-template name="person" /></dc:contributor>
  40. </x:template>
  41. <x:template match="atom:title">
  42. <title><x:call-template name="asHTML" /></title>
  43. </x:template>
  44. <x:template match="atom:generator"/>
  45. <x:template match="atom:generator" mode="gen">
  46. <x:apply-templates mode="asText"/> <x:if test="@version"> v<x:value-of select="@version"/></x:if> <x:if test="@uri"> (<x:value-of select="@uri"/>)</x:if>
  47. </x:template>
  48. <x:template match="atom:published|atom:updated">
  49. <x:if test="local-name() = 'published' or not(../atom:published)">
  50. <pubDate>
  51. <x:choose>
  52. <x:when test="function-available('php:function')">
  53. <x:variable name="time" select="php:function('strtotime', string(.))"/>
  54. <x:value-of select="php:function('gmstrftime', '%a, %d %b %Y %T %Z', $time)"/>
  55. </x:when>
  56. <x:otherwise>
  57. <x:apply-templates/>
  58. </x:otherwise>
  59. </x:choose>
  60. </pubDate>
  61. </x:if>
  62. </x:template>
  63. <x:template match="atom:rights"><copyright><x:apply-templates /></copyright></x:template>
  64. <x:template match="atom:link[not(@rel) or @rel='alternate']">
  65. <x:if test="generate-id(.) = generate-id(../atom:link[not(@rel) or @rel='alternate'][1])">
  66. <link><x:value-of select="@href"/></link>
  67. </x:if>
  68. </x:template>
  69. <x:template match="atom:link[@rel='enclosure']">
  70. <x:if test="generate-id(.) = generate-id(../atom:link[@rel='enclosure'][1])">
  71. <enclosure url="{@href}" type="{@type}" length="{@length}"/>
  72. </x:if>
  73. </x:template>
  74. <x:template match="atom:entry/atom:id">
  75. <guid>
  76. <x:if test="not(. = ../atom:link[@rel='alternate']/@href) and not(. = ../atom:link[@rel='permalink']/@href) and not(. = ../atom:link[not(@rel)]/@href)">
  77. <x:attribute name="isPermaLink">false</x:attribute>
  78. </x:if>
  79. <x:apply-templates />
  80. </guid>
  81. </x:template>
  82. <!-- dodgy conversions -->
  83. <x:template match="atom:icon|atom:logo"/><!-- merged into rss:image -->
  84. <x:template match="atom:icon|atom:logo" mode="image">
  85. <url><x:value-of select="."/></url>
  86. <x:if test="../atom:title"><title><x:apply-templates select="../atom:title" mode="asText" /></title></x:if>
  87. <x:if test="../atom:link[not(@rel) or @rel='alternate']"><link><x:value-of select="../atom:link[not(@rel) or @rel='alternate'][1]/@href"/></link></x:if>
  88. </x:template>
  89. <x:template name="person">
  90. <x:choose>
  91. <x:when test="atom:email"><x:value-of select="atom:email"/></x:when>
  92. <x:when test="/atom:feed/atom:author[./atom:email][1]/atom:email"><x:value-of select="/atom:feed/atom:author[./atom:email][1]/atom:email"/></x:when>
  93. </x:choose>
  94. (<x:value-of select="atom:name"/><x:if test="@uri"> <x:value-of select="uri"/></x:if>)
  95. </x:template>
  96. <x:template match="atom:author[not(starts-with(./atom:email,'webmaster@'))][1]">
  97. <x:if test="atom:email">
  98. <managingEditor>
  99. <x:call-template name="person" />
  100. </managingEditor>
  101. </x:if>
  102. </x:template>
  103. <x:template match="atom:author[starts-with(./atom:email,'webmaster@')][1]">
  104. <webMaster>
  105. <x:call-template name="person" />
  106. </webMaster>
  107. </x:template>
  108. <x:template match="atom:subtitle"/>
  109. <x:template match="atom:source">
  110. <source url="{atom:link[@rel='self']}"><x:apply-templates select="atom:title" mode="asText"/></source>
  111. </x:template>
  112. <!-- lossy conversion -->
  113. <x:template match="atom:feed/atom:id"/>
  114. <!-- Commented because self link to private feed on Github may contain double dash which is not allowed in comments -->
  115. <!-- <x:template match="atom:feed/atom:link[@rel='self']"><x:comment> source: <x:value-of select="@href"/><x:text> </x:text></x:comment> </x:template> -->
  116. <x:template match="atom:category"><!-- label gets lost -->
  117. <category>
  118. <x:if test="@scheme">
  119. <x:attribute name="domain"><x:value-of select="@scheme"/></x:attribute>
  120. </x:if>
  121. <x:value-of select="@term"/>
  122. <x:if test="@label and not(@label = @term)"><x:comment><x:value-of select="@label"/></x:comment></x:if>
  123. </category>
  124. </x:template>
  125. <!-- entry -->
  126. <x:template match="atom:summary|atom:content"/>
  127. <x:template match="atom:entry">
  128. <item>
  129. <x:choose>
  130. <x:when test="atom:summary"><description><x:apply-templates select="atom:summary" mode="asHTML"/> <x:if test="atom:content"> (...)</x:if></description></x:when>
  131. <x:when test="atom:content"><description><x:apply-templates select="atom:content" mode="asHTML"/></description></x:when>
  132. </x:choose>
  133. <x:apply-templates/>
  134. <x:if test="not(atom:source) and /atom:feed/atom:link[@rel='self']">
  135. <source url="{/atom:feed/atom:link[@rel='self']/@href}">
  136. <x:choose>
  137. <x:when test="/atom:feed/atom:link[@rel='self' and @title]"><x:value-of select="/atom:feed/atom:link[@rel='self']/@title"/></x:when>
  138. <x:otherwise><x:apply-templates select="/atom:feed/atom:title" mode="asText"/></x:otherwise>
  139. </x:choose>
  140. </source>
  141. </x:if>
  142. <x:apply-templates select="atom:source/atom:category"/>
  143. <x:if test="not(atom:copyright)"><x:apply-templates select="atom:source/atom:copyright"/></x:if>
  144. <x:if test="not(atom:author)"><x:apply-templates select="atom:source/atom:author"/></x:if>
  145. <x:if test="not(atom:contributor)"><x:apply-templates select="atom:source/atom:contributor"/></x:if>
  146. <x:if test="not(atom:updated)"><x:apply-templates select="atom:source/atom:updated"/></x:if>
  147. </item>
  148. </x:template>
  149. <!-- santas little helpers -->
  150. <x:template match="*" mode="asHTML"><x:call-template name="asHTML"/></x:template>
  151. <x:template name="asHTML">
  152. <x:choose>
  153. <x:when test="@type='xhtml'">
  154. <x:apply-templates select="xhtml:div" mode="xhtml2html" />
  155. </x:when>
  156. <x:when test="@type='html'"><x:value-of select="." /></x:when>
  157. <x:otherwise>
  158. <x:value-of select="."/>
  159. </x:otherwise>
  160. </x:choose>
  161. </x:template>
  162. <x:template match="*[@type='html' or @type='text/html']" mode="asText">
  163. <x:call-template name="removeHtml"><x:with-param name="text" select="."/></x:call-template>
  164. </x:template>
  165. <x:template match="*" mode="asText">
  166. <x:value-of select="."/>
  167. </x:template>
  168. <!-- html 2 text (primitive method) -->
  169. <x:template name="removeHtml">
  170. <x:param name="text"/>
  171. <x:choose>
  172. <x:when test="contains($text, '&lt;') and contains(substring-after($text, '&lt;'),'&gt;')">
  173. <x:value-of select="substring-before($text, '&lt;')"/>
  174. <x:call-template name="removeHtml">
  175. <x:with-param name="text" select="substring-after(substring-after($text,'&lt;'),'&gt;')"/>
  176. </x:call-template>
  177. </x:when>
  178. <x:otherwise>
  179. <x:value-of select="$text"/>
  180. </x:otherwise>
  181. </x:choose>
  182. </x:template>
  183. <!-- xhtml 2 html -->
  184. <x:template match="xhtml:img|xhtml:br|xhtml:hr|xhtml:input|xhtml:col|xhtml:area|xhtml:input|xhtml:link|xhtml:meta|xhtml:param" mode="xhtml2html">
  185. &lt;<x:value-of select="local-name(.)"/><x:apply-templates select="@*" mode="xhtml2html"/>&gt;<x:apply-templates mode="xhtml2html"/>
  186. </x:template>
  187. <x:template match='xhtml:*' mode="xhtml2html">
  188. &lt;<x:value-of select="local-name(.)"/><x:apply-templates select="@*" mode="xhtml2html"/>&gt;<x:apply-templates mode="xhtml2html"/>&lt;/<x:value-of select="local-name(.)"/>&gt;
  189. </x:template>
  190. <x:template match='@*' mode="xhtml2html">
  191. <x:text> </x:text><x:value-of select="local-name(.)"/>="<x:value-of select="."/>"</x:template>
  192. <x:template match="comment()" mode="xhtml2html">
  193. <x:text disable-output-escaping="yes">&lt;![CDATA[</x:text>
  194. <x:comment><x:value-of select="."/></x:comment>
  195. <x:text disable-output-escaping="yes">]]&gt;</x:text>
  196. </x:template>
  197. <x:template match="text()" mode="xhtml2html">
  198. <x:choose>
  199. <x:when test="contains(.,'&amp;') or contains(.,'&lt;')">
  200. <x:text disable-output-escaping="yes">&lt;![CDATA[</x:text>
  201. <x:value-of select="." />
  202. <x:text disable-output-escaping="yes">]]&gt;</x:text>
  203. </x:when>
  204. <x:otherwise>
  205. <x:value-of select="."/>
  206. </x:otherwise>
  207. </x:choose>
  208. </x:template>
  209. <!-- copy extensions -->
  210. <x:template match='*'>
  211. <x:comment>Unknown element <x:value-of select="local-name(.)"/></x:comment>
  212. <x:copy>
  213. <x:copy-of select='node()|@*'/>
  214. </x:copy>
  215. </x:template>
  216. </x:stylesheet>