updating opensearch output to contain proper unAPI stuff
[Evergreen.git] / Open-ILS / xsl / ATOM2XHTML.xsl
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!--
3
4 !! Information About This File: http://opensearch.a9.com/docs/stylesheet.jsp
5
6 Copyright (c) 2005-2006 A9.com, Inc. or its affiliates.
7
8 Author: Michael Fagan, parts by Joel Tesler
9 Changelog:
10         2005-11-28: Updated to work with OpenSearch 1.1 Draft 2 (rather than Draft 1)
11         2005-10-19: Changlog added (unknown update)
12 Description: Converts an OpenSearch feed into XHTML.
13         Can handle
14                 OpenSearch 1.0 and 1.1 Draft 2
15                 RSS 0.9, 0.91, 0.92, 0.93, 1.0, 2.0 and Atom 1.0
16                 (suggested searches using OpenSearch 1.1 Query is not yet handled)
17         Also handles lack of data and errors very well and flexibly. (This is not a strict parser; invalid responses may appear okay)
18         This file should be bunled with a CSS and a Javascript file, the latter is necessary to handle XSLT parsers (e.g. Mozilla-based) that do not support disable-output-escaping
19 Note:
20         Javascript and other potentially malicious code is *not* dealt with
21 To-do list:
22         don't separate authors or categories with a ';' if there's only one of them
23         webMaster (rss) not used due to duplication with managingEditor... really should be able to detect dupes...
24         use dc:source
25         use rating (rss)
26         for link to html version (ideal) for atom make sure alternate link is (x)html (one of list of mime types?)
27         handle common rss/atom extensions (*dc*, geo, vcard, foaf, doap, pheed, media rss, itunes, slash, licenses, etc)
28 -->
29 <xsl:stylesheet version="1.0"
30  xmlns="http://www.w3.org/1999/xhtml"
31  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
32  xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"
33  xmlns:opensearchOld="http://a9.com/-/spec/opensearchrss/1.0/"
34  xmlns:atom="http://www.w3.org/2005/Atom"
35  xmlns:rss9="http://my.netscape.com/rdf/simple/0.9/"
36  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
37  xmlns:rss1="http://purl.org/rss/1.0/"
38  xmlns:content="http://purl.org/rss/1.0/modules/content/"
39  xmlns:dc="http://purl.org/dc/elements/1.1/"
40  xmlns:xhtml="http://www.w3.org/1999/xhtml"
41  exclude-result-prefixes="xsl opensearch opensearchOld atom rss9 rdf rss1 content dc xhtml"
42  >
43         <xsl:output omit-xml-declaration="yes" method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" encoding="UTF-8" media-type="application/xhtml+xml" />
44         
45         <!-- START SETTINGS -->
46         <!-- text used; change this for translation and also some settings -->
47         <xsl:variable name="t-lang">en-US</xsl:variable> <!-- the ISO 639 code the the language that the text (the texts below) are in -->
48         <!-- next 2 vars are the title and description of error no rss/atom feed found -->
49         <xsl:variable name="t-errortitle">Can't Display Search Results</xsl:variable>
50         <xsl:variable name="t-errordesc">Sorry, there was a problem displaying search results. No valid response was found. Try contacting the owner of this website for assistance.</xsl:variable>
51         <!-- next 4 vars used in <link> tags in the <head> -->
52         <xsl:variable name="t-prevpage">previous page of search results</xsl:variable>
53         <xsl:variable name="t-nextpage">next page of search results</xsl:variable>
54         <xsl:variable name="t-firstpage">first page of search results</xsl:variable>
55         <xsl:variable name="t-lastpage">last page of search results</xsl:variable>
56         <!-- next 3 vars example: "Results 1 to 10 of 35" -->
57         <xsl:variable name="t-results">Results</xsl:variable>
58         <xsl:variable name="t-resultsto">to</xsl:variable>
59         <xsl:variable name="t-resultsof">of</xsl:variable>
60         <xsl:variable name="t-resultstitle">Search Results</xsl:variable> <!-- used in case of absent title -->
61         <xsl:variable name="t-resultsfor">Search Results for</xsl:variable> <!-- used in case of absent title but query is known -->
62         <!-- next 2 vars are text links to previous and next result pages; entitles should be double-escaped as shown -->
63         <xsl:variable name="t-prevlink">&amp;#171; previous</xsl:variable>
64         <xsl:variable name="t-nextlink">next &amp;#187;</xsl:variable>
65         <xsl:variable name="t-nomoreresults">No further results.</xsl:variable> <!-- shown when the page is beyond the last page of results -->
66         <xsl:variable name="t-noresults">Sorry, no results were found.</xsl:variable>
67         <xsl:variable name="t-untitleditem">(untitled)</xsl:variable> <!-- text of untitled items when the title needs to be shown) -->
68         <xsl:variable name="t-entrylink">view full entry</xsl:variable> <!-- text of the link to the full entry (used with <content src="" /> in atom) -->
69         <xsl:variable name="t-authors">by</xsl:variable> <!-- label before one or more author/contributors (eg the 'by' in 'by Joe'); leave blank to not show authors -->
70         <xsl:variable name="t-categories">categories:</xsl:variable> <!-- label before one or more categories; leave blank to not show categories -->
71         <xsl:variable name="t-source">from</xsl:variable> <!-- label of source (e.g. 'from' or 'via' in English); leave blank to not show sources -->
72         <xsl:variable name="t-comments">comments</xsl:variable> <!-- leave blank to not show link to comments -->
73         <xsl:variable name="t-download">download</xsl:variable> <!-- leave this or t-enclosure blank to not show link to enclosures -->
74         <xsl:variable name="t-enclosure">enclosure</xsl:variable> <!-- text of untitled enclosures; leave this or t-download blank to not show link to enclosures -->
75         <xsl:variable name="t-numsep"><xsl:text>,</xsl:text></xsl:variable> <!-- text to separate number of over 3 digits (eg ',' or ' '); leave blank for no separator-->
76         <!-- END SETTINGS -->
77         
78         <xsl:template match="/">
79                 <xsl:comment>For information about the XSLT file that generated this, see http://opensearch.a9.com/docs/stylesheet.jsp</xsl:comment>
80                 <xsl:choose>
81                         <xsl:when test="not(atom:feed | rss/channel | //rss1:item | //rss9:item)">
82                                 <html xml:lang="{$t-lang}" lang="{$t-lang}">
83                                         <head>
84                                                 <title><xsl:value-of select="$t-errortitle" /></title>
85                                                 <meta name="robots" content="noindex,nofollow,noarchive" />
86                                         </head>
87                                         <body><p><xsl:value-of select="$t-errordesc" /></p></body>
88                                 </html>
89                         </xsl:when>
90                         <xsl:otherwise><xsl:apply-templates /></xsl:otherwise>
91                 </xsl:choose>
92         </xsl:template>
93
94         <xsl:template match="atom:feed | rss/channel | rdf:RDF">
95                 <xsl:variable name="language" select="(@xml:lang | language)[1]" />
96                 <html xml:lang="{$language}" lang="{$language}">
97                         <xsl:variable name="query" select="opensearch:Query[@role='request' and @searchTerms][1]/@searchTerms" />
98                         <xsl:variable name="statedtitle" select="(atom:title | title | //rss1:channel/rss1:title | //rss9:channel/rss9:title)[1]" />
99                         <xsl:variable name="title">
100                                 <xsl:choose>
101                                         <xsl:when test="string-length($statedtitle)&gt;0 and (not(string-length($query)&gt;0) or contains($statedtitle, $query))"><xsl:value-of select="$statedtitle" /></xsl:when>
102                                         <xsl:when test="string-length($statedtitle)&gt;0 and string-length($query)&gt;0"><xsl:value-of select="$statedtitle" /> (<xsl:value-of select="$query" />)</xsl:when>
103                                         <xsl:when test="string-length($query)&gt;0"><xsl:value-of select="$t-resultsfor" /> '<xsl:value-of select="$query" />'</xsl:when>
104                                         <xsl:otherwise><xsl:value-of select="$t-resultstitle" /></xsl:otherwise>
105                                 </xsl:choose>
106                         </xsl:variable>
107                         <!-- search stats and rel links -->
108                         <xsl:variable name="items" select="atom:entry | item | //rss1:item | //rss9:item" />
109                         <xsl:variable name="endIndex">
110                                 <xsl:choose>
111                                         <xsl:when test="opensearch:startIndex | opensearchOld:startIndex"><xsl:value-of select="(opensearch:startIndex | opensearchOld:startIndex)[1] + count($items) - 1" /></xsl:when>
112                                         <xsl:otherwise><xsl:value-of select="count($items)" /></xsl:otherwise>
113                                 </xsl:choose>
114                         </xsl:variable>
115                         <xsl:variable name="totalresults"><xsl:if test="(opensearch:totalResults | opensearchOld:totalResults)&gt;=$endIndex"><xsl:value-of select="(opensearch:totalResults | opensearchOld:totalResults)[1]" /></xsl:if></xsl:variable>
116                         <xsl:variable name="navprev"><xsl:if test="atom:link[@rel='previous']/@href and ((opensearch:startIndex&gt;1 or opensearchOld:startIndex&gt;1) or not(opensearch:startIndex or opensearchOld:startIndex))"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="(atom:link[@rel='previous']/@href)[1]" /></xsl:call-template></xsl:if></xsl:variable>
117                         <xsl:variable name="navnext"><xsl:if test="atom:link[@rel='next']/@href and (($totalresults&gt;0 and $totalresults&gt;$endIndex) or (not($totalresults&gt;0)))"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="atom:link[@rel='next']/@href" /></xsl:call-template></xsl:if></xsl:variable>
118
119                         <xsl:variable name="statedStartIndex" select="(opensearch:startIndex | opensearchOld:startIndex)[1]" />
120                         <head>
121                                 <title><xsl:value-of select="$title" /></title>
122                                 <meta name="robots" content="noindex,follow,noarchive" />
123                                 <xsl:if test="atom:icon">
124                                         <xsl:variable name="iconurl"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="atom:icon[1]" /></xsl:call-template></xsl:variable>
125                                         <link rel="shortcut icon" href="{$iconurl}" />
126                                 </xsl:if>
127                                 <link rel="stylesheet" type="text/css" title="default" media="screen">
128                                         <xsl:attribute name="href"><xsl:value-of select="concat($base_dir,'/os.css')"/></xsl:attribute>
129                                 </link>
130                                 <!-- rel links -->
131
132                                 <xsl:for-each select="atom:link[@rel='unapi' and string-length(@href)&gt;0]">
133                                         <link rel="meta" title="unAPI" type="application/xml">
134                                                 <xsl:attribute name='href'>
135                                                         <xsl:value-of select="./@href"/>
136                                                 </xsl:attribute>
137                                         </link>
138                                 </xsl:for-each>
139
140                                 <xsl:if test="string-length($navprev)&gt;0"><link rel="previous" href="{$navprev}" title="{$t-prevpage}" /></xsl:if>
141                                 <xsl:if test="string-length($navnext)&gt;0"><link rel="next" href="{$navnext}" title="{$t-nextpage}" /></xsl:if>
142                                 <xsl:if test="atom:link[@rel='first']/@href and ($statedStartIndex&gt;1 or string-length($statedStartIndex)=0)">
143                                         <xsl:variable name="starturl"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="(atom:link[@rel='first']/@href)[1]" /></xsl:call-template></xsl:variable>
144                                         <link rel="start" title="{$t-firstpage}" href="{$starturl}" />
145                                 </xsl:if>
146                                 <xsl:if test="atom:link[@rel='last']/@href and ($totalresults&gt;$endIndex or string-length($totalresults)=0)">
147                                         <xsl:variable name="endurl"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="(atom:link[@rel='last']/@href)[1]" /></xsl:call-template></xsl:variable>
148                                         <link rel="last" title="{$t-lastpage}" href="{$endurl}"/>
149                                 </xsl:if>
150                                 <xsl:for-each select="atom:link[(@rel='alternate' or @rel='self' or @rel='description') and @href]">
151                                         <xsl:variable name="linkurl"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="@href" /></xsl:call-template></xsl:variable>
152                                         <link rel="{@rel}" href="{$linkurl}" hreflang="{@hreflang}" title="{@title}" />
153                                 </xsl:for-each>
154                         </head>
155                         <body>
156
157                                 <!-- title section -->
158                                 <div id="header">
159
160
161                                         <xsl:variable name="htmllink" select="(atom:link[@rel='alternate' or not(@rel)]/@href | link | rss1:link)[1]" />
162                                         <h1>
163                                                 <xsl:choose>
164                                                         <xsl:when test="$htmllink">
165                                                                 <xsl:variable name="htmlversion"><xsl:if test="$htmllink"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="$htmllink" /></xsl:call-template></xsl:if></xsl:variable>
166                                                                 <a href="{$htmlversion}"><xsl:value-of select="$title" /></a>
167                                                         </xsl:when>
168                                                         <xsl:otherwise><xsl:value-of select="$title" /></xsl:otherwise>
169                                                 </xsl:choose>
170                                         </h1>
171                                         <xsl:variable name="imgurl" select="(atom:logo | image/url | rss1:image/rss1:url | rss9:image/rss9:url)[1]" />
172                                         <xsl:variable name="absimgurl"><xsl:if test="$imgurl"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="$imgurl" /></xsl:call-template></xsl:if></xsl:variable>
173                                         <xsl:if test="$absimgurl"><img src="{$absimgurl}" width="{image/width}" height="{image/height}" alt="{image/title}" /></xsl:if>
174                                         <xsl:variable name="subtitle" select="(atom:subtitle | description | //rss1:channel/rss1:description | //rss9:channel/rss9:description)[1]" />
175                                         <xsl:if test="$subtitle and ($subtitle != $title)"><p><xsl:value-of select="$subtitle" /></p></xsl:if>
176                                         <xsl:if test="$t-authors and (managingEditor | atom:author | dc:creator | dc:publisher | atom:contributor | dc:contributor)"><p><xsl:value-of select="concat($t-authors,' ')" /><xsl:apply-templates select="managingEditor | atom:author | dc:creator | dc:publisher | atom:contributor | dc:contributor" /></p></xsl:if>
177                                         <xsl:if test="$t-categories and (atom:category | category)"><xsl:value-of select="concat($t-categories, ' ')" /><p><xsl:apply-templates select="atom:category | category" /></p></xsl:if>
178                                 </div>
179                                 
180                                 <!-- text input: if present in an opensearch feed, this is probably a search box -->
181                                 <xsl:if test="textInput | rss1:textinput"><xsl:apply-templates select="(textInput | rss1:textinput)[1]"><xsl:with-param name="query" select="$query" /></xsl:apply-templates></xsl:if>
182
183                                 <!-- output search results or 'no results' msg -->
184                                 <xsl:choose>
185                                         <xsl:when test="$items">
186                                                 <!-- display the search numbers -->
187                                                 <p class="nav">
188                                                         <xsl:value-of select="concat($t-results,' ')" />
189                                                         <xsl:choose>
190                                                                 <xsl:when test="$statedStartIndex&gt;0"><xsl:value-of select="$statedStartIndex" /></xsl:when>
191                                                                 <xsl:otherwise>1</xsl:otherwise>
192                                                         </xsl:choose>
193                                                         <xsl:value-of select="concat(' ', $t-resultsto, ' ')" />
194                                                         <xsl:value-of select="$endIndex" />
195                                                         <xsl:if test="$totalresults&gt;0"><xsl:value-of select="concat(' ', $t-resultsof, ' ')" /><xsl:number value="$totalresults" grouping-size="3" grouping-separator="{$t-numsep}" /></xsl:if>
196                                                         <xsl:if test="string-length($navnext)&gt;0 or string-length($navprev)&gt;0">   |   </xsl:if>
197                                                         <xsl:if test="string-length($navprev)&gt;0">
198                                                                 <a class="x-escape" href="{$navprev}" rel="previous"><xsl:value-of select="$t-prevlink" disable-output-escaping="yes" /></a>
199                                                                 <xsl:if test="string-length($navnext)&gt;0"> | </xsl:if>
200                                                         </xsl:if>
201                                                         <xsl:if test="string-length($navnext)&gt;0"><a class="x-escape" href="{$navnext}" rel="next"><xsl:value-of select="$t-nextlink" disable-output-escaping="yes" /></a></xsl:if>
202                                                 </p>
203                                                 <dl><xsl:apply-templates select="$items" /></dl>
204                                                 <!-- result navigation -->
205                                                 <p class="nav">
206                                                         <xsl:value-of select="concat($t-results,' ')" />
207                                                         <xsl:choose>
208                                                                 <xsl:when test="$statedStartIndex&gt;0"><xsl:value-of select="$statedStartIndex" /></xsl:when>
209                                                                 <xsl:otherwise>1</xsl:otherwise>
210                                                         </xsl:choose>
211                                                         <xsl:value-of select="concat(' ', $t-resultsto, ' ')" />
212                                                         <xsl:value-of select="$endIndex" />
213                                                         <xsl:if test="$totalresults&gt;0"><xsl:value-of select="concat(' ', $t-resultsof, ' ')" /><xsl:number value="$totalresults" grouping-size="3" grouping-separator="{$t-numsep}" /></xsl:if>
214                                                         <xsl:if test="string-length($navnext)&gt;0 or string-length($navprev)&gt;0">   |   </xsl:if>
215                                                         <xsl:if test="string-length($navprev)&gt;0">
216                                                                 <a class="x-escape" href="{$navprev}" rel="previous"><xsl:value-of select="$t-prevlink" disable-output-escaping="yes" /></a>
217                                                                 <xsl:if test="string-length($navnext)&gt;0"> | </xsl:if>
218                                                         </xsl:if>
219                                                         <xsl:if test="string-length($navnext)&gt;0"><a class="x-escape" href="{$navnext}" rel="next"><xsl:value-of select="$t-nextlink" disable-output-escaping="yes" /></a></xsl:if>
220                                                 </p>
221                                         </xsl:when>
222                                         <xsl:when test="(opensearch:startIndex&gt;1 or opensearchOld&gt;1) and not($totalresults=0)"><xsl:value-of select="$t-nomoreresults" /></xsl:when>
223                                         <xsl:otherwise><p><xsl:value-of select="$t-noresults" /></p></xsl:otherwise>
224                                 </xsl:choose>
225
226                                 <!-- display the copyright -->
227                                 <xsl:variable name="rights" select="(atom:rights[not(@type) or @type='' or @type='text' or @type='html' or @type='xhtml'] | copyright | dc:rights)[1]" />
228                                 <div id="footer">
229                                         <xsl:if test="$rights"><p><xsl:call-template name="showtext"><xsl:with-param name="node" select="$rights" /></xsl:call-template></p></xsl:if>
230                                         <p><small>This XSLT is &#169; <a href="http://a9.com/">A9.com, Inc</a>; see <a href="http://opensearch.a9.com/docs/stylesheet.jsp">full details</a>.</small></p>
231                                 </div>
232
233                         </body>
234                 </html>
235         </xsl:template>
236         
237         <xsl:template match="textInput | rss1:textinput">
238                 <xsl:param name="query" />
239                 <xsl:if test="(name | rss1:name) and (link | rss1:link)">
240                         <xsl:variable name="formaction"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="(link | rss1:link)[1]" /></xsl:call-template></xsl:variable>
241                         <form method="get" action="{$formaction}">
242                                 <input type="text" name="{name | rss1:name}" value="{$query}" />
243                                 <xsl:choose>
244                                         <xsl:when test="title | rss1:title"><input type="submit" value="{title | rss1:title}" /></xsl:when>
245                                         <xsl:otherwise><input type="submit" /></xsl:otherwise>
246                                 </xsl:choose>
247                                 <xsl:if test="description | rss1:description"><p><xsl:value-of select="(description | rss1:description)[1]" /></p></xsl:if>
248                         </form>
249                 </xsl:if>
250         </xsl:template>
251
252         <xsl:template match="atom:entry | item | //rss1:item | //rss9:item"> <!-- match="" must match the select="" earlier on -->
253                 <xsl:variable name="url"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="(atom:link[not(@rel) or @rel='alternate' or @rel='']/@href | link | guid[@isPermaLink='true'] | rss1:link | rss9:link)[1]" /></xsl:call-template></xsl:variable>
254                 <!-- item title -->
255                 <dt>
256                         <xsl:choose>
257                                 <xsl:when test="string-length($url)&gt;0">
258                                         <a href="{$url}">
259                                                 <xsl:choose>
260                                                         <xsl:when test="atom:title | title | rss1:title | rss9:title"><xsl:call-template name="showtext"><xsl:with-param name="node" select="(atom:title | title | rss1:title | rss9:title)[1]" /></xsl:call-template></xsl:when>
261                                                         <xsl:otherwise><xsl:value-of select="$t-untitleditem" /></xsl:otherwise>
262                                                 </xsl:choose>
263                                         </a>
264                                 </xsl:when>
265                                 <xsl:otherwise>
266                                         <strong>
267                                                 <xsl:choose>
268                                                         <xsl:when test="atom:title | title | rss1:title | rss9:title"><xsl:call-template name="showtext"><xsl:with-param name="node" select="(atom:title | title | rss1:title | rss9:title)[1]" /></xsl:call-template></xsl:when>
269                                                         <xsl:otherwise><xsl:value-of select="$t-untitleditem" /></xsl:otherwise>
270                                                 </xsl:choose>
271                                         </strong>
272                                 </xsl:otherwise>
273                         </xsl:choose>
274                         <!-- item authors -->
275                         <xsl:if test="$t-authors and (author | atom:author | atom:contributor | dc:creator | dc:publisher | dc:contributor)">
276                                 <xsl:value-of select="concat(' ', $t-authors, ' ')" />
277                                 <xsl:apply-templates select="author | atom:author | atom:contributor | dc:creator | dc:publisher | dc:contributor" />
278                         </xsl:if>
279                 </dt>
280                 <!-- item description -->
281                 <xsl:if test="atom:content[not(@type) or @type='' or @type='text' or @type='html' or @type='xhtml'] | content:encoded | description | rss1:description | rss9:description | atom:summary[not(@type) or @type='' or @type='text' or @type='html' or @type='xhtml']">
282                         <dd class="desc">
283                                 <xsl:choose>
284                                         <xsl:when test="atom:content[(not(@type) or @type='' or @type='text' or @type='html' or @type='xhtml') and not(@src)] | content:encoded"><xsl:call-template name="showtext"><xsl:with-param name="node" select="atom:content[(not(@type) or @type='' or @type='text' or @type='html' or @type='xhtml') and not(@src)] | content:encoded" /></xsl:call-template></xsl:when>
285                                         <xsl:when test="description | rss1:description | rss9:description | atom:summary[not(@type) or @type='' or @type='text' or @type='html' or @type='xhtml']"><xsl:call-template name="showtext"><xsl:with-param name="node" select="description | rss1:description | rss9:description | atom:summary[not(@type) or @type='' or @type='text' or @type='html' or @type='xhtml']" /></xsl:call-template></xsl:when>
286                                 </xsl:choose>
287                                 <xsl:if test="atom:content/@src">
288                                         <xsl:if test="atom:summary"><br /></xsl:if>
289                                         <a>
290                                                 <xsl:attribute name="href"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="atom:content/@src" /></xsl:call-template></xsl:attribute>
291                                                 <xsl:value-of select="$t-entrylink" />
292                                         </a>
293                                 </xsl:if>
294                         </dd>
295                 </xsl:if>
296                 <!-- item categories -->
297                 <xsl:if test="$t-categories and (atom:category | category)"><dd><xsl:value-of select="concat($t-categories, ' ')" /><xsl:apply-templates select="atom:category | category" /></dd></xsl:if>
298                 <!-- item source -->
299                 <xsl:if test="string-length($t-source)&gt;0">
300                         <xsl:variable name="maybesourceurl" select="(atom:source/link[@rel='alternate']/@href | source/@url)[1]" />
301                         <xsl:variable name="sourceurl"><xsl:if test="$maybesourceurl"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="$maybesourceurl" /></xsl:call-template></xsl:if></xsl:variable>
302                         <xsl:variable name="maybesourcename">
303                                 <xsl:choose>
304                                         <xsl:when test="atom:source/title[not(@type) or @type='' or @type='text' or @type='html' or @type='xhtml']"><xsl:value-of select="atom:source/title[@type='' or @type='text' or @type='html' or @type='xhtml'][1]" /></xsl:when>
305                                         <xsl:when test="string-length(source)&gt;0"><xsl:value-of select="source[1]" /></xsl:when>
306                                         </xsl:choose>
307                         </xsl:variable>
308                         <xsl:if test="string-length($sourceurl)&gt;0 or string-length($maybesourcename)&gt;0">
309                                 <dd>
310                                         <xsl:value-of select="concat($t-source,' ')" />
311                                         <xsl:variable name="sourcename">
312                                                 <xsl:choose>
313                                                         <xsl:when test="$maybesourcename"><xsl:value-of select="$maybesourcename" /></xsl:when>
314                                                         <xsl:otherwise><xsl:value-of select="$sourceurl" /></xsl:otherwise>
315                                                 </xsl:choose>
316                                         </xsl:variable>
317                                         <xsl:choose>
318                                                 <xsl:when test="$sourceurl"><a href="{$sourceurl}"><xsl:value-of select="$sourcename" /></a></xsl:when>
319                                                 <xsl:otherwise><xsl:value-of select="$sourcename" /></xsl:otherwise>
320                                         </xsl:choose>
321                                 </dd>
322                         </xsl:if>
323                 </xsl:if>
324                 <!-- item comments -->
325                 <xsl:if test="comments and string-length($t-comments)&gt;0">
326                         <xsl:variable name="commentsurl"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="comments[1]" /></xsl:call-template></xsl:variable>
327                         <dd><a href="{$commentsurl}"><xsl:value-of select="$t-comments" /></a></dd>
328                 </xsl:if>
329                 <!-- item enclosure -->
330                 <xsl:if test="(atom:link[@rel='enclosure']/@href | enclosure/@url) and string-length($t-download)&gt;0 and string-length($t-enclosure)&gt;0"><dd><xsl:apply-templates select="atom:link[@rel='enclosure'] | enclosure" /></dd></xsl:if>
331                 <!-- item rights -->
332                 <xsl:variable name="itemrights" select="atom:rights[not(@type) or @type='' or @type='text' or @type='html' or @type='xhtml'][1]" />
333                 <xsl:if test="$itemrights"><dd class="rights"><xsl:call-template name="showtext"><xsl:with-param name="node" select="$itemrights" /></xsl:call-template></dd></xsl:if>
334                 <!-- item url -->
335                 <xsl:if test="string-length($url)&gt;0">
336                         <dd class="url">
337                                 <span class="unapi-uri">
338                                         <xsl:for-each select="atom:link[@rel='unapi-uri']">
339                                                 <xsl:attribute name="title">
340                                                         <xsl:value-of select="@href" />
341                                                 </xsl:attribute>
342                                         </xsl:for-each>
343                                         <xsl:choose>
344                                                 <xsl:when test="string-length(substring-after($url, 'http://'))&gt;100">
345                                                         <xsl:value-of select="concat(substring(substring-after($url, 'http://'),1,100),'&#8230;')" />
346                                                 </xsl:when>
347                                                 <xsl:otherwise>
348                                                         <xsl:value-of select="substring-after($url, 'http://')" />
349                                                 </xsl:otherwise>
350                                         </xsl:choose>
351                                 </span>
352                         </dd>
353                 </xsl:if>
354         </xsl:template>
355
356         <xsl:template match="atom:link[@rel='enclosure'] | enclosure">
357                 <xsl:variable name="encurl"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="(@href | @url)[1]" /></xsl:call-template></xsl:variable>
358                 <xsl:value-of select="concat($t-download, ' ')" />
359                 <a href="{$encurl}">
360                         <xsl:choose>
361                                 <xsl:when test="@title"><xsl:value-of select="@title" /></xsl:when>
362                                 <xsl:otherwise><xsl:value-of select="$t-enclosure" /></xsl:otherwise>
363                         </xsl:choose>
364                 </a>
365                 <xsl:if test="@type"> (<xsl:value-of select="@type" />)</xsl:if>
366         </xsl:template>
367
368         <xsl:template match="atom:category | category">
369                 <xsl:variable name="name">
370                         <xsl:choose>
371                                 <xsl:when test="not(namespace-uri())"><xsl:value-of select="." /></xsl:when>
372                                 <xsl:when test="@label"><xsl:value-of select="@label" /></xsl:when>
373                                 <xsl:when test="@term"><xsl:value-of select="@term" /></xsl:when>
374                         </xsl:choose>
375                 </xsl:variable>
376                 <xsl:if test="string-length($name)&gt;0">
377                         <xsl:variable name="category">
378                                 <xsl:choose>
379                                         <xsl:when test="not(namespace-uri())"><xsl:value-of select="." /></xsl:when>
380                                         <xsl:otherwise><xsl:value-of select="@term" /></xsl:otherwise>
381                                 </xsl:choose>
382                         </xsl:variable>
383                         <xsl:variable name="maybeurl" select="(@domain | @scheme)[1]" />
384                         <xsl:variable name="url">
385                                 <xsl:if test="starts-with($maybeurl, 'http')">
386                                         <xsl:value-of select="concat($maybeurl, '#', $category)" />
387                                 </xsl:if>
388                         </xsl:variable>
389                         <xsl:choose>
390                                 <xsl:when test="string-length($url)&gt;0"><a href="{$url}"><xsl:value-of select="$name" /></a></xsl:when>
391                                 <xsl:otherwise><xsl:value-of select="$name" /></xsl:otherwise>
392                         </xsl:choose>
393                         <xsl:text>; </xsl:text>
394                 </xsl:if>
395         </xsl:template>
396         
397         <!-- outputs a 'person' (next 4 templates) -->
398         <xsl:template match="dc:creator | dc:publisher | dc:contributor">
399                 <xsl:call-template name="person"><xsl:with-param name="name" select="." /></xsl:call-template>
400         </xsl:template>
401         <xsl:template match="managingEditor | webMaster | author">
402                 <xsl:call-template name="person">
403                         <xsl:with-param name="email" select="substring-before(concat(normalize-space(.),' '), ' ')" />
404                         <xsl:with-param name="name"><xsl:if test="substring-after(., '(')"><xsl:value-of select="normalize-space(substring-before(substring-after(., '('), ')'))" /></xsl:if></xsl:with-param>
405                 </xsl:call-template>
406         </xsl:template>
407         <xsl:template match="atom:author | atom:contributor">
408                 <xsl:call-template name="person">
409                         <xsl:with-param name="link"><xsl:if test="atom:uri"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="atom:uri" /></xsl:call-template></xsl:if></xsl:with-param>
410                         <xsl:with-param name="email" select="atom:email" />
411                         <xsl:with-param name="name" select="atom:name" />
412                 </xsl:call-template>
413         </xsl:template>
414         <xsl:template name="person">
415                 <xsl:param name="email" />
416                 <xsl:param name="link" />
417                 <xsl:param name="name" />
418                 <xsl:variable name="showname">
419                         <xsl:choose>
420                                 <xsl:when test="string-length($name)&gt;0"><xsl:value-of select="$name" /></xsl:when>
421                                 <xsl:when test="string-length($email)&gt;0"><xsl:value-of select="$email" /></xsl:when>
422                                 <xsl:otherwise><xsl:value-of select="$link" /></xsl:otherwise>
423                         </xsl:choose>
424                 </xsl:variable>
425                 <xsl:variable name="showlink">
426                         <xsl:choose>
427                                 <xsl:when test="string-length($link)"><xsl:value-of select="$link" /></xsl:when>
428                                 <xsl:when test="string-length($email)">mailto:<xsl:value-of select="$email" /></xsl:when>
429                         </xsl:choose>
430                 </xsl:variable>
431                 <xsl:if test="string-length($showname)&gt;0">
432                         <xsl:choose>
433                                 <xsl:when test="string-length($showlink)&gt;0"><a href="{$showlink}"><xsl:value-of select="$showname" /></a></xsl:when>
434                                 <xsl:otherwise><xsl:value-of select="$showname" /></xsl:otherwise>
435                         </xsl:choose>
436                         <xsl:text>; </xsl:text>
437                 </xsl:if>
438         </xsl:template>
439         
440         <!-- outputs text/(x)html; based on code from jtesler -->
441         <xsl:template name="showtext">
442                 <xsl:param name="node" />
443                 <xsl:choose>
444                         <xsl:when test="name($node)='description' or $node/@type='html'"><div class="x-escape"><xsl:value-of select="$node" disable-output-escaping="yes" /></div></xsl:when>
445                         <xsl:when test="$node/@type='xhtml'"><xsl:apply-templates select="$node/xhtml:div" mode="stripXhtml" /></xsl:when>
446                         <xsl:otherwise><xsl:value-of select="$node" /></xsl:otherwise>
447                 </xsl:choose>
448         </xsl:template>
449         <!-- These templates are used for outputting the xhtml output.  We need to
450         Strip xhtml: from all the nodes.  We must also convert any href and src
451         attributes from relative to absolute if there is an xml:base -->
452         <xsl:template match="xhtml:*" mode="stripXhtml">
453                 <xsl:element name="{local-name()}">
454                         <xsl:if test="@href"><xsl:attribute name="href"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="@href"/></xsl:call-template></xsl:attribute></xsl:if>
455                         <xsl:if test="@src"><xsl:attribute name="src"><xsl:call-template name="resolvelink"><xsl:with-param name="url" select="@src"/></xsl:call-template></xsl:attribute></xsl:if>
456                         <xsl:apply-templates select="@* | node()" mode="stripXhtml" />
457                 </xsl:element>
458         </xsl:template>
459         <xsl:template match="node() | @*" mode="stripXhtml"><xsl:copy><xsl:apply-templates select="@* | node()" mode="stripXhtml" /></xsl:copy></xsl:template>
460         <!-- Since we already processed href and src nodes up above, don't process them again here -->
461         <xsl:template match="@href | @src" mode="stripXhtml" priority="1" />
462         
463         <!-- returns absolute links, given absolute ones or relative ones with base ones -->
464         <xsl:template name="resolvelink">
465                 <xsl:param name="url" />
466                 <xsl:param name="node" select="$url" />
467                 <xsl:choose>
468                         <xsl:when test="(contains($url,':') and (not(contains($url,'/')) or contains(substring-before($url,':'), substring-before($url,':')))) or not($url)"><xsl:value-of select="$url" /></xsl:when><!-- url is absolute already -->
469                         <xsl:otherwise>
470                                 <xsl:variable name="basenode" select="($node/ancestor-or-self::*[@xml:base])[last()]" />
471                                 <xsl:variable name="base">
472                                                 <xsl:call-template name="resolvelink">
473                                                 <xsl:with-param name="url" select="$basenode/@xml:base" />
474                                                 <xsl:with-param name="node" select="($basenode/ancestor::*[@xml:base])[last()]" />
475                                         </xsl:call-template>
476                                 </xsl:variable>
477                                 <xsl:variable name="protocol"><xsl:if test="contains($base, '://')"><xsl:value-of select="concat(substring-before($base, '://'), '://')" /></xsl:if></xsl:variable>
478                                 <xsl:variable name="basenoprot"><xsl:choose><xsl:when test="string-length($protocol)"><xsl:value-of select="substring-after($base, '://')" /></xsl:when><xsl:otherwise><xsl:value-of select="$base" /></xsl:otherwise></xsl:choose></xsl:variable>
479                                 <xsl:variable name="trailingslash"><xsl:if test="substring($basenoprot,string-length($basenoprot),1)='/'">true</xsl:if></xsl:variable>
480                                 <xsl:variable name="usebase">
481                                         <xsl:value-of select="$protocol" />
482                                         <xsl:choose>
483                                                 <xsl:when test="not(string-length($trailingslash)) and not(contains($basenoprot, '/'))"><xsl:value-of select="$basenoprot" />/</xsl:when>
484                                                 <xsl:when test="not(string-length($trailingslash)) and contains($basenoprot, '/') and $url != '' and not(starts-with($url, '#')) and not(starts-with($url, '?'))">
485                                                         <xsl:call-template name="uponelevel">
486                                                                 <xsl:with-param name="url" select="$basenoprot" />
487                                                         </xsl:call-template>
488                                                 </xsl:when>
489                                                 <xsl:otherwise><xsl:value-of select="$basenoprot" /></xsl:otherwise>
490                                         </xsl:choose>
491                                 </xsl:variable>
492                                 <xsl:choose>
493                                         <xsl:when test="starts-with($url,'/')"><xsl:value-of select="concat(substring-before($base, '://'), '://', substring-before(substring-after($usebase, '://'), '/'), $url)" /></xsl:when>
494                                         <xsl:when test="starts-with($url,'../')">
495                                                 <xsl:call-template name="resolvelink">
496                                                         <xsl:with-param name="url" select="substring-after($url, '../')" />
497                                                         <xsl:with-param name="base">
498                                                                 <xsl:value-of select="concat(substring-before($base,'://'), '://')" />
499                                                                 <xsl:call-template name="uponelevel"><xsl:with-param name="url" select="substring-after(substring($usebase, 0, string-length($usebase)-1), '://')" /></xsl:call-template>
500                                                         </xsl:with-param>
501                                                 </xsl:call-template>
502                                         </xsl:when>
503                                         <xsl:otherwise>
504                                                 <xsl:variable name="useurl">
505                                                         <xsl:choose>
506                                                                 <xsl:when test="starts-with($url, './')"><xsl:value-of select="substring-after($url, './')" /></xsl:when>
507                                                                 <xsl:otherwise><xsl:value-of select="$url" /></xsl:otherwise>
508                                                         </xsl:choose>
509                                                 </xsl:variable>
510                                                 <xsl:value-of select="concat($usebase, $useurl)" />
511                                         </xsl:otherwise>
512                                 </xsl:choose>
513                         </xsl:otherwise>
514                 </xsl:choose>
515         </xsl:template>
516         <xsl:template name="uponelevel">
517                 <xsl:param name="url" /> <!-- url looks like sub.domain.com/folder/two/three -->
518                 <xsl:variable name="firstpart" select="substring-before($url, '/')" />
519                 <xsl:variable name="afterslash" select="substring-after($url, '/')" />
520                 <xsl:variable name="secondpart"><xsl:if test="contains($afterslash, '/')"><xsl:call-template name="uponelevel"><xsl:with-param name="url" select="$afterslash" /></xsl:call-template></xsl:if></xsl:variable>
521                 <xsl:value-of select="concat($firstpart, '/', $secondpart)" />
522         </xsl:template>
523
524 </xsl:stylesheet>