source: metadata/trunk/toolkit/xslt/comp2schema-v2/comp2schema.xsl @ 2626

Last change on this file since 2626 was 2626, checked in by twagoo, 11 years ago

Modified comp2schema XSLT to include the component specification's <Header> element as an appInfo annotation to the resulting XSD.

  • Property svn:executable set to *
  • Property svn:keywords set to
    Date
    Rev
File size: 17.6 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2
3<!--
4    $Rev: 2626 $
5    $Date: 2013-02-26 07:55:17 +0000 (Tue, 26 Feb 2013) $
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:complexType>
100                        </xs:element>
101
102                        <!-- Generate the footer -->
103                    </xs:sequence>
104                   
105                    <!-- CMD version -->
106                    <xs:attribute name="CMDVersion" fixed="{$CMDVersion}" use="required"/>
107                   
108                </xs:complexType>
109            </xs:element>
110        </xs:schema>
111
112    </xsl:template>
113   
114    <xsl:template match="*" mode="Header">
115        <xsl:element name="ann:{name()}" namespace="http://www.clarin.eu">
116            <xsl:value-of select="text()"/>
117            <xsl:apply-templates select="*" mode="Header" />
118        </xsl:element>
119    </xsl:template>
120
121    <xsl:template name="CreateComplexTypes">
122        <xsl:apply-templates select="CMD_Component" mode="types"/>
123    </xsl:template>
124
125
126    <!-- Start types -->
127
128    <!-- skip all text nodes -->
129    <xsl:template match="text()" mode="types"/>
130
131    <!-- first pass: create the complex types on top of the resulting XSD -->
132    <!-- ignore when this ValueScheme is descendant of an Attribute as we do not allow CV-attributes in a CV-list -->
133    <xsl:template match="ValueScheme[not(../../Attribute)]" mode="types">
134
135        <!-- create a unique suffix (the path to the element) to ensure the unicity of the types to be created -->
136        <xsl:variable name="uniquePath">
137            <xsl:call-template name="printComponentId">
138                <!-- start from the CMD_Element above and go upwards in the tree -->
139                <xsl:with-param name="node" select=".."/>
140            </xsl:call-template>
141        </xsl:variable>
142
143        <!-- first auto-generate a name for the simpletype to be extended -->
144        <xs:simpleType name="simpletype{$uniquePath}">
145            <xs:restriction base="xs:string">
146                <xsl:apply-templates select="pattern"/>
147                <xsl:apply-templates select="enumeration"/>
148            </xs:restriction>
149        </xs:simpleType>
150
151        <!--  then auto-derive a complextype for the attributes -->
152        <xs:complexType name="complextype{$uniquePath}">
153            <xs:simpleContent>
154                <xs:extension base="cmd:simpletype{$uniquePath}">
155                    <!-- now look at the attribute list of the CMD_Element parent of this ValueScheme-->
156                    <xsl:apply-templates select="parent::node()/AttributeList/Attribute"/>
157                    <!--<xs:attribute name="attributeName" type="xs:anyURI"/>-->
158                </xs:extension>
159            </xs:simpleContent>
160        </xs:complexType>
161
162    </xsl:template>
163
164    <!-- Stop types -->
165
166    <!-- create a unique identifier from the current ValueScheme element -->
167    <xsl:template name="printComponentId">
168        <xsl:param name="node"/>
169        <xsl:text>-</xsl:text>
170
171        <xsl:choose>
172
173            <!-- deeper recursion needed -->
174            <xsl:when test="$node[not(@ComponentId)]">
175
176                <xsl:choose>
177                    <!-- element has name, add it to the type name and recurse upwards in the tree -->
178                    <xsl:when test="name($node) = 'CMD_Element'">
179                        <xsl:value-of select="$node/attribute::name"/>
180                    </xsl:when>
181                    <!-- "worst" case: embedded anonymous component without ComponentId: use the xpath -->
182                    <xsl:when test="name($node)  = 'CMD_Component'">
183                        <xsl:value-of select="count($node/preceding-sibling::*)"/>
184                    </xsl:when>
185                </xsl:choose>
186
187                <!-- recursive call -->
188                <xsl:call-template name="printComponentId">
189                    <xsl:with-param name="node" select="$node/.."/>
190                </xsl:call-template>
191
192            </xsl:when>
193
194            <!-- end of recursion: component has ComponentId -->
195            <xsl:otherwise>
196                <xsl:value-of select="replace($node/attribute::ComponentId, ':', '.')"/>
197            </xsl:otherwise>
198
199        </xsl:choose>
200
201    </xsl:template>
202
203
204
205    <!-- convert all components -->
206    <xsl:template match="CMD_Component">
207        <!--  use override values if specified in parent <CMD_Component filename=...> , otherwise use default cardinality for this component -->
208        <xsl:param name="MinOccurs" select="@CardinalityMin"/>
209        <xsl:param name="MaxOccurs" select="@CardinalityMax"/>
210
211        <xs:element name="{@name}">
212           
213            <xsl:if test="$MinOccurs">
214                <xsl:attribute name="minOccurs">
215                    <xsl:value-of select="$MinOccurs"/>
216                </xsl:attribute>
217            </xsl:if>
218            <xsl:if test="$MaxOccurs">
219                <xsl:attribute name="maxOccurs">
220                    <xsl:value-of select="$MaxOccurs"/>
221                </xsl:attribute>
222            </xsl:if>
223            <!-- Add a dcr:datcat if a ConceptLink attribute is found -->
224            <xsl:apply-templates select="./@ConceptLink"/>
225
226            <xs:complexType>
227                <xs:sequence>
228                    <!-- process all elements at this level -->
229                    <xsl:apply-templates select="./CMD_Element"/>
230                    <!-- process all components at one level deeper (recursive call) -->
231                    <xsl:apply-templates select="./CMD_Component"/>
232                </xs:sequence>
233                <!-- DISABLED (Arbil needs to handle it first) allow @xml:base as a residue of XInclude processing -X->
234                <xs:attribute ref="xml:base"/>
235                -->
236                <!-- @ref to the resource proxy (TODO: put this in the CMD namespace, i.e., @cmd:ref -->                 
237                <xs:attribute name="ref" type="xs:IDREFS"/>
238                <xsl:apply-templates select="./AttributeList/Attribute"/>
239                <xsl:if test="@ComponentId">
240                    <xs:attribute name="ComponentId" type="xs:anyURI" fixed="{@ComponentId}"/>
241                </xsl:if>
242            </xs:complexType>
243
244        </xs:element>
245
246    </xsl:template>
247
248    <!-- Process all CMD_Elements, its attributes and children -->
249
250    <!-- Highest complexity: both attributes and a valuescheme, link to the type we created during the preprocessing of the ValueScheme -->
251    <xsl:template match="CMD_Element[./AttributeList][./ValueScheme]" priority="3">
252        <xs:element name="{@name}">
253
254            <!-- process all Documentation and DisplayPriority attributes -->
255            <xsl:call-template name="annotations"/>
256
257            <xsl:apply-templates select="@ConceptLink"/>
258            <xsl:apply-templates select="@CardinalityMin"/>
259            <xsl:apply-templates select="@CardinalityMax"/>
260            <xsl:apply-templates select="ValueScheme"/>
261
262        </xs:element>
263    </xsl:template>
264
265    <!-- Medium complexity: attributes (or Multilingual field) but no valuescheme, can be arranged inline -->
266    <xsl:template match="CMD_Element[./AttributeList or ./@Multilingual]" priority="2">
267        <xs:element name="{@name}">
268
269            <xsl:apply-templates select="@Multilingual"/>
270            <xsl:apply-templates select="@ConceptLink"/>
271            <xsl:apply-templates select="@CardinalityMin"/>
272            <xsl:apply-templates select="@CardinalityMax"/>
273
274            <!-- process all Documentation and DisplayPriority attributes -->
275            <xsl:call-template name="annotations"/>
276
277            <!-- <xsl:apply-templates select= "and(not(@type) and @*)"/> -->
278            <xs:complexType>
279                <xs:simpleContent>
280                    <xs:extension base="{concat('xs:',@ValueScheme)}">
281                        <xsl:apply-templates select="./AttributeList/Attribute"/>
282                        <!-- temporarily disabled -->
283                        <xsl:if test="./@Multilingual='true'">
284                            <xs:attribute ref="xml:lang" />
285                        </xsl:if>
286                    </xs:extension>
287                </xs:simpleContent>
288            </xs:complexType>
289        </xs:element>
290    </xsl:template>
291
292
293    <!-- Simple case: no attributes and no value scheme, 1-to-1 transform to an xs:element, just rename element and attributes -->
294    <xsl:template match="CMD_Element" priority="1">
295        <xsl:element name="xs:element">
296            <xsl:apply-templates
297                select="@*[name() != 'Documentation' and name() != 'DisplayPriority'] | node()"/>
298            <!-- process all Documentation and DisplayPriority attributes -->
299            <xsl:call-template name="annotations"/>
300        </xsl:element>
301    </xsl:template>
302
303    <!-- end of CMD_Element templates -->
304
305    <!-- second pass, now link to the earlier created complextype definition -->
306    <xsl:template match="ValueScheme">
307        <xsl:variable name="uniquePath">
308            <xsl:call-template name="printComponentId">
309                <!-- start from the CMD_Element above and go upwards in the tree -->
310                <xsl:with-param name="node" select=".."/>
311            </xsl:call-template>
312        </xsl:variable>
313
314        <xsl:attribute name="type">
315            <xsl:text>cmd:complextype</xsl:text>
316            <xsl:value-of select="$uniquePath"/>
317        </xsl:attribute>
318    </xsl:template>
319
320    <!-- Convert the AttributeList into real XSD attributes -->
321    <xsl:template match="AttributeList/Attribute">
322        <xs:attribute name="{./Name}">
323
324            <!-- Add a dcr:datcat if a ConceptLink element is found -->
325            <xsl:if test="normalize-space(./ConceptLink)!=''">
326                <xsl:attribute name="dcr:datcat">
327                    <xsl:value-of select="./ConceptLink" />
328                </xsl:attribute>
329            </xsl:if>
330           
331            <!-- add some extra stuff if we have a CV attribute -->
332            <xsl:choose>
333
334                <!-- complex situation: CV or regex -->
335                <xsl:when test="./ValueScheme">
336                    <xs:simpleType>
337                        <xs:restriction base="xs:string">
338                            <!-- now use general rules for enumeration or pattern -->
339                            <xsl:apply-templates select="./ValueScheme/*"/>
340                        </xs:restriction>
341                    </xs:simpleType>
342                </xsl:when>
343
344                <!-- simple situation: just a basic type -->
345                <xsl:otherwise>
346                    <xsl:attribute name="type">
347                        <xsl:value-of select="concat('xs:',./Type)"/>
348                    </xsl:attribute>
349                </xsl:otherwise>
350
351            </xsl:choose>
352
353        </xs:attribute>
354    </xsl:template>
355   
356   
357    <!-- Convert patterns -->
358    <xsl:template match="pattern">
359        <xs:pattern value="{self::node()}"/>
360    </xsl:template>
361
362    <!-- Convert enumerations -->
363    <xsl:template match="enumeration">
364
365        <xsl:for-each select="item">
366            <xs:enumeration value="{node()}">
367                <!-- Add a dcr:datcat if a ConceptLink attribute is found -->
368                <xsl:apply-templates select="./@ConceptLink"/>
369                <xsl:apply-templates select="./@AppInfo"/>
370            </xs:enumeration>
371        </xsl:for-each>
372    </xsl:template>
373
374
375    <!--  default action: keep the attributes like they are -->
376    <xsl:template match="@*|node()">
377        <xsl:copy/>
378    </xsl:template>
379
380
381    <!-- except for those attributes we want to be renamed -->
382    <xsl:template match="@CardinalityMin">
383        <xsl:attribute name="minOccurs">
384            <xsl:value-of select="."/>
385        </xsl:attribute>
386    </xsl:template>
387
388    <xsl:template match="@CardinalityMax">
389        <xsl:attribute name="maxOccurs">
390            <xsl:value-of select="."/>
391        </xsl:attribute>
392    </xsl:template>
393
394    <!-- start multilinguality part -->
395
396    <!-- if the multilingual attribute is there and the field has the type string, allow multuple occurrences -->
397    <xsl:template match="@Multilingual[../@ValueScheme='string'][. = 'true'] ">
398        <!-- temporarily disabled until Arbil can deal with the <xs:import> to cope with xml:lang -->
399        <xsl:attribute name="maxOccurs">
400            <xsl:value-of>unbounded</xsl:value-of>
401        </xsl:attribute>
402    </xsl:template>
403
404    <xsl:template match="@Multilingual">
405        <!-- do nothing - only influences maxOccurs if it is true and if it is a a string element -->
406    </xsl:template>
407
408    <xsl:template match="@CardinalityMax[../@Multilingual='true'][../@ValueScheme='string']">
409        <!-- do nothing - maxOccurs should be set by Multilingual rule for strings -->
410    </xsl:template>
411
412    <!-- end multilinguality part -->
413
414    <xsl:template match="@ConceptLink">
415        <xsl:attribute name="dcr:datcat">
416            <xsl:value-of select="."/>
417        </xsl:attribute>
418    </xsl:template>
419
420    <xsl:template match="@AppInfo">
421        <xsl:attribute name="ann:label"><xsl:value-of select="."/></xsl:attribute>
422    </xsl:template>
423
424    <xsl:template match="@ValueScheme">
425        <xsl:attribute name="type">
426            <xsl:value-of select="concat('xs:',.)"/>
427        </xsl:attribute>
428    </xsl:template>
429
430    <xsl:template match="@Documentation">
431        <xsl:attribute name="ann:documentation">
432            <xsl:value-of select="."/>
433        </xsl:attribute>
434        <!--<xs:documentation><xsl:value-of select="."/></xs:documentation>-->
435    </xsl:template>
436
437    <xsl:template match="@DisplayPriority">
438        <xsl:attribute name="ann:displaypriority">
439            <xsl:value-of select="."/>
440        </xsl:attribute>
441        <!--<xs:appinfo><DisplayPriority><xsl:value-of select="."/></DisplayPriority></xs:appinfo>-->
442    </xsl:template>
443
444    <xsl:template name="annotations">
445        <xsl:if test="@Documentation or @DisplayPriority">
446            <!--<xs:annotation>-->
447            <xsl:apply-templates select="@Documentation"/>
448            <xsl:apply-templates select="@DisplayPriority"/>
449            <!--</xs:annotation>-->
450        </xsl:if>
451    </xsl:template>
452   
453</xsl:stylesheet>
Note: See TracBrowser for help on using the repository browser.