1<?xml version="1.0"?>
2<!DOCTYPE xsl:stylesheet [
3
4<!ENTITY lowercase "'abcdefghijklmnopqrstuvwxyz'">
5<!ENTITY uppercase "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'">
6
7<!ENTITY primary   'concat(primary/@sortas, primary[not(@sortas)])'>
8<!ENTITY secondary 'concat(secondary/@sortas, secondary[not(@sortas)])'>
9<!ENTITY tertiary  'concat(tertiary/@sortas, tertiary[not(@sortas)])'>
10
11<!ENTITY section   '(ancestor-or-self::set
12                     |ancestor-or-self::book
13                     |ancestor-or-self::part
14                     |ancestor-or-self::reference
15                     |ancestor-or-self::partintro
16                     |ancestor-or-self::chapter
17                     |ancestor-or-self::appendix
18                     |ancestor-or-self::preface
19                     |ancestor-or-self::section
20                     |ancestor-or-self::sect1
21                     |ancestor-or-self::sect2
22                     |ancestor-or-self::sect3
23                     |ancestor-or-self::sect4
24                     |ancestor-or-self::sect5
25                     |ancestor-or-self::refsect1
26                     |ancestor-or-self::refsect2
27                     |ancestor-or-self::refsect3
28                     |ancestor-or-self::simplesect
29                     |ancestor-or-self::bibliography
30                     |ancestor-or-self::glossary
31                     |ancestor-or-self::index)[last()]'>
32
33<!ENTITY section.id 'generate-id(&section;)'>
34<!ENTITY sep '" "'>
35]>
36<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
37                version="1.0">
38
39<xsl:import href="docbook.xsl"/>
40
41<!-- ==================================================================== -->
42<!-- Jeni Tennison gets all the credit for what follows.
43     I think I understand it :-) Anyway, I've hacked it a bit, so the
44     bugs are mine. -->
45
46<xsl:key name="letter"
47         match="indexterm"
48         use="translate(substring(&primary;, 1, 1),&lowercase;,&uppercase;)"/>
49
50<xsl:key name="primary"
51         match="indexterm"
52         use="&primary;"/>
53
54<xsl:key name="secondary"
55         match="indexterm"
56         use="concat(&primary;, &sep;, &secondary;)"/>
57
58<xsl:key name="tertiary"
59         match="indexterm"
60         use="concat(&primary;, &sep;, &secondary;, &sep;, &tertiary;)"/>
61
62<xsl:key name="primary-section"
63         match="indexterm[not(secondary) and not(see)]"
64         use="concat(&primary;, &sep;, &section.id;)"/>
65
66<xsl:key name="secondary-section"
67         match="indexterm[not(tertiary) and not(see)]"
68         use="concat(&primary;, &sep;, &secondary;, &sep;, &section.id;)"/>
69
70<xsl:key name="tertiary-section"
71         match="indexterm[not(see)]"
72         use="concat(&primary;, &sep;, &secondary;, &sep;, &tertiary;, &sep;, &section.id;)"/>
73
74<xsl:key name="see-also"
75         match="indexterm[seealso]"
76         use="concat(&primary;, &sep;, &secondary;, &sep;, &tertiary;, &sep;, seealso)"/>
77
78<xsl:key name="see"
79         match="indexterm[see]"
80         use="concat(&primary;, &sep;, &secondary;, &sep;, &tertiary;, &sep;, see)"/>
81
82<xsl:key name="sections" match="*[@id]" use="@id"/>
83
84<xsl:template name="generate-index">
85  <xsl:variable name="terms" select="//indexterm[count(.|key('letter',
86                                     translate(substring(&primary;, 1, 1),&lowercase;,&uppercase;))[1]) = 1]"/>
87
88  <xsl:variable name="alphabetical"
89                select="$terms[contains(concat(&lowercase;, &uppercase;),
90                                        substring(&primary;, 1, 1))]"/>
91  <xsl:variable name="others" select="$terms[not(contains(concat(&lowercase;,
92                                                 &uppercase;),
93                                             substring(&primary;, 1, 1)))]"/>
94  <div class="index">
95    <xsl:if test="$others">
96      <div class="indexdiv">
97        <h3>
98          <xsl:call-template name="gentext">
99            <xsl:with-param name="key" select="'index symbols'"/>
100          </xsl:call-template>
101        </h3>
102        <dl>
103          <xsl:apply-templates select="$others[count(.|key('primary',
104                                       &primary;)[1]) = 1]"
105                               mode="index-primary">
106            <xsl:sort select="&primary;"/>
107          </xsl:apply-templates>
108        </dl>
109      </div>
110    </xsl:if>
111    <xsl:apply-templates select="$alphabetical[count(.|key('letter',
112                                 translate(substring(&primary;, 1, 1),&lowercase;,&uppercase;))[1]) = 1]"
113                         mode="index-div">
114      <xsl:sort select="&primary;"/>
115    </xsl:apply-templates>
116  </div>
117</xsl:template>
118
119<xsl:template match="indexterm" mode="index-div">
120  <xsl:variable name="key" select="translate(substring(&primary;, 1, 1),&lowercase;,&uppercase;)"/>
121  <div class="indexdiv">
122    <h3>
123      <xsl:value-of select="translate($key, &lowercase;, &uppercase;)"/>
124    </h3>
125    <dl>
126      <xsl:apply-templates select="key('letter', $key)[count(.|key('primary', &primary;)[1]) = 1]"
127                           mode="index-primary">
128        <xsl:sort select="&primary;"/>
129      </xsl:apply-templates>
130    </dl>
131  </div>
132</xsl:template>
133
134<xsl:template match="indexterm" mode="index-primary">
135  <xsl:variable name="key" select="&primary;"/>
136  <xsl:variable name="refs" select="key('primary', $key)"/>
137  <dt>
138    <xsl:value-of select="primary"/>
139    <xsl:for-each select="$refs[generate-id() = generate-id(key('primary-section', concat($key, &sep;, &section.id;))[1])]">
140      <xsl:apply-templates select="." mode="reference"/>
141    </xsl:for-each>
142  </dt>
143  <xsl:if test="$refs/secondary or $refs[not(secondary)]/*[self::see or self::seealso]">
144    <dd>
145      <dl>
146        <xsl:apply-templates select="$refs[generate-id() = generate-id(key('see', concat(&primary;, &sep;, &sep;, &sep;, see))[1])]"
147                             mode="index-see">
148          <xsl:sort select="see"/>
149        </xsl:apply-templates>
150        <xsl:apply-templates select="$refs[generate-id() = generate-id(key('see-also', concat(&primary;, &sep;, &sep;, &sep;, seealso))[1])]"
151                             mode="index-seealso">
152          <xsl:sort select="seealso"/>
153        </xsl:apply-templates>
154        <xsl:apply-templates select="$refs[secondary and count(.|key('secondary', concat($key, &sep;, &secondary;))[1]) = 1]" 
155                             mode="index-secondary">
156          <xsl:sort select="&secondary;"/>
157        </xsl:apply-templates>
158      </dl>
159    </dd>
160  </xsl:if>
161</xsl:template>
162
163<xsl:template match="indexterm" mode="index-secondary">
164  <xsl:variable name="key" select="concat(&primary;, &sep;, &secondary;)"/>
165  <xsl:variable name="refs" select="key('secondary', $key)"/>
166  <dt>
167    <xsl:value-of select="secondary"/>
168    <xsl:for-each select="$refs[generate-id() = generate-id(key('secondary-section', concat($key, &sep;, &section.id;))[1])]">
169      <xsl:apply-templates select="." mode="reference"/>
170    </xsl:for-each>
171  </dt>
172  <xsl:if test="$refs/tertiary or $refs[not(tertiary)]/*[self::see or self::seealso]">
173    <dd>
174      <dl>
175        <xsl:apply-templates select="$refs[generate-id() = generate-id(key('see', concat(&primary;, &sep;, &secondary;, &sep;, &sep;, see))[1])]"
176                             mode="index-see">
177          <xsl:sort select="see"/>
178        </xsl:apply-templates>
179        <xsl:apply-templates select="$refs[generate-id() = generate-id(key('see-also', concat(&primary;, &sep;, &secondary;, &sep;, &sep;, seealso))[1])]"
180                             mode="index-seealso">
181          <xsl:sort select="seealso"/>
182        </xsl:apply-templates>
183        <xsl:apply-templates select="$refs[tertiary and count(.|key('tertiary', concat($key, &sep;, &tertiary;))[1]) = 1]" 
184                             mode="index-tertiary">
185          <xsl:sort select="&tertiary;"/>
186        </xsl:apply-templates>
187      </dl>
188    </dd>
189  </xsl:if>
190</xsl:template>
191
192<xsl:template match="indexterm" mode="index-tertiary">
193  <xsl:variable name="key" select="concat(&primary;, &sep;, &secondary;, &sep;, &tertiary;)"/>
194  <xsl:variable name="refs" select="key('tertiary', $key)"/>
195  <dt>
196    <xsl:value-of select="tertiary"/>
197    <xsl:for-each select="$refs[generate-id() = generate-id(key('tertiary-section', concat($key, &sep;, &section.id;))[1])]">
198      <xsl:apply-templates select="." mode="reference"/>
199    </xsl:for-each>
200  </dt>
201  <xsl:variable name="see" select="$refs/see | $refs/seealso"/>
202  <xsl:if test="$see">
203    <dd>
204      <dl>
205        <xsl:apply-templates select="$refs[generate-id() = generate-id(key('see', concat(&primary;, &sep;, &secondary;, &sep;, &tertiary;, &sep;, see))[1])]"
206                             mode="index-see">
207          <xsl:sort select="see"/>
208        </xsl:apply-templates>
209        <xsl:apply-templates select="$refs[generate-id() = generate-id(key('see-also', concat(&primary;, &sep;, &secondary;, &sep;, &tertiary;, &sep;, seealso))[1])]"
210                             mode="index-seealso">
211          <xsl:sort select="seealso"/>
212        </xsl:apply-templates>
213      </dl>
214    </dd>
215  </xsl:if>
216</xsl:template>
217
218<xsl:template match="indexterm" mode="reference">
219  <xsl:text>, </xsl:text>
220  <xsl:choose>
221    <xsl:when test="@zone and string(@zone)">
222      <xsl:call-template name="reference">
223        <xsl:with-param name="zones" select="normalize-space(@zone)"/>
224      </xsl:call-template>
225    </xsl:when>
226    <xsl:otherwise>
227      <a>
228        <xsl:variable name="title">
229          <xsl:apply-templates select="&section;" mode="title.markup"/>
230        </xsl:variable>
231
232        <xsl:attribute name="href">
233          <xsl:call-template name="href.target">
234            <xsl:with-param name="object" select="&section;"/>
235          </xsl:call-template>
236        </xsl:attribute>
237
238        <xsl:value-of select="$title"/> <!-- text only -->
239      </a>
240    </xsl:otherwise>
241  </xsl:choose>
242</xsl:template>
243
244<xsl:template name="reference">
245  <xsl:param name="zones"/>
246  <xsl:choose>
247    <xsl:when test="contains($zones, ' ')">
248      <xsl:variable name="zone" select="substring-before($zones, ' ')"/>
249      <xsl:variable name="target" select="key('sections', $zone)"/>
250
251      <a>
252        <xsl:attribute name="href">
253          <xsl:call-template name="href.target">
254            <xsl:with-param name="object" select="$target[1]"/>
255          </xsl:call-template>
256        </xsl:attribute>
257        <xsl:apply-templates select="$target[1]" mode="index-title-content"/>
258      </a>
259      <xsl:text>, </xsl:text>
260      <xsl:call-template name="reference">
261        <xsl:with-param name="zones" select="substring-after($zones, ' ')"/>
262      </xsl:call-template>
263    </xsl:when>
264    <xsl:otherwise>
265      <xsl:variable name="zone" select="$zones"/>
266      <xsl:variable name="target" select="key('sections', $zone)"/>
267
268      <a>
269        <xsl:attribute name="href">
270          <xsl:call-template name="href.target">
271            <xsl:with-param name="object" select="$target[1]"/>
272          </xsl:call-template>
273        </xsl:attribute>
274        <xsl:apply-templates select="$target[1]" mode="index-title-content"/>
275      </a>
276    </xsl:otherwise>
277  </xsl:choose>
278</xsl:template>
279
280<xsl:template match="indexterm" mode="index-see">
281   <dt><xsl:value-of select="see"/></dt>
282</xsl:template>
283
284<xsl:template match="indexterm" mode="index-seealso">
285   <dt><xsl:value-of select="seealso"/></dt>
286</xsl:template>
287
288<xsl:template match="*" mode="index-title-content">
289  <xsl:variable name="title">
290    <xsl:apply-templates select="&section;" mode="title.markup"/>
291  </xsl:variable>
292
293  <xsl:value-of select="$title"/>
294</xsl:template>
295
296</xsl:stylesheet>
297