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