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