source: metadata/trunk/toolkit/src/main/resources/toolkit/xslt/comp2schema.xsl @ 6859

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

M toolkit/src/main/resources/toolkit/xslt/comp2schema.xsl

  • new cues namespace
  • clearer copy of cue attributes

M toolkit/src/test/resources/toolkit/CMD/profiles/components-invalid.xml
M toolkit/src/test/resources/toolkit/successor/profiles/successor-invalid.xml
M toolkit/src/test/resources/toolkit/successor/profiles/successor-valid.xml
M toolkit/src/test/resources/toolkit/Adelheid/records/Adelheid_1_2-invalid.cmdi
M toolkit/src/test/resources/toolkit/Adelheid/profiles/clarin.eu:cr1:p_1311927752306_1_2.xml
M toolkit/src/main/resources/toolkit/xsd/cmd-component.xsd
M toolkit/src/main/resources/toolkit/upgrade/cmd-component-1_1-to-1_2.xsl

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