source: metadata/branches/cmdi-1.1/toolkit/xslt/comp2schema-v2/comp2schema.xsl @ 6921

Last change on this file since 6921 was 6921, checked in by Menzo Windhouwer, 9 years ago

M xslt/comp2schema-v2/comp2schema.xsl

  • only match when @Multilingual="true" instead of when @Multilingual exists
  • Property svn:executable set to *
  • Property svn:keywords set to
    Date
    Rev
File size: 17.8 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2
3<!--
4    $Rev: 6921 $
5    $Date: 2016-01-21 11:52:41 +0000 (Thu, 21 Jan 2016) $
6-->
7
8<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
9    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:dcr="http://www.isocat.org/ns/dcr"
10    xmlns:ann="http://www.clarin.eu">
11   
12    <xsl:variable name="CMDVersion" select="'1.1'"/>
13
14    <xsl:strip-space elements="*"/>
15    <xsl:include href="comp2schema-header.xsl"/>
16    <xsl:include href="cleanup-xsd.xsl"/>
17    <!-- note: the automatic chaining with clean-xsd.xsl only works with the Saxon XSLT processor, otherwise you'll have to do this manually (or use e.g the Xalan pipeDocument tag) -->
18    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no" />
19
20    <!-- Start includes -->
21
22    <!-- resolve includes -->
23    <xsl:template match="@*|node()" mode="include">
24        <xsl:copy>
25            <xsl:apply-templates select="@*|node()" mode="include"/>
26        </xsl:copy>
27    </xsl:template>
28
29    <xsl:template match="CMD_Component[@filename]" mode="include">
30        <!-- some of the outer CMD_Component attributes can overwrite the inner CMD_Component attributes -->
31        <xsl:variable name="outer-attr" select="@CardinalityMin|@CardinalityMax"/>
32        <xsl:for-each select="document(@filename)/CMD_ComponentSpec/CMD_Component">
33            <xsl:variable name="inner-attr" select="@*"/>
34            <xsl:copy>
35                <xsl:apply-templates select="$outer-attr" mode="include"/>
36                <xsl:apply-templates
37                    select="$inner-attr[not(node-name(.) = $outer-attr/node-name(.))]"
38                    mode="include"/>
39                <xsl:apply-templates select="node()" mode="include"/>
40            </xsl:copy>
41        </xsl:for-each>
42    </xsl:template>
43
44    <!-- Stop includes -->
45
46    <!-- main -->
47    <xsl:template match="/">
48        <!-- Resolve all includes -->
49        <xsl:variable name="tree">
50            <xsl:apply-templates mode="include"/>
51        </xsl:variable>
52        <!-- Process the complete tree -->
53        <xsl:variable name="schema">
54            <xsl:apply-templates select="$tree/*"/>
55        </xsl:variable>
56        <xsl:apply-templates select="$schema" mode="clean" />
57    </xsl:template>
58
59    <!-- generate XSD -->
60    <xsl:template match="/CMD_ComponentSpec">
61
62        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:dcr="http://www.isocat.org/ns/dcr" xmlns:cmd="http://www.clarin.eu/cmd/" targetNamespace="http://www.clarin.eu/cmd/" elementFormDefault="qualified">
63           
64            <!-- put the header information from the component specification in the schema as appinfo -->
65            <xs:annotation>
66                <xs:appinfo xmlns:ann="http://www.clarin.eu">
67                    <xsl:apply-templates select="Header" mode="Header"/>
68                </xs:appinfo>
69            </xs:annotation>
70           
71            <!-- import this for the use of the xml:lang attribute -->
72            <xs:import namespace="http://www.w3.org/XML/1998/namespace"
73                schemaLocation="http://www.w3.org/2001/xml.xsd"/>
74
75
76            <!--  first create complex types for valueschemes (not inline) -->
77            <xsl:call-template name="CreateComplexTypes"/>
78
79            <!-- then create simple type for the ResourceProxy -->
80            <xsl:call-template name="PrintHeaderType"/>
81           
82
83            <xs:element name="CMD">
84                <xs:complexType>
85                   
86                    <xs:sequence>
87
88                        <!-- Produce (fixed) header elements (description and resources)-->
89                        <xsl:call-template name="PrintHeader"/>
90
91                        <!-- Then generate the components -->
92                        <xs:element name="Components">
93
94                            <xs:complexType>
95                                <xs:sequence>
96                                    <!--Start with processing the root component once and then process everything else recursively-->
97                                    <xsl:apply-templates select="/CMD_ComponentSpec/CMD_Component"/>
98                                </xs:sequence>
99                                <xs:anyAttribute namespace="##other" processContents="lax"/>
100                            </xs:complexType>
101                        </xs:element>
102
103                        <!-- Generate the footer -->
104                    </xs:sequence>
105                   
106                    <!-- CMD version -->
107                    <xs:attribute name="CMDVersion" fixed="{$CMDVersion}" use="required"/>
108                        <xs:anyAttribute namespace="##other" processContents="lax"/>
109                   
110                </xs:complexType>
111            </xs:element>
112        </xs:schema>
113
114    </xsl:template>
115   
116    <xsl:template match="*" mode="Header">
117        <xsl:element name="ann:{name()}" namespace="http://www.clarin.eu">
118            <xsl:value-of select="text()"/>
119            <xsl:apply-templates select="*" mode="Header" />
120        </xsl:element>
121    </xsl:template>
122
123    <xsl:template name="CreateComplexTypes">
124        <xsl:apply-templates select="CMD_Component" mode="types"/>
125    </xsl:template>
126
127
128    <!-- Start types -->
129
130    <!-- skip all text nodes -->
131    <xsl:template match="text()" mode="types"/>
132
133    <!-- first pass: create the complex types on top of the resulting XSD -->
134    <!-- ignore when this ValueScheme is descendant of an Attribute as we do not allow CV-attributes in a CV-list -->
135    <xsl:template match="ValueScheme[not(../../Attribute)]" mode="types">
136
137        <!-- create a unique suffix (the path to the element) to ensure the unicity of the types to be created -->
138        <xsl:variable name="uniquePath">
139            <xsl:call-template name="printComponentId">
140                <!-- start from the CMD_Element above and go upwards in the tree -->
141                <xsl:with-param name="node" select=".."/>
142            </xsl:call-template>
143        </xsl:variable>
144
145        <!-- first auto-generate a name for the simpletype to be extended -->
146        <xs:simpleType name="simpletype{$uniquePath}">
147            <xs:restriction base="xs:string">
148                <xsl:apply-templates select="pattern"/>
149                <xsl:apply-templates select="enumeration"/>
150            </xs:restriction>
151        </xs:simpleType>
152
153        <!--  then auto-derive a complextype for the attributes -->
154        <xs:complexType name="complextype{$uniquePath}">
155            <xs:simpleContent>
156                <xs:extension base="cmd:simpletype{$uniquePath}">
157                    <!-- now look at the attribute list of the CMD_Element parent of this ValueScheme-->
158                    <xsl:apply-templates select="parent::node()/AttributeList/Attribute"/>
159                    <!--<xs:attribute name="attributeName" type="xs:anyURI"/>-->
160                </xs:extension>
161            </xs:simpleContent>
162        </xs:complexType>
163
164    </xsl:template>
165
166    <!-- Stop types -->
167
168    <!-- create a unique identifier from the current ValueScheme element -->
169    <xsl:template name="printComponentId">
170        <xsl:param name="node"/>
171        <xsl:text>-</xsl:text>
172
173        <xsl:choose>
174
175            <!-- deeper recursion needed -->
176            <xsl:when test="$node[not(@ComponentId)]">
177
178                <xsl:choose>
179                    <!-- element has name, add it to the type name and recurse upwards in the tree -->
180                    <xsl:when test="name($node) = 'CMD_Element'">
181                        <xsl:value-of select="$node/attribute::name"/>
182                    </xsl:when>
183                    <!-- "worst" case: embedded anonymous component without ComponentId: use the xpath -->
184                    <xsl:when test="name($node)  = 'CMD_Component'">
185                        <xsl:value-of select="count($node/preceding-sibling::*)"/>
186                    </xsl:when>
187                </xsl:choose>
188
189                <!-- recursive call -->
190                <xsl:call-template name="printComponentId">
191                    <xsl:with-param name="node" select="$node/.."/>
192                </xsl:call-template>
193
194            </xsl:when>
195
196            <!-- end of recursion: component has ComponentId -->
197            <xsl:otherwise>
198                <xsl:value-of select="replace($node/attribute::ComponentId, ':', '.')"/>
199            </xsl:otherwise>
200
201        </xsl:choose>
202
203    </xsl:template>
204
205
206
207    <!-- convert all components -->
208    <xsl:template match="CMD_Component">
209        <!--  use override values if specified in parent <CMD_Component filename=...> , otherwise use default cardinality for this component -->
210        <xsl:param name="MinOccurs" select="@CardinalityMin"/>
211        <xsl:param name="MaxOccurs" select="@CardinalityMax"/>
212
213        <xs:element name="{@name}">
214           
215            <xsl:if test="$MinOccurs">
216                <xsl:attribute name="minOccurs">
217                    <xsl:value-of select="$MinOccurs"/>
218                </xsl:attribute>
219            </xsl:if>
220            <xsl:if test="$MaxOccurs">
221                <xsl:attribute name="maxOccurs">
222                    <xsl:value-of select="$MaxOccurs"/>
223                </xsl:attribute>
224            </xsl:if>
225            <!-- Add a dcr:datcat if a ConceptLink attribute is found -->
226            <xsl:apply-templates select="./@ConceptLink"/>
227
228            <xs:complexType>
229                <xs:sequence>
230                    <!-- process all elements at this level -->
231                    <xsl:apply-templates select="./CMD_Element"/>
232                    <!-- process all components at one level deeper (recursive call) -->
233                    <xsl:apply-templates select="./CMD_Component"/>
234                </xs:sequence>
235                <!-- DISABLED (Arbil needs to handle it first) allow @xml:base as a residue of XInclude processing -X->
236                <xs:attribute ref="xml:base"/>
237                -->
238                <!-- @ref to the resource proxy (TODO: put this in the CMD namespace, i.e., @cmd:ref -->                 
239                <xs:attribute name="ref" type="xs:IDREFS"/>
240                <xsl:apply-templates select="./AttributeList/Attribute"/>
241                <xsl:if test="@ComponentId">
242                    <xs:attribute name="ComponentId" type="xs:anyURI" fixed="{@ComponentId}"/>
243                </xsl:if>
244            </xs:complexType>
245
246        </xs:element>
247
248    </xsl:template>
249
250    <!-- Process all CMD_Elements, its attributes and children -->
251
252    <!-- Highest complexity: both attributes and a valuescheme, link to the type we created during the preprocessing of the ValueScheme -->
253    <xsl:template match="CMD_Element[./AttributeList][./ValueScheme]" priority="3">
254        <xs:element name="{@name}">
255
256            <!-- process all Documentation and DisplayPriority attributes -->
257            <xsl:call-template name="annotations"/>
258
259            <xsl:apply-templates select="@ConceptLink"/>
260            <xsl:apply-templates select="@CardinalityMin"/>
261            <xsl:apply-templates select="@CardinalityMax"/>
262            <xsl:apply-templates select="ValueScheme"/>
263
264        </xs:element>
265    </xsl:template>
266
267    <!-- Medium complexity: attributes (or Multilingual field) but no valuescheme, can be arranged inline -->
268    <xsl:template match="CMD_Element[./AttributeList or ./@Multilingual='true']" priority="2">
269        <xs:element name="{@name}">
270
271            <xsl:apply-templates select="@Multilingual"/>
272            <xsl:apply-templates select="@ConceptLink"/>
273            <xsl:apply-templates select="@CardinalityMin"/>
274            <xsl:apply-templates select="@CardinalityMax"/>
275
276            <!-- process all Documentation and DisplayPriority attributes -->
277            <xsl:call-template name="annotations"/>
278
279            <!-- <xsl:apply-templates select= "and(not(@type) and @*)"/> -->
280            <xs:complexType>
281                <xs:simpleContent>
282                    <xs:extension base="{concat('xs:',@ValueScheme)}">
283                        <xsl:apply-templates select="./AttributeList/Attribute"/>
284                        <!-- temporarily disabled -->
285                        <xsl:if test="./@Multilingual='true'">
286                            <xs:attribute ref="xml:lang" />
287                        </xsl:if>
288                    </xs:extension>
289                </xs:simpleContent>
290            </xs:complexType>
291        </xs:element>
292    </xsl:template>
293
294
295    <!-- Simple case: no attributes and no value scheme, 1-to-1 transform to an xs:element, just rename element and attributes -->
296    <xsl:template match="CMD_Element" priority="1">
297        <xsl:element name="xs:element">
298            <xsl:apply-templates
299                select="@*[name() != 'Documentation' and name() != 'DisplayPriority'] | node()"/>
300            <!-- process all Documentation and DisplayPriority attributes -->
301            <xsl:call-template name="annotations"/>
302        </xsl:element>
303    </xsl:template>
304
305    <!-- end of CMD_Element templates -->
306
307    <!-- second pass, now link to the earlier created complextype definition -->
308    <xsl:template match="ValueScheme">
309        <xsl:variable name="uniquePath">
310            <xsl:call-template name="printComponentId">
311                <!-- start from the CMD_Element above and go upwards in the tree -->
312                <xsl:with-param name="node" select=".."/>
313            </xsl:call-template>
314        </xsl:variable>
315
316        <xsl:attribute name="type">
317            <xsl:text>cmd:complextype</xsl:text>
318            <xsl:value-of select="$uniquePath"/>
319        </xsl:attribute>
320    </xsl:template>
321
322    <!-- Convert the AttributeList into real XSD attributes -->
323    <xsl:template match="AttributeList/Attribute">
324        <xs:attribute name="{./Name}">
325
326            <!-- Add a dcr:datcat if a ConceptLink element is found -->
327            <xsl:if test="normalize-space(./ConceptLink)!=''">
328                <xsl:attribute name="dcr:datcat">
329                    <xsl:value-of select="./ConceptLink" />
330                </xsl:attribute>
331            </xsl:if>
332           
333            <!-- add some extra stuff if we have a CV attribute -->
334            <xsl:choose>
335
336                <!-- complex situation: CV or regex -->
337                <xsl:when test="./ValueScheme">
338                    <xs:simpleType>
339                        <xs:restriction base="xs:string">
340                            <!-- now use general rules for enumeration or pattern -->
341                            <xsl:apply-templates select="./ValueScheme/*"/>
342                        </xs:restriction>
343                    </xs:simpleType>
344                </xsl:when>
345
346                <!-- simple situation: just a basic type -->
347                <xsl:otherwise>
348                    <xsl:attribute name="type">
349                        <xsl:value-of select="concat('xs:',./Type)"/>
350                    </xsl:attribute>
351                </xsl:otherwise>
352
353            </xsl:choose>
354
355        </xs:attribute>
356    </xsl:template>
357   
358   
359    <!-- Convert patterns -->
360    <xsl:template match="pattern">
361        <xs:pattern value="{self::node()}"/>
362    </xsl:template>
363
364    <!-- Convert enumerations -->
365    <xsl:template match="enumeration">
366
367        <xsl:for-each select="item">
368            <xs:enumeration value="{node()}">
369                <!-- Add a dcr:datcat if a ConceptLink attribute is found -->
370                <xsl:apply-templates select="./@ConceptLink"/>
371                <xsl:apply-templates select="./@AppInfo"/>
372            </xs:enumeration>
373        </xsl:for-each>
374    </xsl:template>
375
376
377    <!--  default action: keep the attributes like they are -->
378    <xsl:template match="@*|node()">
379        <xsl:copy/>
380    </xsl:template>
381
382
383    <!-- except for those attributes we want to be renamed -->
384    <xsl:template match="@CardinalityMin">
385        <xsl:attribute name="minOccurs">
386            <xsl:value-of select="."/>
387        </xsl:attribute>
388    </xsl:template>
389
390    <xsl:template match="@CardinalityMax">
391        <xsl:attribute name="maxOccurs">
392            <xsl:value-of select="."/>
393        </xsl:attribute>
394    </xsl:template>
395
396    <!-- start multilinguality part -->
397
398    <!-- if the multilingual attribute is there and the field has the type string, allow multuple occurrences -->
399    <xsl:template match="@Multilingual[../@ValueScheme='string'][. = 'true'] ">
400        <!-- temporarily disabled until Arbil can deal with the <xs:import> to cope with xml:lang -->
401        <xsl:attribute name="maxOccurs">
402            <xsl:value-of>unbounded</xsl:value-of>
403        </xsl:attribute>
404    </xsl:template>
405
406    <xsl:template match="@Multilingual">
407        <!-- do nothing - only influences maxOccurs if it is true and if it is a a string element -->
408    </xsl:template>
409
410    <xsl:template match="@CardinalityMax[../@Multilingual='true'][../@ValueScheme='string']">
411        <!-- do nothing - maxOccurs should be set by Multilingual rule for strings -->
412    </xsl:template>
413
414    <!-- end multilinguality part -->
415
416    <xsl:template match="@ConceptLink">
417        <xsl:attribute name="dcr:datcat">
418            <xsl:value-of select="."/>
419        </xsl:attribute>
420    </xsl:template>
421
422    <xsl:template match="@AppInfo">
423        <xsl:attribute name="ann:label"><xsl:value-of select="."/></xsl:attribute>
424    </xsl:template>
425
426    <xsl:template match="@ValueScheme">
427        <xsl:attribute name="type">
428            <xsl:value-of select="concat('xs:',.)"/>
429        </xsl:attribute>
430    </xsl:template>
431
432    <xsl:template match="@Documentation">
433        <xsl:attribute name="ann:documentation">
434            <xsl:value-of select="."/>
435        </xsl:attribute>
436        <!--<xs:documentation><xsl:value-of select="."/></xs:documentation>-->
437    </xsl:template>
438
439    <xsl:template match="@DisplayPriority">
440        <xsl:attribute name="ann:displaypriority">
441            <xsl:value-of select="."/>
442        </xsl:attribute>
443        <!--<xs:appinfo><DisplayPriority><xsl:value-of select="."/></DisplayPriority></xs:appinfo>-->
444    </xsl:template>
445
446    <xsl:template name="annotations">
447        <xsl:if test="@Documentation or @DisplayPriority">
448            <!--<xs:annotation>-->
449            <xsl:apply-templates select="@Documentation"/>
450            <xsl:apply-templates select="@DisplayPriority"/>
451            <!--</xs:annotation>-->
452        </xsl:if>
453    </xsl:template>
454   
455</xsl:stylesheet>
Note: See TracBrowser for help on using the repository browser.