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="*"/> 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 </axsl:stylesheet> 67 </xsl:template> 68 69 70 71 <!-- Match element references. --> 72 73 <xsl:template match="element"> 74 75 <!-- Make a rule for the element. --> 76 <axsl:template match="{@name}"> 77 78 <!-- Copy the element. --> 79 <xsl:element name="{@name}"> 80 81 <!-- Process attributes. --> 82 <axsl:apply-templates select="@*"/> 83 84 <!-- Find elements and determine how to process them. --> 85 <xsl:call-template name="process-elements"/> 86 </xsl:element> 87 </axsl:template> 88 89 <!-- Make rules for nested elements. --> 90 <xsl:call-template name="process-rules"/> 91 92 </xsl:template> 93 94 95 96 <!-- Process elements. --> 97 98 <xsl:template name="process-elements"> 99 <xsl:param name="path">.</xsl:param> 100 101 <!-- To ensure "stable ordering" of elements, the initialised/static elements are 102 added first; the collection/dynamic elements are added afterwards. This may not 103 necessarily match the schema, however. --> 104 105 <xsl:for-each select="element"> 106 <!-- Define elements which do not have selectors. --> 107 <xsl:variable name="adding-selectors" select="count(//selector[@element=current()/@name])"/> 108 109 <xsl:choose> 110 <!-- Enumerations. --> 111 <xsl:when test="@type='multiple-choice-value' or @type='multiple-choice-list-value'"> 112 <!-- Only generate enumerations if requested. --> 113 <xsl:if test="$init-enumerations = 'yes'"> 114 <xsl:call-template name="inside-enumeration"> 115 <xsl:with-param name="path" select="concat($path, '/', @name)"/> 116 </xsl:call-template> 117 </xsl:if> 118 </xsl:when> 119 <!-- Added elements. --> 120 <xsl:when test="(not(@init) or @init = 'auto') and $adding-selectors = 0 or @init = 'yes'"> 121 <xsl:element name="{@name}"> 122 <axsl:apply-templates select="{$path}/{@name}/@*"/> 123 <xsl:call-template name="process-elements"> 124 <xsl:with-param name="path" select="concat($path, '/', @name)"/> 125 </xsl:call-template> 126 </xsl:element> 127 </xsl:when> 128 <!-- Other elements are only added if found and must appear last - see below. --> 129 <xsl:otherwise/> 130 </xsl:choose> 131 </xsl:for-each> 132 133 <!-- Add the collection/dynamic elements at the end. This includes placeholder 134 elements which may have represented the static elements. 135 NOTE: We may wish to exclude placeholder elements in any situation where static 136 NOTE: elements are employed, since the only place where keeping them around is 137 NOTE: necessary/meaningful is in dynamic element collections. --> 138 139 <xsl:call-template name="produce-selection"> 140 <xsl:with-param name="path" select="$path"/> 141 <xsl:with-param name="selection" select="concat($path, '/placeholder')"/> 142 <xsl:with-param name="element" select="element[1]"/> 143 </xsl:call-template> 144 145 </xsl:template> 146 147 148 149 <!-- Produce a selection of collection/dynamic elements. 150 This should produce an apply-templates instruction selecting dynamic elements. 151 For example: 152 ./placeholder|./some-element|./some-other-element --> 153 154 <xsl:template name="produce-selection"> 155 <xsl:param name="path"/> 156 <xsl:param name="selection"/> 157 <xsl:param name="element"/> 158 159 <xsl:choose> 160 <!-- After processing all elements, produce the selection instruction. --> 161 <xsl:when test="not($element)"> 162 <axsl:apply-templates select="{$selection}"/> 163 </xsl:when> 164 <!-- Otherwise, process the remaining elements. --> 165 <xsl:otherwise> 166 167 <!-- Define elements which do not have selectors. --> 168 <xsl:variable name="adding-selectors" select="count(//selector[@element=$element/@name])"/> 169 170 <xsl:choose> 171 <!-- Do not select added elements or enumerations - see process-elements. --> 172 <xsl:when test="((not($element/@init) or $element/@init = 'auto') and $adding-selectors = 0 or $element/@init = 'yes') 173 or (@type='multiple-choice-value' or @type='multiple-choice-list-value')"> 174 <xsl:call-template name="produce-selection"> 175 <xsl:with-param name="path" select="$path"/> 176 <xsl:with-param name="selection" select="$selection"/> 177 <xsl:with-param name="element" select="$element/following-sibling::element[1]"/> 178 </xsl:call-template> 179 </xsl:when> 180 <!-- Other elements are only added if found. --> 181 <xsl:otherwise> 182 <xsl:call-template name="produce-selection"> 183 <xsl:with-param name="path" select="$path"/> 184 <xsl:with-param name="selection" select="concat($selection, '|', $path, '/', $element/@name)"/> 185 <xsl:with-param name="element" select="$element/following-sibling::element[1]"/> 186 </xsl:call-template> 187 </xsl:otherwise> 188 </xsl:choose> 189 190 </xsl:otherwise> 191 </xsl:choose> 192 </xsl:template> 193 194 195 196 <!-- Process rules. --> 197 198 <xsl:template name="process-rules"> 199 <xsl:param name="path">.</xsl:param> 200 201 <xsl:for-each select="element"> 202 <!-- Define elements which do not have selectors. --> 203 <!-- NOTE: Duplicating adding-selectors - see above. --> 204 <xsl:variable name="adding-selectors" select="count(//selector[@element=current()/@name])"/> 205 206 <xsl:choose> 207 <xsl:when test="@type='multiple-choice-value' or @type='multiple-choice-list-value'"> 208 <!-- Do not match multiple-choice values. --> 209 </xsl:when> 210 <xsl:when test="(not(@init) or @init = 'auto') and $adding-selectors = 0 or @init = 'yes'"> 211 <xsl:call-template name="process-rules"> 212 <xsl:with-param name="path" select="concat($path, '/', @name)"/> 213 </xsl:call-template> 214 </xsl:when> 215 <xsl:otherwise> 216 <xsl:apply-templates select="."/> 217 </xsl:otherwise> 218 </xsl:choose> 219 </xsl:for-each> 220 </xsl:template> 221 222 223 224 <!-- Fill in enumerations. --> 225 226 <xsl:template name="inside-enumeration"> 227 <xsl:param name="path"/> 228 229 <!-- Store multiple-choice selections, if appropriate. --> 230 <xsl:if test="../@type='multiple-choice-list'"> 231 <!-- NOTE: It is assumed here that ../attribute/@name (if it exists) == attribute/@name. --> 232 <axsl:variable name="values-{@name}" select="{$path}/@{attribute/@name}"/> 233 </xsl:if> 234 235 <!-- Select inside the enumeration source, inside an element with the field's name, the enumeration elements. --> 236 <xsl:choose> 237 <xsl:when test="../@source='dynamic'"> 238 <axsl:for-each select="dyn:evaluate(${../@name})/{../@name}/{@name}"> 239 <xsl:call-template name="inside-enumeration-element"/> 240 </axsl:for-each> 241 </xsl:when> 242 <xsl:otherwise> 243 <axsl:for-each select="${../@name}/{../@name}/{@name}"> 244 <xsl:call-template name="inside-enumeration-element"/> 245 </axsl:for-each> 246 </xsl:otherwise> 247 </xsl:choose> 248 </xsl:template> 249 250 <xsl:template name="inside-enumeration-element"> 251 <axsl:copy> 252 <axsl:apply-templates select="@*"/> 253 <xsl:if test="@type='multiple-choice-list-value'"> 254 <axsl:if test="$values-{@name}[string() = current()/@{attribute/@name}]"> 255 <axsl:attribute name="{@expr-name}">true</axsl:attribute> 256 </axsl:if> 257 </xsl:if> 258 <!-- Include child nodes, if provided. --> 259 <axsl:copy-of select="node()"/> 260 </axsl:copy> 261 </xsl:template> 262 263 </xsl:stylesheet>