Improving desktop template
[geeqie.git] / doc / wiki2docbook / html2db / html2db.xsl
1 <?xml version="1.0" encoding="utf-8"?>\r
2 <!-- Copyright 2004 by Laszlo Systems, Inc.\r
3      Released under the Artistic License.\r
4      Written by Oliver Steele.\r
5      Version 1.0.1\r
6      http://osteele.com/sources/xslt/htm2db/\r
7   -->\r
8 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
9                 xmlns:exslt="http://exslt.org/common"\r
10                 xmlns:java="http://xml.apache.org/xalan/java"\r
11                 xmlns:math="http://exslt.org/math"\r
12                 xmlns:db="urn:docbook"\r
13                 xmlns:h="http://www.w3.org/1999/xhtml"\r
14                 exclude-result-prefixes="exslt java math db h"\r
15                 version="1.0">\r
16   \r
17   <!-- Prefixed to every id generated from <a name=> and <a href="#"> -->\r
18   <xsl:param name="anchor-id-prefix" select="''"/>\r
19   \r
20   <!-- Default document root; can be overridden by <?html2db class=> -->\r
21   <xsl:param name="document-root" select="'article'"/>\r
22   \r
23   <xsl:include href="html2db-utils.xsl"/>\r
24   \r
25   <!--\r
26     Default templates\r
27   -->\r
28   \r
29   <!-- pass docbook elements through unchanged; just strip the prefix\r
30        -->\r
31   <xsl:template match="db:*">\r
32     <xsl:element name="{local-name()}">\r
33       <xsl:for-each select="@*">\r
34         <xsl:attribute name="{name()}">\r
35           <xsl:value-of select="."/>\r
36         </xsl:attribute>\r
37       </xsl:for-each>\r
38       <xsl:apply-templates/>\r
39     </xsl:element>\r
40   </xsl:template>\r
41   \r
42   <xsl:template match="@id">\r
43     <xsl:copy/>\r
44   </xsl:template>\r
45   \r
46   <!-- copy processing instructions, too -->\r
47   <xsl:template match="processing-instruction()">\r
48     <xsl:copy/>\r
49   </xsl:template>\r
50   \r
51   <!-- except for html2db instructions -->\r
52   <xsl:template match="processing-instruction('html2db')"/>\r
53   \r
54   <!-- Warn about any html elements that don't match a more\r
55        specific template.  Copy them too, since it's often\r
56        easier to find them in the output. -->\r
57   <xsl:template match="h:*">\r
58     <xsl:message terminate="no">\r
59       Unknown element <xsl:value-of select="name()"/>\r
60     </xsl:message>\r
61     <xsl:copy>\r
62       <xsl:apply-templates/>\r
63     </xsl:copy>\r
64   </xsl:template>\r
65   \r
66   <!--\r
67     Root element and body\r
68   -->\r
69   \r
70   <!-- ignore everything except the body -->\r
71   <xsl:template match="/">\r
72     <xsl:apply-templates select="//h:body"/>\r
73   </xsl:template>\r
74 \r
75   <xsl:template match="h:body">\r
76     <xsl:variable name="class-pi"\r
77                   select="processing-instruction('html2db')[starts-with(string(), 'class=&quot;')][1]"/>\r
78     <xsl:variable name="class">\r
79       <xsl:choose>\r
80         <xsl:when test="count($class-pi)!=0">\r
81           <xsl:value-of select="substring-before(substring-after(string($class-pi[0]), 'class=&quot;'), '&quot;')"/>\r
82         </xsl:when>\r
83         <xsl:otherwise>\r
84           <xsl:value-of select="$document-root"/>\r
85         </xsl:otherwise>\r
86       </xsl:choose>\r
87     </xsl:variable>\r
88     \r
89     <!-- Warn if there are any text nodes outside a para, etc.  See\r
90          the note at the naked text template for why this is a\r
91          warning. -->\r
92     <xsl:if test="text()[normalize-space() != '']">\r
93       <xsl:message terminate="no">\r
94         Text must be inside a &lt;p&gt; tag.\r
95       </xsl:message>\r
96     </xsl:if>\r
97     \r
98     <xsl:element name="{$class}">\r
99       <xsl:apply-templates select="@id"/>\r
100       <xsl:call-template name="section-content">\r
101         <xsl:with-param name="level" select="1"/>\r
102         <xsl:with-param name="nodes" select="//h:body/node()|//h:body/text()"/>\r
103       </xsl:call-template>\r
104     </xsl:element>\r
105   </xsl:template>\r
106   \r
107   <!--\r
108     Section and section title processing\r
109   -->\r
110 \r
111   <!--\r
112     Nest elements that *follow* an h1, h2, etc. into <section> elements\r
113     such that the <h1> content is the section's <title>.\r
114   -->\r
115   <xsl:template name="section-content">\r
116     <xsl:param name="level"/>\r
117     <xsl:param name="nodes"/>\r
118     <xsl:param name="h1" select="concat('h', $level)"/>\r
119     <xsl:param name="h2" select="concat('h', $level+1)"/>\r
120     <xsl:param name="h2-position" select="count(exslt:node-set($nodes)[1]/following-sibling::*[local-name()=$h2])"/>\r
121     \r
122     <!-- copy up to first h2 -->\r
123     <xsl:apply-templates select="exslt:node-set($nodes)[\r
124                          count(following-sibling::*[local-name()=$h2])=$h2-position\r
125                          ]"/>\r
126     \r
127     <!-- if section is empty, add an empty para so it will validate -->\r
128     <xsl:if test="not(exslt:node-set($nodes)/h:para[\r
129             count(following-sibling::*[local-name()=$h2])=$h2-position\r
130             ])">\r
131       <para/>\r
132     </xsl:if>\r
133     \r
134     <!-- subsections -->\r
135     <xsl:for-each select="exslt:node-set($nodes)[local-name()=$h2]">\r
136       <section>\r
137         <xsl:variable name="mynodes" select="exslt:node-set($nodes)[\r
138                       count(following-sibling::*[local-name()=$h2])=\r
139                       count(current()/following-sibling::*[local-name()=$h2])]"/>\r
140         <xsl:for-each select="exslt:node-set($mynodes)[local-name()=$h2]">\r
141           <xsl:choose>\r
142             <xsl:when test="@id">\r
143               <xsl:apply-templates select="@id"/>\r
144             </xsl:when>\r
145             <xsl:when test="h:a/@name">\r
146               <xsl:attribute name="id">\r
147                 <xsl:value-of select="concat($anchor-id-prefix, h:a/@name)"/>\r
148               </xsl:attribute>\r
149             </xsl:when>\r
150           </xsl:choose>\r
151         </xsl:for-each>\r
152         <xsl:call-template name="section-content">\r
153           <xsl:with-param name="level" select="$level+1"/>\r
154           <xsl:with-param name="nodes" select="exslt:node-set($nodes)[\r
155                           count(following-sibling::*[local-name()=$h2])=\r
156                           count(current()/following-sibling::*[local-name()=$h2])]"/>\r
157         </xsl:call-template>\r
158       </section>\r
159     </xsl:for-each>\r
160   </xsl:template>\r
161   \r
162   <!--\r
163     Remove anchors from hn titles.  section-content attaches these as ids\r
164     to the section (after mutilating them as described in the docs).\r
165   -->\r
166   <xsl:template match="h:h1|h:h2|h:h3|h:h4|h:h5|h:h6">\r
167     <title>\r
168       <xsl:apply-templates mode="skip-anchors" select="node()"/>\r
169     </title>\r
170   </xsl:template>\r
171   \r
172   <xsl:template mode="skip-anchors" match="h:a[@name]">\r
173     <xsl:apply-templates/>\r
174   </xsl:template>\r
175   \r
176   <xsl:template mode="skip-anchors" match="node()">\r
177     <xsl:apply-templates select="."/>\r
178   </xsl:template>\r
179   \r
180   <!--\r
181     Inline elements\r
182   -->\r
183   <xsl:template match="h:b|h:i|h:em|h:strong">\r
184     <emphasis role="{local-name()}">\r
185       <xsl:apply-templates/>\r
186     </emphasis>\r
187   </xsl:template>\r
188   \r
189   <xsl:template match="h:dfn">\r
190     <indexterm significance="preferred">\r
191       <primary><xsl:apply-templates/></primary>\r
192     </indexterm>\r
193     <glossterm><xsl:apply-templates/></glossterm>\r
194   </xsl:template>\r
195   \r
196   <xsl:template match="h:var">\r
197     <replaceable><xsl:apply-templates/></replaceable>\r
198   </xsl:template>\r
199   \r
200   <!--\r
201     Inline elements in code\r
202   -->\r
203   <xsl:template match="h:code/h:i|h:tt/h:i|h:pre/h:i">\r
204     <replaceable>\r
205       <xsl:apply-templates/>\r
206     </replaceable>\r
207   </xsl:template>\r
208   \r
209   <xsl:template match="h:code|h:tt">\r
210     <literal>\r
211       <xsl:if test="@class">\r
212         <xsl:attribute name="role"><xsl:value-of select="@class"/></xsl:attribute>\r
213       </xsl:if>\r
214       <xsl:apply-templates/>\r
215     </literal>\r
216   </xsl:template>\r
217   \r
218   <!-- For now, everything that doesn't have a specific match in inline\r
219        processing mode is matched against the default processing mode. -->\r
220   <xsl:template mode="inline" match="*">\r
221     <xsl:apply-templates select="."/>\r
222   </xsl:template>\r
223   \r
224   <!--\r
225     Block elements\r
226   -->\r
227   <xsl:template match="h:p">\r
228     <para>\r
229       <xsl:apply-templates select="@id"/>\r
230       <xsl:apply-templates mode="inline"/>\r
231     </para>\r
232   </xsl:template>\r
233   \r
234   <!-- Wrap naked text nodes in a <para> so that they'll process more\r
235        correctly.  The h:body also warns about these, because even\r
236        this preprocessing step isn't guaranteed to fix them.  This is\r
237        because "Some <i>italic</i> text" will be preprocessed into\r
238        "<para>Some </para> <emphasis>italic</emphasis><para>\r
239        text</para>" instead of "<para>Some <emphasis>italic</emphasis>\r
240        text</para>".  Getting this right would require more work than\r
241        just maintaining the source documents. -->\r
242   <xsl:template match="h:body/text()[normalize-space()!= '']">\r
243     <!-- add an invalid tag to make it easy to find this in\r
244          the generated file -->\r
245     <naked-text>\r
246       <para>\r
247         <xsl:apply-templates/>\r
248       </para>\r
249     </naked-text>\r
250   </xsl:template>\r
251   \r
252   <xsl:template match="h:body/h:code|h:pre">\r
253     <programlisting>\r
254       <xsl:apply-templates/>\r
255     </programlisting>\r
256   </xsl:template>\r
257   \r
258   <xsl:template match="h:blockquote">\r
259     <blockquote>\r
260       <xsl:apply-templates mode="item" select="."/>\r
261     </blockquote>\r
262   </xsl:template>\r
263   \r
264   <!--\r
265     Images\r
266   -->\r
267   <xsl:template name="imageobject">\r
268     <imageobject>\r
269       <imagedata fileref="{@src}">\r
270         <xsl:apply-templates select="@width|@height"/>\r
271       </imagedata>\r
272     </imageobject>\r
273   </xsl:template>\r
274   \r
275   <xsl:template match="h:img/@width">\r
276     <xsl:copy/>\r
277   </xsl:template>\r
278   \r
279   <xsl:template match="h:img">\r
280     <xsl:param name="informal">\r
281       <xsl:if test="not(@title) and not(db:title)">informal</xsl:if>\r
282     </xsl:param>\r
283     <xsl:element name="{$informal}figure">\r
284       <xsl:apply-templates select="@id"/>\r
285       <xsl:choose>\r
286         <xsl:when test="@title">\r
287           <title><xsl:value-of select="@title"/></title>\r
288         </xsl:when>\r
289         <xsl:otherwise>\r
290           <xsl:apply-templates select="db:title"/>\r
291         </xsl:otherwise>\r
292       </xsl:choose>\r
293       <mediaobject>\r
294         <xsl:call-template name="imageobject"/>\r
295         <xsl:if test="@alt and normalize-space(@alt)!=''">\r
296           <caption>\r
297             <para>\r
298               <xsl:value-of select="@alt"/>\r
299             </para>\r
300           </caption>\r
301         </xsl:if>\r
302       </mediaobject>\r
303     </xsl:element>\r
304   </xsl:template>\r
305   \r
306   <xsl:template mode="inline" match="h:img">\r
307     <inlinemediaobject>\r
308       <xsl:apply-templates select="@id"/>\r
309       <xsl:call-template name="imageobject"/>\r
310     </inlinemediaobject>\r
311   </xsl:template>\r
312   \r
313   <!--\r
314     links\r
315   -->\r
316   \r
317   <!-- anchors -->\r
318   <xsl:template match="h:a[@name]">\r
319     <anchor id="{$anchor-id-prefix}{@name}"/>\r
320     <xsl:apply-templates/>\r
321   </xsl:template>\r
322   \r
323   <!-- internal link -->\r
324   <xsl:template match="h:a[starts-with(@href, '#')]">\r
325     <link linkend="{$anchor-id-prefix}{substring-after(@href, '#')}">\r
326       <xsl:apply-templates select="@*"/>\r
327       <xsl:apply-templates/>\r
328     </link>\r
329   </xsl:template>\r
330   \r
331   <!-- external link -->\r
332   <xsl:template match="h:a">\r
333     <ulink url="{@href}">\r
334       <xsl:apply-templates select="@*"/>\r
335       <xsl:apply-templates/>\r
336     </ulink>\r
337   </xsl:template>\r
338   \r
339   <!-- email -->\r
340   <xsl:template match="h:a[starts-with(@href, 'mailto:')]">\r
341     <email>\r
342       <xsl:apply-templates select="@*"/>\r
343       <xsl:value-of select="substring-after(@href, 'mailto:')"/>\r
344     </email>\r
345   </xsl:template>\r
346   \r
347   <!-- link attributes -->\r
348   \r
349   <xsl:template match="h:a/@*"/>\r
350   \r
351   <xsl:template match="h:a/@id">\r
352     <xsl:apply-templates select="@id"/>\r
353   </xsl:template>\r
354   \r
355   <xsl:template match="h:a/@target|h:a/@link">\r
356     <xsl:processing-instruction name="db2html">\r
357       <xsl:text>attribute name="</xsl:text>\r
358       <xsl:value-of select="name()"/>\r
359       <xsl:text>" value=</xsl:text>\r
360       <xsl:call-template name="quote"/>\r
361     </xsl:processing-instruction>\r
362   </xsl:template>\r
363   \r
364   <!--\r
365     lists\r
366   -->\r
367   \r
368   <xsl:template match="h:dl">\r
369     <variablelist>\r
370       <xsl:apply-templates select="db:*"/>\r
371       <xsl:apply-templates select="h:dt"/>\r
372     </variablelist>\r
373   </xsl:template>\r
374   \r
375   <xsl:template match="h:dt">\r
376     <xsl:variable name="item-number" select="count(preceding-sibling::h:dt)+1"/>\r
377     <varlistentry>\r
378       <term>\r
379         <xsl:apply-templates/>\r
380       </term>\r
381       <listitem>\r
382         <!-- Select the dd that follows this dt without an intervening dd -->\r
383         <xsl:apply-templates mode="item"\r
384                              select="following-sibling::h:dd[\r
385                              count(preceding-sibling::h:dt)=$item-number\r
386                              ]"/>\r
387         <!-- If there is no such dd, then insert an empty para -->\r
388         <xsl:if test="count(following-sibling::h:dd[\r
389                 count(preceding-sibling::h:dt)=$item-number\r
390                 ])=0">\r
391           <para/>\r
392         </xsl:if>\r
393       </listitem>\r
394     </varlistentry>\r
395   </xsl:template>\r
396   \r
397   <xsl:template mode="item" match="*[count(h:p) = 0]">\r
398     <para>\r
399       <xsl:apply-templates/>\r
400     </para>\r
401   </xsl:template>\r
402   \r
403   <xsl:template mode="nonblank-nodes" match="node()">\r
404     <xsl:element name="{local-name()}"/>\r
405   </xsl:template>\r
406   \r
407   <xsl:template mode="nonblank-nodes" match="text()[normalize-space()='']"/>\r
408   \r
409   <xsl:template mode="nonblank-nodes" match="text()">\r
410     <text/>\r
411   </xsl:template>\r
412   \r
413   <xsl:template mode="item" match="*">\r
414     <!-- Test whether the first non-blank node is not a p -->\r
415     <xsl:param name="nonblank-nodes">\r
416       <xsl:apply-templates mode="nonblank-nodes"/>\r
417     </xsl:param>\r
418     \r
419     <xsl:param name="tested" select="\r
420                count(exslt:node-set($nonblank-nodes)/*) != 0 and\r
421                local-name(exslt:node-set($nonblank-nodes)/*[1]) != 'p'"/>\r
422     \r
423     <xsl:param name="n1" select="count(*[1]/following::h:p)"/>\r
424     <xsl:param name="n2" select="count(text()[1]/following::h:p)"/>\r
425     \r
426     <xsl:param name="n">\r
427       <xsl:if test="$tested">\r
428         <xsl:value-of select="java:java.lang.Math.max($n1, $n2)"/>\r
429       </xsl:if>\r
430     </xsl:param>\r
431     \r
432     <xsl:if test="false()">\r
433       <nodeset tested="{$tested}" count="{count(exslt:node-set($nonblank-nodes)/*)}">\r
434         <xsl:for-each select="exslt:node-set($nonblank-nodes)/*">\r
435           <element name="{local-name()}"/>\r
436         </xsl:for-each>\r
437       </nodeset>\r
438     </xsl:if>\r
439     \r
440     <!-- Wrap everything before the first p into a para -->\r
441     <xsl:if test="$tested">\r
442       <para>\r
443         <xsl:apply-templates select="\r
444                              node()[count(following::h:p)=$n] |\r
445                              text()[count(following::h:p)=$n]"/>\r
446       </para>\r
447     </xsl:if>\r
448     <xsl:apply-templates select="\r
449                          node()[count(following::h:p)!=$n] |\r
450                          text()[count(following::h:p)!=$n]"/>\r
451   </xsl:template>\r
452   \r
453   <xsl:template match="h:ol">\r
454     <orderedlist spacing="compact">\r
455       <xsl:for-each select="h:li">\r
456         <listitem>\r
457           <xsl:apply-templates mode="item" select="."/>\r
458         </listitem>\r
459       </xsl:for-each>\r
460     </orderedlist>\r
461   </xsl:template>\r
462   \r
463   <xsl:template match="h:ul">\r
464     <itemizedlist spacing="compact">\r
465       <xsl:for-each select="h:li">\r
466         <listitem>\r
467           <xsl:apply-templates mode="item" select="."/>\r
468         </listitem>\r
469       </xsl:for-each>\r
470     </itemizedlist>\r
471   </xsl:template>\r
472   \r
473   <xsl:template match="h:ul[processing-instruction('html2db')]">\r
474     <simplelist>\r
475       <xsl:for-each select="h:li">\r
476         <member type="vert">\r
477           <xsl:apply-templates mode="item" select="."/>\r
478         </member>\r
479       </xsl:for-each>\r
480     </simplelist>\r
481   </xsl:template>\r
482   \r
483   <!--\r
484     ignored markup\r
485   -->\r
486   <xsl:template match="h:br">\r
487     <xsl:processing-instruction name="db2html">\r
488       <xsl:text>element="</xsl:text>\r
489       <xsl:value-of select="local-name()"/>\r
490       <xsl:text>"</xsl:text>\r
491     </xsl:processing-instruction>\r
492   </xsl:template>\r
493   \r
494   <xsl:template match="h:span|h:div">\r
495     <xsl:apply-templates select="*|node()|text()"/>\r
496   </xsl:template>\r
497   \r
498   <!--\r
499     Utility functions and templates for tables\r
500   -->\r
501   <xsl:template mode="count-columns" match="h:tr">\r
502     <n>\r
503       <xsl:value-of select="count(h:td)"/>\r
504     </n>\r
505   </xsl:template>\r
506   \r
507   <!-- tables -->\r
508   <xsl:template match="h:table">\r
509     <xsl:param name="informal">\r
510       <xsl:if test="not(@summary)">informal</xsl:if>\r
511     </xsl:param>\r
512     <xsl:param name="colcounts">\r
513       <xsl:apply-templates mode="count-columns" select=".//h:tr"/>\r
514     </xsl:param>\r
515     <xsl:param name="cols" select="math:max(exslt:node-set($colcounts)/n)"/>\r
516     <xsl:param name="sorted">\r
517       <xsl:for-each select="exslt:node-set($colcounts)/n">\r
518         <xsl:sort order="descending" data-type="number"/>\r
519         <n><xsl:value-of select="."/></n>\r
520       </xsl:for-each>\r
521     </xsl:param>\r
522     <xsl:element name="{$informal}table">\r
523       <xsl:apply-templates select="@id"/>\r
524       <xsl:if test="processing-instruction('html2db')[starts-with(., 'rowsep')]">\r
525         <xsl:attribute name="rowsep">1</xsl:attribute>\r
526       </xsl:if>\r
527       <xsl:apply-templates select="processing-instruction()"/>\r
528       <xsl:if test="@summary">\r
529         <title><xsl:value-of select="@summary"/></title>\r
530       </xsl:if>\r
531       <tgroup cols="{$cols}">\r
532         <xsl:if test=".//h:tr/h:th">\r
533           <thead>\r
534             <xsl:for-each select=".//h:tr[count(h:th)!=0]">\r
535               <row>\r
536                 <xsl:apply-templates select="@id"/>\r
537                 <xsl:for-each select="h:td|h:th">\r
538                   <entry>\r
539                     <xsl:apply-templates select="@id"/>\r
540                     <xsl:apply-templates/>\r
541                   </entry>\r
542                 </xsl:for-each>\r
543               </row>\r
544               <xsl:text>&#10;</xsl:text> <!-- cr -->\r
545             </xsl:for-each>\r
546           </thead>\r
547         </xsl:if>\r
548         <tbody>\r
549           <xsl:for-each select=".//h:tr[count(h:th)=0]">\r
550             <row>\r
551               <xsl:apply-templates select="@id"/>\r
552               <xsl:for-each select="h:td|h:th">\r
553                 <entry>\r
554                   <xsl:apply-templates select="@id"/>\r
555                   <xsl:apply-templates/>\r
556                 </entry>\r
557               </xsl:for-each>\r
558             </row>\r
559             <xsl:text>&#10;</xsl:text> <!-- cr -->\r
560           </xsl:for-each>\r
561         </tbody>\r
562       </tgroup>\r
563     </xsl:element>\r
564   </xsl:template>\r
565 </xsl:stylesheet>\r