source: CMDI-Interoperability/CMD2RDF/trunk/xsl/CMDRecord2RDF.xsl @ 5322

Last change on this file since 5322 was 5322, checked in by Menzo Windhouwer, 10 years ago

M xsl/CMDRecord2RDF.xsl
M xsl/CMDRecord2RDFcache.xsl

  • <if> should be <xsl:if>
  • pick the first component Hack: to deal with some invalid (Meertens) CMD records
File size: 14.7 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE rdf:RDF [
3    <!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
4    <!ENTITY rdfs 'http://www.w3.org/TR/WD-rdf-schema#'>
5    <!ENTITY xsd 'http://www.w3.org/2001/XMLSchema#'>
6    <!ENTITY cmdm 'http://www.clarin.eu/cmd/general.rdf#'>
7    <!ENTITY oa 'http://www.w3.org/ns/oa#'>
8]>
9<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:dcr="http://www.isocat.org/ns/dcr.rdf#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:cmd="http://www.clarin.eu/cmd/" xmlns:cmdm="http://www.clarin.eu/cmd/general.rdf#" xmlns:ore="http://www.openarchives.org/ore/terms/" xmlns:oa="http://www.w3.org/ns/oa#" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
10
11    <xsl:output method="xml" encoding="UTF-8"/>
12
13    <!-- allow to rewrite the urls -->
14    <xsl:param name="base_strip" select="base-uri()"/>
15    <xsl:param name="base_add" select="''"/>
16
17    <xsl:variable name="about" select="replace(if ($base_strip=base-uri()) then base-uri() else replace(base-uri(), $base_strip, $base_add),'([./])(xml|cmdi)$','$1rdf')"/>
18
19    <xsl:include href="CMD2RDF.xsl"/>
20
21    <xsl:template match="text()"/>
22
23    <!-- let's create some RDF -->
24    <xsl:template match="/cmd:CMD">
25        <rdf:RDF xml:base="{$about}">
26            <!-- The CMDI is seen as OA Annotation of a (set of) resource(s) -->
27            <oa:Annotation rdf:about="{$about}">
28                <xsl:apply-templates select="cmd:Resources" mode="resources"/>
29                <oa:hasBody>
30                    <xsl:apply-templates select="cmd:Components">
31                        <xsl:with-param name="context" tunnel="yes" select="''"/>
32                    </xsl:apply-templates>
33                </oa:hasBody>
34                <oa:motivatedBy rdf:resource="&oa;describing"/>
35                <xsl:apply-templates select="cmd:Resources" mode="other"/>
36            </oa:Annotation>
37            <!-- The CMDI is an ORE ResourceMap to other metadata descriptions -->
38            <xsl:if test="exists(cmd:Resources/ResourceProxyList/ResourceProxy[ResourceType='Metadata'])">
39                <ore:ResourceMap rdf:about="{$about}">
40                    <ore:describes>
41                        <ore:Aggregation>
42                            <xsl:apply-templates select="cmd:Resources" mode="metadata"/>
43                        </ore:Aggregation>
44                    </ore:describes>
45                </ore:ResourceMap>
46            </xsl:if>
47            <xsl:apply-templates select="cmd:Header"/>
48        </rdf:RDF>
49    </xsl:template>
50
51    <xsl:template match="cmd:MdCreator">
52        <rdf:Description rdf:about="{concat('#',generate-id((/cmd:CMD/cmd:Components/*)[1]))}">
53            <dc:creator>
54                <xsl:value-of select="."/>
55            </dc:creator>
56        </rdf:Description>
57    </xsl:template>
58
59    <xsl:template match="cmd:MdCreationDate">
60        <rdf:Description rdf:about="{concat('#',generate-id((/cmd:CMD/cmd:Components/*)[1]))}">
61            <dc:created>
62                <xsl:value-of select="."/>
63            </dc:created>
64        </rdf:Description>
65    </xsl:template>
66
67    <xsl:template match="cmd:MdSelfLink">
68        <rdf:Description rdf:about="{concat('#',generate-id((/cmd:CMD/cmd:Components/*)[1]))}">
69            <dc:identifier>
70                <xsl:value-of select="."/>
71            </dc:identifier>
72        </rdf:Description>
73    </xsl:template>
74
75    <xsl:template match="cmd:MdProfile">
76        <!-- TODO? -->
77    </xsl:template>
78
79    <xsl:template match="cmd:MdCollectionDisplayName">
80        <!-- TODO -->
81    </xsl:template>
82
83    <xsl:template match="text()" mode="resources"/>
84    <xsl:template match="cmd:ResourceProxy[cmd:ResourceType!='Resource']" mode="resources"/>
85    <xsl:template match="cmd:ResourceProxy[cmd:ResourceType='Resource']" mode="resources">
86        <oa:hasTarget>
87            <cmdm:Resource rdf:about="{cmd:ResourceRef}">
88                <xsl:if test="normalize-space(cmd:ResourceType/@mimetype)!=''">
89                    <cmdm:hasMimeType>
90                        <xsl:value-of select="cmd:ResourceType/@mimetype"/>
91                    </cmdm:hasMimeType>
92                </xsl:if>
93            </cmdm:Resource>
94        </oa:hasTarget>
95    </xsl:template>
96
97    <xsl:template match="text()" mode="metadata"/>
98    <xsl:template match="cmd:ResourceProxy[cmd:ResourceType!='Metadata']" mode="metadata"/>
99    <xsl:template match="cmd:ResourceProxy[cmd:ResourceType='Metadata']" mode="metadata">
100        <ore:aggregates rdf:resource="{cmd:ResourceRef}"/>
101        <!--
102        <cmdm:hasMimeType rdf:about="{ResourceRef}">
103            <xsl:value-of select="ResourceType/@mimetype"/>
104        </cmdm:hasMimeType>
105        -->
106    </xsl:template>
107
108    <xsl:template match="text()" mode="other"/>
109    <xsl:template match="cmd:ResourceProxy[cmd:ResourceType=('Resource','Metadata')]" mode="other"/>
110    <xsl:template match="cmd:ResourceProxy[not(cmd:ResourceType=('Resource','Metadata'))]" mode="other">
111        <xsl:element name="cmdm:has{cmd:ResourceType}">
112            <xsl:attribute name="rdf:resource" select="cmd:ResourceRef"/>
113        </xsl:element>
114        <!--
115        <cmdm:hasMimeType rdf:about="{ResourceRef}">
116            <xsl:value-of select="ResourceType/@mimetype"/>
117        </cmdm:hasMimeType>
118        -->
119    </xsl:template>
120
121    <!-- the CMD body -->
122    <xsl:template match="/cmd:CMD/cmd:Components">
123        <!-- get the profile id -->
124        <xsl:variable name="id">
125            <xsl:choose>
126                <xsl:when test="exists(/cmd:CMD/cmd:Header/cmd:MdProfile)">
127                    <!-- and ignore if there are multiple MdProfile and just take the first!!
128                         although probably this more a case for the schema validation!  -->
129                    <xsl:sequence select="cmd:id((/cmd:CMD/cmd:Header/cmd:MdProfile)[1])"/>
130                </xsl:when>
131                <xsl:when test="exists(/cmd:CMD/@xsi:schemaLocation)">
132                    <xsl:sequence select="cmd:id(/cmd:CMD/@xsi:schemaLocation)"/>
133                </xsl:when>
134                <xsl:otherwise>
135                    <xsl:message terminate="yes">
136                        <xsl:text>ERR: the CMDI record doesn't refer to its profile!</xsl:text>
137                    </xsl:message>
138                </xsl:otherwise>
139            </xsl:choose>
140        </xsl:variable>
141        <xsl:if test="not(starts-with($id,'clarin.eu:'))">
142            <xsl:text>ERR: the CMDI record doesn't refer to a profile in the CR!</xsl:text>
143        </xsl:if>
144        <!-- load the profile -->
145        <xsl:variable name="profile" select="cmd:profile($id)"/>
146        <!-- the base URL (the namespace in RDF/XML) of the RDF resources will change during traversal to the URL of the active profile/component -->
147        <xsl:variable name="ns" select="concat(cmd:ppath($id,'rdf'),'#')"/>
148        <!-- we traverse the profile/component scheme and find the matching instances -->
149        <xsl:apply-templates select="$profile/CMD_ComponentSpec/CMD_Component">
150            <xsl:with-param name="context" tunnel="yes" select="''"/>
151            <xsl:with-param name="ns" tunnel="yes" select="$ns"/>
152            <xsl:with-param name="instance" tunnel="yes" select="."/>
153        </xsl:apply-templates>
154    </xsl:template>
155
156    <!-- a CMD component -->
157    <xsl:template match="CMD_Component">
158        <xsl:param name="context" tunnel="yes"/>
159        <xsl:param name="ns" tunnel="yes"/>
160        <xsl:param name="instance" tunnel="yes"/>
161        <!-- if the component has its own id its something that can be shared by multiple profiles/components and has its own base RDF (namespace) -->
162        <xsl:variable name="local-ns">
163            <xsl:choose>
164                <xsl:when test="exists(@ComponentId)">
165                    <xsl:sequence select="concat(cmd:cpath(@ComponentId,'rdf'),'#')"/>
166                </xsl:when>
167                <xsl:otherwise>
168                    <xsl:sequence select="$ns"/>
169                </xsl:otherwise>
170            </xsl:choose>
171        </xsl:variable>
172        <!-- if the component has its own id its something that can be shared by multiple profiles/components a new context is started -->
173        <xsl:variable name="local-context">
174            <xsl:choose>
175                <xsl:when test="exists(@ComponentId)">
176                    <xsl:sequence select="''"/>
177                </xsl:when>
178                <xsl:otherwise>
179                    <xsl:sequence select="$context"/>
180                </xsl:otherwise>
181            </xsl:choose>
182        </xsl:variable>
183        <xsl:variable name="profile" select="."/>
184        <xsl:variable name="name" select="@name"/>
185        <!-- extend the context with this component -->
186        <xsl:variable name="id" select="cmd:path($local-context,$name)"/>
187        <!-- find the matching instances -->
188        <xsl:for-each select="$instance/*[local-name()=$name]">
189            <!-- create a class -->
190            <xsl:variable name="class">
191                <xsl:element name="{$id}" namespace="{$local-ns}">
192                    <xsl:attribute name="rdf:about" select="concat('#',generate-id(.))"/>
193                    <xsl:for-each select="tokenize(@ref,'\s+')">
194                        <xsl:variable name="res" select="."/>
195                        <cmdm:describesResource rdf:resource="{$instance/ancestor::cmd:CMD/cmd:Resources/cmd:ResourceProxyList/cmd:ResourceProxy[@id=$res]/cmd:ResourceRef}"/>
196                    </xsl:for-each>
197                    <!-- switch back from the instance to the profile -->
198                    <xsl:apply-templates select="$profile/*">
199                        <xsl:with-param name="context" tunnel="yes" select="$id"/>
200                        <xsl:with-param name="ns" tunnel="yes" select="$local-ns"/>
201                        <xsl:with-param name="instance" tunnel="yes" select="."/>
202                    </xsl:apply-templates>
203                </xsl:element>
204            </xsl:variable>
205            <!-- is this the root or not -->
206            <xsl:choose>
207                <xsl:when test="exists(parent::cmd:Components)">
208                    <xsl:copy-of select="$class"/>
209                </xsl:when>
210                <xsl:otherwise>
211                    <!-- use the generic RELcat related relationship for the nesting of components -->
212                    <cmdm:contains>
213                        <xsl:copy-of select="$class"/>
214                    </cmdm:contains>
215                </xsl:otherwise>
216            </xsl:choose>
217        </xsl:for-each>
218    </xsl:template>
219
220    <!-- a CMD element -->
221    <xsl:template match="CMD_Element">
222        <xsl:param name="context" tunnel="yes"/>
223        <xsl:param name="ns" tunnel="yes"/>
224        <xsl:param name="instance" tunnel="yes"/>
225        <xsl:variable name="profile" select="."/>
226        <xsl:variable name="name" select="@name"/>
227        <!-- extend the context with this element -->
228        <xsl:variable name="id" select="cmd:path($context,$name)"/>
229        <xsl:variable name="has" select="cmd:path($context,concat('has',@name))"/>
230        <!-- find the matching instances -->
231        <xsl:for-each select="$instance/*[local-name()=$name]">
232            <!-- use the generic RELcat related relationship for the nesting of the element in its component -->
233            <cmdm:contains>
234                <!-- a CMD element is a RDF class -->
235                <xsl:element name="{$id}" namespace="{$ns}">
236                    <xsl:attribute name="rdf:about" select="concat('#',generate-id(.))"/>
237                    <!-- the value is assigned to a propery of the CMD element RDF class -->
238                    <xsl:element name="{$has}ElementValue" namespace="{$ns}">
239                        <!-- map the CMD XSD datatype to a datatype supported by RDF -->
240                        <xsl:attribute name="rdf:datatype" select="concat('&xsd;',cmd:datatype($profile/@ValueScheme))"/>
241                        <!-- copy @xml:lang -->
242                        <xsl:copy-of select="@xml:lang"/>
243                        <!-- copy the literal -->
244                        <xsl:value-of select="."/>
245                    </xsl:element>
246                    <!-- if there is enum we also have an entity property -->
247                    <xsl:if test="exists($profile/ValueScheme/enumeration)">
248                        <xsl:element name="{$id}ElementEntity" namespace="{$ns}">
249                            <xsl:attribute name="rdf:resource" select="concat($ns,$id,'ValueScheme',$STEP,replace(.,'\s',''))"/>
250                        </xsl:element>
251                    </xsl:if>
252                    <!-- switch back from the instance to the profile to handle the attributes -->
253                    <xsl:apply-templates select="$profile/AttributeList/Attribute">
254                        <xsl:with-param name="context" tunnel="yes" select="$id"/>
255                        <xsl:with-param name="ns" tunnel="yes" select="$ns"/>
256                        <xsl:with-param name="instance" tunnel="yes" select="."/>
257                    </xsl:apply-templates>
258                </xsl:element>
259            </cmdm:contains>
260        </xsl:for-each>
261    </xsl:template>
262
263    <!-- a CMD attribute -->
264    <xsl:template match="Attribute">
265        <xsl:param name="context" tunnel="yes"/>
266        <xsl:param name="ns" tunnel="yes"/>
267        <xsl:param name="instance" tunnel="yes"/>
268        <xsl:variable name="profile" select="."/>
269        <xsl:variable name="name" select="Name"/>
270        <!-- extend the context with this attribute -->
271        <xsl:variable name="id" select="concat(cmd:path($context,$name),'Attribute')"/>
272        <xsl:variable name="has" select="concat(cmd:path($context,concat('has',$name)),'Attribute')"/>
273        <!-- find the matching instances -->
274        <xsl:for-each select="$instance/@*[local-name()=$name]">
275            <cmdm:containsAttribute>
276                <xsl:element name="{$id}" namespace="{$ns}">
277                    <xsl:attribute name="rdf:about" select="concat('#',generate-id(.))"/>
278                    <xsl:element name="{$has}Value" namespace="{$ns}">
279                        <!-- map the CMD XSD datatype to a datatype supported by RDF -->
280                        <xsl:attribute name="rdf:datatype" select="concat('&xsd;',cmd:datatype($profile/Type))"/>
281                        <!-- copy the literal -->
282                        <xsl:value-of select="."/>
283                    </xsl:element>
284                    <xsl:if test="exists($profile/ValueScheme/enumeration)">
285                        <xsl:element name="{$has}Entity" namespace="{$ns}">
286                            <xsl:attribute name="rdf:resource" select="concat($ns,$id,'ValueScheme',$STEP,replace(.,'\s',''))"/>
287                        </xsl:element>
288                    </xsl:if>
289                </xsl:element>
290            </cmdm:containsAttribute>
291        </xsl:for-each>
292    </xsl:template>
293
294</xsl:stylesheet>
Note: See TracBrowser for help on using the repository browser.