1 <?xml version="1.0"?> 2 <!-- 3 A stylesheet which produces initialisation/input stylesheets for a particular 4 kind of document. 5 6 Copyright (C) 2005 Paul Boddie <paul@boddie.org.uk> 7 8 This library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Lesser General Public 10 License as published by the Free Software Foundation; either 11 version 2.1 of the License, or (at your option) any later version. 12 13 This library is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Lesser General Public License for more details. 17 18 You should have received a copy of the GNU Lesser General Public 19 License along with this library; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 21 --> 22 <xsl:stylesheet version="1.0" 23 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 24 xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" 25 xmlns:template="http://www.boddie.org.uk/ns/xmltools/template"> 26 27 <xsl:output indent="yes"/> 28 <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/> 29 30 31 32 <xsl:param name="init-enumerations">yes</xsl:param> 33 34 35 36 <!-- Match the document itself. --> 37 38 <xsl:template match="/"> 39 <axsl:stylesheet version="1.0" xmlns:dyn="http://exslt.org/dynamic" 40 extension-element-prefixes="dyn"> 41 42 <axsl:output indent="yes"/> 43 44 <!-- Make document parameters for all elements appearing to use enumerations. --> 45 <xsl:if test="$init-enumerations = 'yes'"> 46 <xsl:for-each select="//element[@type='multiple-choice' or @type='multiple-choice-list']"> 47 <axsl:param name="{@name}"/> 48 </xsl:for-each> 49 </xsl:if> 50 51 <!-- Make a document-level rule. --> 52 <axsl:template match="/"> 53 <axsl:apply-templates select="*" mode="{generate-id(*[1])}"/> 54 </axsl:template> 55 56 <!-- Process the top-level element to make other rules. --> 57 <xsl:apply-templates select="*"/> 58 59 <!-- Replicate unknown elements. --> 60 <axsl:template match="@*|placeholder|node()"> 61 <axsl:copy> 62 <axsl:apply-templates select="@*|node()"/> 63 </axsl:copy> 64 </axsl:template> 65 66 <!-- Replicate placeholders for specific elements. --> 67 <xsl:for-each select="//element"> 68 <axsl:template match="placeholder" mode="{generate-id(.)}"> 69 <axsl:copy> 70 <axsl:apply-templates select="@*|node()"/> 71 </axsl:copy> 72 </axsl:template> 73 </xsl:for-each> 74 75 </axsl:stylesheet> 76 </xsl:template> 77 78 79 80 <!-- Match element references. --> 81 82 <xsl:template match="element"> 83 84 <!-- Make a rule for the element. --> 85 <axsl:template match="{@name}" mode="{generate-id(.)}"> 86 87 <!-- Copy the element. --> 88 <xsl:element name="{@name}"> 89 90 <!-- Process attributes. --> 91 <axsl:apply-templates select="@*"/> 92 93 <!-- Find elements and determine how to process them. --> 94 <xsl:call-template name="process-elements"/> 95 </xsl:element> 96 </axsl:template> 97 98 <!-- Make rules for nested elements. --> 99 <xsl:call-template name="process-rules"/> 100 101 </xsl:template> 102 103 104 105 <!-- Process elements. --> 106 107 <xsl:template name="process-elements"> 108 <xsl:param name="path">.</xsl:param> 109 110 <!-- To ensure "stable ordering" of elements, the initialised/static elements are 111 added first; the collection/dynamic elements are added afterwards. This may not 112 necessarily match the schema, however. --> 113 114 <xsl:for-each select="element|element-ref"> 115 <!-- Define elements which do not have selectors. --> 116 <xsl:variable name="adding-selectors" select="count(//selector[@element=current()/@name])"/> 117 118 <xsl:choose> 119 <!-- Recursive element references. --> 120 <xsl:when test="local-name(.) = 'element-ref'"> 121 <axsl:apply-templates select="{@name}" mode="{generate-id(ancestor::element[@name=current()/@name])}"/> 122 </xsl:when> 123 <!-- Enumerations. --> 124 <xsl:when test="@type='multiple-choice-value' or @type='multiple-choice-list-value'"> 125 <!-- Only generate enumerations if requested. --> 126 <xsl:if test="$init-enumerations = 'yes'"> 127 <xsl:call-template name="inside-enumeration"> 128 <xsl:with-param name="path" select="concat($path, '/', @name)"/> 129 </xsl:call-template> 130 </xsl:if> 131 </xsl:when> 132 <!-- Added elements. --> 133 <xsl:when test="(not(@init) or @init = 'auto') and $adding-selectors = 0 or @init = 'yes'"> 134 <xsl:element name="{@name}"> 135 <axsl:apply-templates select="{$path}/{@name}/@*"/> 136 <xsl:call-template name="process-elements"> 137 <xsl:with-param name="path" select="concat($path, '/', @name)"/> 138 </xsl:call-template> 139 </xsl:element> 140 </xsl:when> 141 <!-- Other elements are only added if found and must appear last - see below. --> 142 <xsl:otherwise/> 143 </xsl:choose> 144 </xsl:for-each> 145 146 <!-- Add the collection/dynamic elements at the end. This includes placeholder 147 elements which may have represented the static elements. 148 NOTE: We may wish to exclude placeholder elements in any situation where static 149 NOTE: elements are employed, since the only place where keeping them around is 150 NOTE: necessary/meaningful is in dynamic element collections. --> 151 152 <xsl:call-template name="produce-selection"> 153 <xsl:with-param name="path" select="$path"/> 154 <xsl:with-param name="element" select="element[1]"/> 155 </xsl:call-template> 156 157 </xsl:template> 158 159 160 161 <!-- Produce a selection of collection/dynamic elements. 162 This should produce apply-templates instructions selecting dynamic elements. --> 163 164 <xsl:template name="produce-selection"> 165 <xsl:param name="path"/> 166 <xsl:param name="element"/> 167 168 <xsl:choose> 169 <!-- While elements remain... --> 170 <xsl:when test="$element"> 171 172 <!-- Define elements which do not have selectors. --> 173 <xsl:variable name="adding-selectors" select="count(//selector[@element=$element/@name])"/> 174 175 <xsl:choose> 176 <!-- Do not select added elements or enumerations - see process-elements. --> 177 <xsl:when test="((not($element/@init) or $element/@init = 'auto') and $adding-selectors = 0 or $element/@init = 'yes') 178 or (@type='multiple-choice-value' or @type='multiple-choice-list-value')"> 179 <xsl:call-template name="produce-selection"> 180 <xsl:with-param name="path" select="$path"/> 181 <xsl:with-param name="element" select="$element/following-sibling::element[1]"/> 182 </xsl:call-template> 183 </xsl:when> 184 <!-- Other elements are only added if found. --> 185 <xsl:otherwise> 186 <axsl:apply-templates select="{$path}/placeholder|{$path}/{$element/@name}" mode="{generate-id($element)}"/> 187 <xsl:call-template name="produce-selection"> 188 <xsl:with-param name="path" select="$path"/> 189 <xsl:with-param name="element" select="$element/following-sibling::element[1]"/> 190 </xsl:call-template> 191 </xsl:otherwise> 192 </xsl:choose> 193 </xsl:when> 194 <!-- Do nothing when no elements remain. --> 195 <xsl:otherwise/> 196 </xsl:choose> 197 </xsl:template> 198 199 200 201 <!-- Process rules. --> 202 203 <xsl:template name="process-rules"> 204 <xsl:param name="path">.</xsl:param> 205 206 <xsl:for-each select="element"> 207 <!-- Define elements which do not have selectors. --> 208 <!-- NOTE: Duplicating adding-selectors - see above. --> 209 <xsl:variable name="adding-selectors" select="count(//selector[@element=current()/@name])"/> 210 211 <xsl:choose> 212 <xsl:when test="@type='multiple-choice-value' or @type='multiple-choice-list-value'"> 213 <!-- Do not match multiple-choice values. --> 214 </xsl:when> 215 <xsl:when test="(not(@init) or @init = 'auto') and $adding-selectors = 0 or @init = 'yes'"> 216 <xsl:call-template name="process-rules"> 217 <xsl:with-param name="path" select="concat($path, '/', @name)"/> 218 </xsl:call-template> 219 </xsl:when> 220 <xsl:otherwise> 221 <xsl:apply-templates select="."/> 222 </xsl:otherwise> 223 </xsl:choose> 224 </xsl:for-each> 225 </xsl:template> 226 227 228 229 <!-- Fill in enumerations. --> 230 231 <xsl:template name="inside-enumeration"> 232 <xsl:param name="path"/> 233 234 <!-- Store multiple-choice selections, if appropriate. --> 235 <xsl:if test="../@type='multiple-choice-list'"> 236 <!-- NOTE: It is assumed here that ../attribute/@name (if it exists) == attribute/@name. --> 237 <axsl:variable name="values-{@name}" select="{$path}/@{attribute/@name}"/> 238 </xsl:if> 239 240 <!-- Select inside the enumeration source, inside an element with the field's name, the enumeration elements. --> 241 <xsl:choose> 242 <xsl:when test="../@source='dynamic'"> 243 <axsl:for-each select="dyn:evaluate(${../@name})/{../@name}/{@name}"> 244 <xsl:call-template name="inside-enumeration-element"/> 245 </axsl:for-each> 246 </xsl:when> 247 <xsl:otherwise> 248 <axsl:for-each select="${../@name}/{../@name}/{@name}"> 249 <xsl:call-template name="inside-enumeration-element"/> 250 </axsl:for-each> 251 </xsl:otherwise> 252 </xsl:choose> 253 </xsl:template> 254 255 <xsl:template name="inside-enumeration-element"> 256 <axsl:copy> 257 <axsl:apply-templates select="@*"/> 258 <xsl:if test="@type='multiple-choice-list-value'"> 259 <axsl:if test="$values-{@name}[string() = current()/@{attribute/@name}]"> 260 <axsl:attribute name="{@expr-name}">true</axsl:attribute> 261 </axsl:if> 262 </xsl:if> 263 <!-- Include child nodes, if provided. --> 264 <axsl:copy-of select="node()"/> 265 </axsl:copy> 266 </xsl:template> 267 268 </xsl:stylesheet>