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

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

Now follow the default Maven layout, so we can easily leverage standard testing facilities.

First test based on Adelheid 1.1 profile and record tests:

  • upgrade of a profile conforms to 1.2 cmd-component.xsd
  • upgrade of a record conforms to the 1.2 profile XSD

Additional records collected at the CLARIN Centre Meeting May 2015 are also added, but still need to be worked into tests.

  • 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: 6255 $
5    $Date: 2015-06-01 10:18:22 +0000 (Mon, 01 Jun 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:dcr="http://www.isocat.org/ns/dcr" xmlns:ann="http://www.clarin.eu" xmlns:cmd="http://www.clarin.eu/cmd/1" xmlns:cue="http://www.clarin.eu/cmdi/cues/display/1.0">
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="ann:{name()}" namespace="http://www.clarin.eu">
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="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            <!-- Add a dcr:datcat if a ConceptLink element is found -->
304            <xsl:if test="normalize-space(@ConceptLink)!=''">
305                <xsl:attribute name="dcr:datcat">
306                    <xsl:value-of select="@ConceptLink"/>
307                </xsl:attribute>
308            </xsl:if>
309
310            <!-- add some extra stuff if we have a CV attribute -->
311            <xsl:choose>
312
313                <!-- complex situation: CV or regex -->
314                <xsl:when test="exists(./ValueScheme/(Vocabulary/enumeration|pattern))">
315
316                    <xs:annotation>
317                        <xsl:apply-templates select="Documentation"/>
318                    </xs:annotation>
319
320                    <xs:simpleType>
321                        <xs:restriction base="xs:string">
322                            <!-- now use general rules for enumeration or pattern -->
323                            <xsl:apply-templates select="./ValueScheme/*"/>
324                        </xs:restriction>
325                    </xs:simpleType>
326                </xsl:when>
327
328                <!-- simple situation: just a basic type -->
329                <xsl:otherwise>
330                    <xsl:attribute name="type">
331                        <xsl:value-of select="concat('xs:',@ValueScheme)"/>
332                    </xsl:attribute>
333                   
334                    <xs:annotation>
335                        <xsl:apply-templates select="Documentation"/>
336                    </xs:annotation>
337                   
338                </xsl:otherwise>
339
340            </xsl:choose>
341
342        </xs:attribute>
343    </xsl:template>
344
345    <!-- Convert patterns -->
346    <xsl:template match="pattern">
347        <xs:pattern value="{self::node()}"/>
348    </xsl:template>
349
350    <!-- Convert enumerations -->
351    <xsl:template match="Vocabulary">
352        <xsl:apply-templates select="@*|node()"/>
353    </xsl:template>
354   
355    <xsl:template match="enumeration">
356        <xsl:for-each select="item">
357            <xs:enumeration value="{node()}">
358                <xsl:apply-templates select="./@ConceptLink"/>
359                <xsl:apply-templates select="./@AppInfo"/>
360            </xs:enumeration>
361        </xsl:for-each>
362    </xsl:template>
363
364    <!--  default action: keep the attributes like they are -->
365    <xsl:template match="@*|node()">
366        <xsl:copy/>
367    </xsl:template>
368
369    <!-- except for those attributes we want to be renamed -->
370    <xsl:template match="@CardinalityMin">
371        <xsl:attribute name="minOccurs">
372            <xsl:value-of select="."/>
373        </xsl:attribute>
374    </xsl:template>
375
376    <xsl:template match="@CardinalityMax">
377        <xsl:attribute name="maxOccurs">
378            <xsl:value-of select="."/>
379        </xsl:attribute>
380    </xsl:template>
381   
382    <!-- the root component can't have cardinality constraints -->
383    <xsl:template match="ComponentSpec/Component/@CardinalityMin" priority="1"/>
384   
385    <xsl:template match="ComponentSpec/Component/@CardinalityMax"/>
386   
387    <!-- start multilinguality part -->
388
389    <!-- if the multilingual attribute is there and the field has the type string, allow multiple occurrences -->
390    <xsl:template match="@Multilingual[../@ValueScheme='string'][. = 'true'] ">
391        <xsl:attribute name="maxOccurs">
392            <xsl:value-of>unbounded</xsl:value-of>
393        </xsl:attribute>
394    </xsl:template>
395
396    <xsl:template match="@Multilingual">
397        <!-- do nothing - only influences maxOccurs if it is true and if it is a a string element -->
398    </xsl:template>
399
400    <xsl:template match="@CardinalityMax[../@Multilingual='true'][../@ValueScheme='string']">
401        <!-- do nothing - maxOccurs should be set by Multilingual rule for strings -->
402    </xsl:template>
403
404    <!-- end multilinguality part -->
405
406    <!-- Add a @dcr:datcat if a ConceptLink attribute is found -->
407    <xsl:template match="@ConceptLink">
408        <xsl:attribute name="dcr:datcat">
409            <xsl:value-of select="."/>
410        </xsl:attribute>
411    </xsl:template>
412
413    <xsl:template match="@AppInfo">
414        <xsl:attribute name="ann:label">
415            <xsl:value-of select="."/>
416        </xsl:attribute>
417    </xsl:template>
418
419    <xsl:template match="@ValueScheme">
420        <xsl:attribute name="type">
421            <xsl:value-of select="concat('xs:',.)"/>
422        </xsl:attribute>
423    </xsl:template>
424   
425    <xsl:template match="Vocabulary/@URI">
426        <xsl:attribute name="ann:Vocabulary">
427            <xsl:value-of select="."/>
428        </xsl:attribute>
429    </xsl:template>
430
431    <xsl:template match="@ValueProperty|@ValueLanguage">
432        <xsl:attribute name="ann:{local-name()}">
433            <xsl:value-of select="."/>
434        </xsl:attribute>
435    </xsl:template>
436   
437    <xsl:template match="Documentation">
438        <xs:documentation>
439            <xsl:copy-of select="@xml:lang"/>
440            <xsl:value-of select="."/>
441        </xs:documentation>
442    </xsl:template>
443
444    <xsl:template match="@AutoValue">
445        <xsl:attribute name="ann:AutoValue">
446            <xsl:value-of select="."/>
447        </xsl:attribute>
448    </xsl:template>
449   
450    <xsl:template match="@cue:DisplayPriority" priority="1">
451        <xsl:attribute name="ann:displaypriority">
452            <xsl:value-of select="."/>
453        </xsl:attribute>
454    </xsl:template>
455
456    <xsl:template match="@cue:*">
457        <xsl:attribute name="ann:{local-name()}">
458            <xsl:value-of select="."/>
459        </xsl:attribute>
460    </xsl:template>
461   
462    <xsl:template name="annotations">
463        <xsl:apply-templates select="@AutoValue"/>
464        <xsl:apply-templates select="@cue:*"/>
465    </xsl:template>
466
467</xsl:stylesheet>
Note: See TracBrowser for help on using the repository browser.