1 <?xml version="1.0"?> 2 <!-- 3 A stylesheet which takes lower-level template annotations and produces an output 4 stylesheet - something which is capable of transforming XML documents into Web 5 pages or other kinds of XML documents. 6 7 Copyright (C) 2005 Paul Boddie <paul@boddie.org.uk> 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2.1 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public 20 License along with this library; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 22 --> 23 <xsl:stylesheet version="1.0" 24 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 25 xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" 26 xmlns:template="http://www.boddie.org.uk/ns/xmltools/template" 27 xmlns:str="http://exslt.org/strings" 28 extension-element-prefixes="str"> 29 30 <xsl:output indent="yes"/> 31 <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/> 32 33 <!-- Fragment extraction support. --> 34 <xsl:param name="element-id"/> 35 36 <!-- Match the document itself. --> 37 38 <xsl:template match="/"> 39 <axsl:stylesheet version="1.0" 40 xmlns:dyn="http://exslt.org/dynamic" 41 extension-element-prefixes="dyn"> 42 43 <axsl:output indent="yes"/> 44 45 <!-- Include internationalisation (i18n) support if appropriate. --> 46 <axsl:param name="translations"/> 47 <axsl:param name="locale"/> 48 49 <!-- Include fragment support if appropriate. --> 50 <axsl:param name="element-path"/> 51 52 <axsl:template match="/"> 53 <xsl:choose> 54 <!-- Fragment production. --> 55 <xsl:when test="$element-id != ''"> 56 <axsl:for-each select="dyn:evaluate($element-path)"> 57 <xsl:apply-templates select="@*|node()"/> 58 </axsl:for-each> 59 </xsl:when> 60 <!-- Whole template production. --> 61 <xsl:otherwise> 62 <xsl:apply-templates select="@*|node()"/> 63 </xsl:otherwise> 64 </xsl:choose> 65 </axsl:template> 66 67 <!-- Produce the rules for each element. --> 68 69 <xsl:apply-templates select="//*[@template:element]"> 70 <xsl:with-param name="top-level">true</xsl:with-param> 71 </xsl:apply-templates> 72 73 </axsl:stylesheet> 74 </xsl:template> 75 76 77 78 <!-- Match elements referencing elements. --> 79 80 <xsl:template match="*[@template:element]" priority="1"> 81 <xsl:param name="top-level">false</xsl:param> 82 <xsl:call-template name="enter-element"> 83 <xsl:with-param name="top-level" select="$top-level"/> 84 </xsl:call-template> 85 </xsl:template> 86 87 <xsl:template name="enter-element"> 88 <xsl:param name="top-level"/> 89 <xsl:choose> 90 <!-- Produce templates where this is a top-level definition. --> 91 <xsl:when test="$top-level = 'true'"> 92 <xsl:call-template name="element-template"> 93 <xsl:with-param name="element-names" select="@template:element"/> 94 </xsl:call-template> 95 </xsl:when> 96 <!-- Produce references to elements where this is within a template. --> 97 <xsl:otherwise> 98 <xsl:variable name="first-name" select="str:split(@template:element, ',')[1]"/> 99 <!-- Check to see if this is a recursive reference. --> 100 <xsl:variable name="recursive-element" select="ancestor::*[$first-name = str:split(@template:element, ',')[1]]"/> 101 <xsl:choose> 102 <!-- Generate a reference to the previous element definition. --> 103 <xsl:when test="$recursive-element"> 104 <axsl:apply-templates select="{$first-name}" mode="{generate-id($recursive-element)}"/> 105 </xsl:when> 106 <!-- Generate a reference to this element definition. --> 107 <xsl:otherwise> 108 <axsl:apply-templates select="{$first-name}" mode="{generate-id(.)}"/> 109 </xsl:otherwise> 110 </xsl:choose> 111 </xsl:otherwise> 112 </xsl:choose> 113 </xsl:template> 114 115 <xsl:template name="element-template"> 116 <xsl:param name="element-names"/> 117 <xsl:variable name="this-name" select="substring-before($element-names, ',')"/> 118 <xsl:variable name="next-names" select="substring-after($element-names, ',')"/> 119 <xsl:variable name="next-name" select="str:split($next-names, ',')[1]"/> 120 <xsl:choose> 121 <!-- Non-last part of a list of element names. --> 122 <!-- Produce a template referencing another template. --> 123 <xsl:when test="$this-name != ''"> 124 <!-- Produce a template with a mode. --> 125 <axsl:template match="{$this-name}" mode="{generate-id(.)}"> 126 <axsl:apply-templates select="{$next-name}" mode="{generate-id(.)}"/> 127 </axsl:template> 128 <!-- Produce the other elements' templates... --> 129 <xsl:call-template name="element-template"> 130 <xsl:with-param name="element-names" select="$next-names"/> 131 </xsl:call-template> 132 </xsl:when> 133 <!-- Last part of a list of element names. --> 134 <!-- Produce a template with content. --> 135 <xsl:otherwise> 136 <!-- Produce a template with a mode. --> 137 <axsl:template match="{$element-names}" mode="{generate-id(.)}"> 138 <xsl:call-template name="enter-attribute"/> 139 </axsl:template> 140 </xsl:otherwise> 141 </xsl:choose> 142 </xsl:template> 143 144 145 146 <!-- Match special conditional expression attributes. --> 147 148 <xsl:template match="*[@template:if]" priority="2"> 149 <xsl:param name="top-level">false</xsl:param> 150 <xsl:choose> 151 <!-- Since this rule may be invoked at the top level, ignore conditions. --> 152 <xsl:when test="$top-level = 'true'"> 153 <xsl:call-template name="enter-element"> 154 <xsl:with-param name="top-level" select="$top-level"/> 155 </xsl:call-template> 156 </xsl:when> 157 <!-- As part of a template, generate the condition. --> 158 <xsl:otherwise> 159 <axsl:if test="{@template:if}"> 160 <xsl:choose> 161 <xsl:when test="@template:element"> 162 <xsl:call-template name="enter-element"/> 163 </xsl:when> 164 <xsl:otherwise> 165 <xsl:call-template name="enter-attribute"/> 166 </xsl:otherwise> 167 </xsl:choose> 168 </axsl:if> 169 </xsl:otherwise> 170 </xsl:choose> 171 </xsl:template> 172 173 174 175 <!-- Match special expression attributes. --> 176 177 <xsl:template match="*[@template:attribute or @template:value or @template:expr or @template:copy]"> 178 <xsl:call-template name="enter-attribute"/> 179 </xsl:template> 180 181 <xsl:template name="enter-attribute"> 182 <xsl:choose> 183 <xsl:when test="@template:attribute"> 184 <axsl:choose> 185 <axsl:when test="@{@template:attribute}"> 186 <axsl:variable name="this-name"><xsl:value-of select="@template:attribute"/></axsl:variable> 187 <axsl:variable name="this-value" select="@{@template:attribute}"/> 188 <xsl:call-template name="special-attributes"/> 189 </axsl:when> 190 <axsl:otherwise> 191 <axsl:variable name="this-name"><xsl:value-of select="@template:attribute"/></axsl:variable> 192 <axsl:variable name="this-value"></axsl:variable> 193 <xsl:call-template name="special-attributes"/> 194 </axsl:otherwise> 195 </axsl:choose> 196 </xsl:when> 197 <xsl:otherwise> 198 <xsl:call-template name="special-attributes"/> 199 </xsl:otherwise> 200 </xsl:choose> 201 </xsl:template> 202 203 <xsl:template name="special-attributes"> 204 <xsl:choose> 205 <xsl:when test="@template:effect = 'replace'"> 206 <xsl:call-template name="special-value"/> 207 </xsl:when> 208 <xsl:otherwise> 209 <xsl:copy> 210 <xsl:apply-templates select="@*"/> 211 <xsl:call-template name="expression-attributes"/> 212 </xsl:copy> 213 </xsl:otherwise> 214 </xsl:choose> 215 </xsl:template> 216 217 <xsl:template name="expression-attributes"> 218 <xsl:if test="@template:expr and @template:expr-attr"> 219 <axsl:if test="{@template:expr}"> 220 <axsl:attribute name="{@template:expr-attr}"><xsl:value-of select="@template:expr-attr"/></axsl:attribute> 221 </axsl:if> 222 </xsl:if> 223 <xsl:call-template name="special-value"/> 224 </xsl:template> 225 226 <xsl:template name="special-value"> 227 <xsl:choose> 228 <!-- Insert the stated value. --> 229 <xsl:when test="@template:value"> 230 <axsl:value-of select="{@template:value}"/> 231 </xsl:when> 232 <!-- Insert the translated value. --> 233 <xsl:when test="@template:i18n"> 234 <xsl:call-template name="translated-value"/> 235 </xsl:when> 236 <!-- Copy the stated expression. --> 237 <xsl:when test="@template:copy"> 238 <axsl:copy-of select="{@template:copy}"/> 239 </xsl:when> 240 <!-- Just process the descendants. --> 241 <xsl:otherwise> 242 <xsl:apply-templates select="node()"/> 243 </xsl:otherwise> 244 </xsl:choose> 245 </xsl:template> 246 247 248 249 <!-- Match internationalisation attributes. --> 250 251 <xsl:template match="*[not(@template:if) and not(@template:element) and not(@template:attribute) and not(@template:value) and not(@template:expr) and @template:i18n]"> 252 <xsl:copy> 253 <xsl:apply-templates select="@*"/> 254 <xsl:call-template name="translated-value"/> 255 </xsl:copy> 256 </xsl:template> 257 258 <xsl:template name="translated-value"> 259 <xsl:choose> 260 <!-- Look for a translation of the contents. --> 261 <xsl:when test="@template:i18n = '-'"> 262 <!-- NOTE: Quoting not done completely. --> 263 <axsl:variable name="translation" 264 select="$translations/translations/locale[code/@value=$locale]/translation[@value='{text()}']/text()"/> 265 <xsl:call-template name="insert-translated-value"/> 266 </xsl:when> 267 <!-- Look for a named translation. --> 268 <xsl:otherwise> 269 <!-- NOTE: Quoting not done completely. --> 270 <axsl:variable name="translation" 271 select="$translations/translations/locale[code/@value=$locale]/translation[@value='{@template:i18n}']/text()"/> 272 <xsl:call-template name="insert-translated-value"/> 273 </xsl:otherwise> 274 </xsl:choose> 275 </xsl:template> 276 277 <xsl:template name="insert-translated-value"> 278 <axsl:choose> 279 <!-- Insert the translated value. --> 280 <axsl:when test="$translation"> 281 <axsl:value-of select="$translation"/> 282 </axsl:when> 283 <!-- Otherwise, just process the descendants. --> 284 <axsl:otherwise> 285 <xsl:apply-templates select="node()"/> 286 </axsl:otherwise> 287 </axsl:choose> 288 </xsl:template> 289 290 291 292 <!-- Remove template attributes. --> 293 294 <xsl:template match="@template:element|@template:init|@template:attribute|@template:value|@template:expr|@template:expr-attr|@template:effect|@template:if|@template:i18n|@template:copy"> 295 </xsl:template> 296 297 298 299 <!-- Replicate unknown elements. --> 300 301 <xsl:template match="@*|node()"> 302 <xsl:copy> 303 <xsl:apply-templates select="@*|node()"/> 304 </xsl:copy> 305 </xsl:template> 306 307 </xsl:stylesheet>