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