2 Nick's web site: XSLT helper functions.
4 Copyright © 2019-2021 Nick Bowler
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>
19 <xsl:stylesheet version='1.0'
20 xmlns='http://www.w3.org/1999/xhtml'
21 xmlns:xhtml='http://www.w3.org/1999/xhtml'
22 xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
23 xmlns:func='http://exslt.org/functions'
24 xmlns:f='http://draconx.ca/my-functions'
25 extension-element-prefixes='func f'>
27 <xsl:output method='xml' encoding='UTF-8' indent='yes'
28 doctype-public='-//W3C//DTD XHTML 1.1//EN'
29 doctype-system='http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd' />
31 <!-- Returns true iff the given element is an XHTML span-level element -->
32 <func:function name='f:element-is-span'>
33 <xsl:param name='node' select='.' />
34 <func:result select='$node/self::xhtml:a
35 or $node/self::xhtml:abbr
36 or $node/self::xhtml:acronym
37 or $node/self::xhtml:b
38 or $node/self::xhtml:bdo
39 or $node/self::xhtml:big
40 or $node/self::xhtml:br
41 or $node/self::xhtml:button
42 or $node/self::xhtml:cite
43 or $node/self::xhtml:code
44 or $node/self::xhtml:dfn
45 or $node/self::xhtml:em
46 or $node/self::xhtml:i
47 or $node/self::xhtml:img
48 or $node/self::xhtml:input
49 or $node/self::xhtml:kbd
50 or $node/self::xhtml:label
51 or $node/self::xhtml:map
52 or $node/self::xhtml:object
53 or $node/self::xhtml:q
54 or $node/self::xhtml:samp
55 or $node/self::xhtml:script
56 or $node/self::xhtml:select
57 or $node/self::xhtml:small
58 or $node/self::xhtml:span
59 or $node/self::xhtml:strong
60 or $node/self::xhtml:sub
61 or $node/self::xhtml:sup
62 or $node/self::xhtml:textarea
63 or $node/self::xhtml:time
64 or $node/self::xhtml:tt
65 or $node/self::xhtml:var' />
68 <!-- Returns true iff the node is a nonempty text node or a span element -->
69 <func:function name='f:node-is-span'>
70 <xsl:param name='node' select='.' />
71 <func:result select='( $node/self::text() and normalize-text($node) )
72 or f:element-is-span($node)' />
75 <!-- f:ends-with(a, b) returns true iff a ends with b -->
76 <func:function name='f:ends-with'>
77 <xsl:param name='str' />
78 <xsl:param name='suffix' />
79 <func:result select='$suffix=substring($str,
80 string-length($str)-string-length($suffix)+1)' />
83 <!-- Remove leading whitespace from a string -->
84 <func:function name='f:strip-leading'>
85 <xsl:param name='str' select='.' />
86 <xsl:param name='curlen' select='string-length($str)' />
88 <xsl:variable name='a' select='substring($str, 1, $curlen)' />
89 <xsl:variable name='b' select='substring($str, 1+$curlen)' />
92 <xsl:when test='2 > $curlen'>
93 <func:result select='concat(normalize-space($a), $b)' />
95 <xsl:when test='normalize-space($a) = ""'>
96 <func:result select='f:strip-leading($b)' />
99 <func:result select='f:strip-leading($str, ceiling($curlen div 2))' />
104 <!-- Remove trailing whitespace from a string -->
105 <func:function name='f:strip-trailing'>
106 <xsl:param name='str' select='.' />
107 <xsl:param name='curlen' select='string-length($str)' />
109 <xsl:variable name='split' select='string-length($str) - $curlen' />
110 <xsl:variable name='a' select='substring($str, 1, $split)' />
111 <xsl:variable name='b' select='substring($str, 1+$split)' />
114 <xsl:when test='2 > $curlen'>
115 <func:result select='concat($a, normalize-space($b))' />
117 <xsl:when test='normalize-space($b) = ""'>
118 <func:result select='f:strip-trailing($a)' />
121 <func:result select='f:strip-trailing($str, ceiling($curlen div 2))' />
127 Convert the given node to a string containing an XHTML listing for that node.
129 <func:function name='f:xhtml-listing'>
130 <xsl:param name='nodeset' select='.' />
131 <xsl:variable name='node' select='$nodeset[1]' />
135 <xsl:when test='$node/self::text()'>
137 <xsl:value-of select='$node' />
139 <xsl:when test='$node/self::comment()'>
140 <!-- comment node -->
141 <xsl:value-of select='concat("<!--", $node, "-->")' />
143 <xsl:when test='$node/self::*'>
144 <!-- element node -->
145 <xsl:value-of select='concat("<", local-name($node))' />
146 <xsl:value-of select='f:xhtml-listing($node/@*)' />
147 <xsl:if test='not($node/node())'>/</xsl:if>
148 <xsl:value-of select='concat(">", f:xhtml-listing($node/node()))' />
149 <xsl:if test='$node/node()'>
150 <xsl:value-of select='concat("</", local-name($node), ">")' />
153 <xsl:when test='$node'>
154 <!-- attribute node -->
155 <xsl:value-of select='concat(" ", local-name($node), "=")' />
156 <xsl:value-of select='concat("'", $node, "'")' />
159 <xsl:for-each select='$nodeset[position()>1]'>
160 <xsl:value-of select='f:xhtml-listing()' />