Project

General

Profile

« Previous | Next » 

Revision 4944

Bug 3835: Design and implement OAI-PMH compliant harvest subsystem
Add support for request parameter "metadataPrefix=eml". This returns EML 2.1.0 records in an OAI-PMH format. EML 2.0.0 and 2.0.1 documents are first transformed to EML 2.1.0 using the eml201to210.xsl stylesheet that is packaged with the EML Utilities.

View differences:

lib/oaipmh/eml201to210.xsl
1
<?xml version="1.0"?>
2
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3
  xmlns:eml="eml://ecoinformatics.org/eml-2.1.0" version="1.0">
4
  <xsl:output method="xml" indent="yes"></xsl:output>
5
  <!--<xsl:strip-space elements="*"></xsl:strip-space>-->
6
  <xsl:param name="package-id" select="'newID'"/>
7
	
8
  <xsl:template match="/* ">
9
    <!--handle top level element-->
10
    <xsl:element name="eml:eml">   
11
      <!--<xsl:copy-of select="@*"></xsl:copy-of>-->
12
      <!--<xsl:attribute name="xsi:schemaLocation">eml://ecoinformatics.org/eml-2.1.0 eml.xsd</xsl:attribute>-->
13

  
14
	  <!--<xsl:copy-of select="namespace::*[not(starts-with(.,'eml://ecoinformatics.org/')) or . != 'http://www.w3.org/2001/XMLSchema-instance']"/>-->
15
      <xsl:for-each select="@*">
16
	   <xsl:choose>
17
	    <xsl:when test="namespace-uri()='http://www.w3.org/2001/XMLSchema-instance'">
18
        <xsl:attribute name="xsi:{local-name()}" namespace="{namespace-uri()}">
19
          <xsl:variable name="value" select="."></xsl:variable>
20
          <xsl:choose>
21
            <!--change eml200 and stmml to eml210 and stmml-1.1 in attribute-->
22
            <xsl:when test="contains($value, &quot;eml://ecoinformatics.org/eml-2.0.0&quot;)">
23
              <xsl:variable name="first-replace">
24
                 <xsl:call-template name="replace-string">
25
                    <xsl:with-param name="text" select="$value"></xsl:with-param>
26
                    <xsl:with-param name="replace" select="'eml://ecoinformatics.org/eml-2.0.0'"></xsl:with-param>
27
                    <xsl:with-param name="with" select="'eml://ecoinformatics.org/eml-2.1.0'"></xsl:with-param>
28
                 </xsl:call-template>
29
			   </xsl:variable>
30
			   <xsl:variable name="second-replace">
31
                 <xsl:call-template name="replace-string">
32
                    <xsl:with-param name="text" select="$first-replace"></xsl:with-param>
33
                    <xsl:with-param name="replace" select="'http://www.xml-cml.org/schema/stmml'"></xsl:with-param>
34
                    <xsl:with-param name="with" select="'http://www.xml-cml.org/schema/stmml-1.1'"></xsl:with-param>
35
                 </xsl:call-template>
36
			   </xsl:variable>
37
				<xsl:value-of select="$second-replace"></xsl:value-of>
38
            </xsl:when>
39
			 <!--change eml201 and stmml to eml210 and stmml-1.1 in attribute-->
40
            <xsl:when test="contains($value, 'eml://ecoinformatics.org/eml-2.0.1') or contains($value, 'http://www.xml-cml.org/schema/stmml')">
41
			  <xsl:variable name="first-replace">
42
                 <xsl:call-template name="replace-string">
43
                    <xsl:with-param name="text" select="$value"></xsl:with-param>
44
                    <xsl:with-param name="replace" select="'eml://ecoinformatics.org/eml-2.0.1'"></xsl:with-param>
45
                    <xsl:with-param name="with" select="'eml://ecoinformatics.org/eml-2.1.0'"></xsl:with-param>
46
                 </xsl:call-template>
47
			   </xsl:variable>
48
			   <xsl:variable name="second-replace">
49
                 <xsl:call-template name="replace-string">
50
                    <xsl:with-param name="text" select="$first-replace"></xsl:with-param>
51
                    <xsl:with-param name="replace" select="'http://www.xml-cml.org/schema/stmml'"></xsl:with-param>
52
                    <xsl:with-param name="with" select="'http://www.xml-cml.org/schema/stmml-1.1'"></xsl:with-param>
53
                 </xsl:call-template>
54
			   </xsl:variable>
55
				<xsl:value-of select="$second-replace"></xsl:value-of>
56
            </xsl:when>
57
            <xsl:otherwise>
58
              <xsl:value-of select="."></xsl:value-of>
59
            </xsl:otherwise>
60
          </xsl:choose>
61
        </xsl:attribute>
62
		</xsl:when>
63
		<xsl:otherwise>
64
            <xsl:choose>
65
               <xsl:when test="name()='packageId'">
66
				   <!-- handle package id: if there is no given packageid, it will use the old one. Otherwise, using the given id-->
67
			       <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
68
					    <xsl:choose>
69
							<xsl:when test="$package-id='newID'">
70
								<xsl:value-of select="."/>
71
							</xsl:when>
72
							<xsl:otherwise>
73
								<xsl:value-of select="$package-id"/>
74
							</xsl:otherwise>
75
						</xsl:choose>
76
			       </xsl:attribute>
77
               </xsl:when>
78
               <xsl:otherwise>
79
				  <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
80
                        <xsl:value-of select="."/>
81
                   </xsl:attribute> 
82
               </xsl:otherwise>
83
            </xsl:choose>
84
		</xsl:otherwise>
85
       </xsl:choose>
86
      </xsl:for-each>
87
      <!--<xsl:attribute name="xsi:schemaLocation">
88
		  <xsl:value-of select='translate(@xsi:schemaLocation, "eml-2.0.1", "eml-2.1.0")'/>
89
	  </xsl:attribute>-->
90
      <!-- move the access sub tree to top level-->
91
      <xsl:apply-templates mode="copy-top-access-tree" select="/*/dataset/access"></xsl:apply-templates>
92
      <xsl:apply-templates mode="copy-top-access-tree" select="/*/citation/access"></xsl:apply-templates>
93
      <xsl:apply-templates mode="copy-top-access-tree" select="/*/software/access"></xsl:apply-templates>
94
      <xsl:apply-templates mode="copy-top-access-tree" select="/*/protocol/access"></xsl:apply-templates>
95

  
96
      <xsl:for-each select="/*/*">
97
        <xsl:choose>
98
          <xsl:when test="name()='dataset'">
99
            <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
100
              <xsl:copy-of select="@*"></xsl:copy-of>
101
              <xsl:apply-templates mode="handle-elements-under-main-module" select="."
102
              ></xsl:apply-templates>
103
            </xsl:element>
104
          </xsl:when>
105

  
106
          <xsl:when test="name()='citation'">
107
            <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
108
              <xsl:copy-of select="@*"></xsl:copy-of>
109
              <xsl:apply-templates mode="handle-elements-under-main-module" select="."
110
              ></xsl:apply-templates>
111
            </xsl:element>
112
          </xsl:when>
113

  
114
          <xsl:when test="name()='software'">
115
            <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
116
              <xsl:copy-of select="@*"></xsl:copy-of>
117
              <xsl:apply-templates mode="handle-elements-under-main-module" select="."
118
              ></xsl:apply-templates>
119
            </xsl:element>
120
          </xsl:when>
121

  
122
          <xsl:when test="name()='protocol'">
123
            <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
124
              <xsl:copy-of select="@*"></xsl:copy-of>
125
              <xsl:apply-templates mode="handle-elements-under-main-module" select="."
126
              ></xsl:apply-templates>
127
            </xsl:element>
128
          </xsl:when>
129

  
130
          <xsl:when test="name()='additionalMetadata'">
131
            <xsl:apply-templates mode="handle-additionalMetadata" select="."></xsl:apply-templates>
132
          </xsl:when>
133

  
134
        </xsl:choose>
135
      </xsl:for-each>
136
    </xsl:element>
137
	 <xsl:message terminate="no">
138
		 <xsl:call-template name="output_message4_warn"/>
139
	  </xsl:message>
140
  </xsl:template>
141

  
142
  <!-- handle make changes under main module (dataset, citation, protocol and software) -->
143
  <xsl:template mode="handle-elements-under-main-module" match="*">
144
    <xsl:for-each select="./*">
145
      <xsl:choose>
146
        <xsl:when test="name()='access'">
147
          <xsl:apply-templates mode="do-nothing" select="."></xsl:apply-templates>
148
        </xsl:when>
149
        <xsl:otherwise>
150
          <xsl:apply-templates select="."></xsl:apply-templates>
151
        </xsl:otherwise>
152
      </xsl:choose>
153
    </xsl:for-each>
154
  </xsl:template>
155

  
156
  <!-- main template which will copy nodes recursively-->
157
  <xsl:template match="*">
158
    <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
159
      <xsl:copy-of select="@*"></xsl:copy-of>
160
      <xsl:apply-templates></xsl:apply-templates>
161
    </xsl:element>
162
  </xsl:template>
163

  
164
  <!-- fixing attributeList/attribute/measurementScale/datetime -> .../dateTime -->
165
  <xsl:template match="attributeList/attribute/measurementScale/datetime">
166
    <xsl:element name="dateTime" namespace="{namespace-uri(.)}">
167
      <xsl:copy-of select="@*"></xsl:copy-of>
168
      <xsl:apply-templates mode="copy-no-ns" select="./*"></xsl:apply-templates>
169
    </xsl:element>
170
  </xsl:template>
171

  
172
  <!-- change the name of element form method to methods -->
173
  <xsl:template match="dataTable/method | spatialRaster/method | spatialVector/method 
174
	  | view/method | storedProcedure/method | otherEntity/method">
175
    <xsl:element name="methods" namespace="{namespace-uri(.)}">
176
      <xsl:copy-of select="@*"></xsl:copy-of>
177
      <xsl:apply-templates mode="copy-no-ns-with-access-move" select="./*"></xsl:apply-templates>
178
    </xsl:element>
179
  </xsl:template>
180

  
181
  <!-- change the name of element form method to methods -->
182
  <xsl:template match="attribute/method">
183
    <xsl:element name="methods" namespace="{namespace-uri(.)}">
184
      <xsl:copy-of select="@*"></xsl:copy-of>
185
      <xsl:apply-templates mode="copy-no-ns-with-access-move" select="./*"></xsl:apply-templates>
186
    </xsl:element>
187
  </xsl:template>
188
	
189
	
190
	<!-- since under element "method", it can have distribution access movement, so this template will handle that-->
191
    <!-- copy node and children without namespace -->
192
  <xsl:template mode="copy-no-ns-with-access-move" match="*">
193
	 <xsl:choose>
194
		 <xsl:when test="name()='distribution' and name(parent::node())='implementation' and name(../..)='software'">			  
195
			 <xsl:call-template name="move-access"/>
196
		  </xsl:when>
197
		 <xsl:otherwise>
198
		      <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
199
                <xsl:copy-of select="@*"></xsl:copy-of>
200
                <xsl:apply-templates mode="copy-no-ns-with-access-move"></xsl:apply-templates>
201
              </xsl:element>
202
		 </xsl:otherwise>
203
	 </xsl:choose>   
204
  </xsl:template>
205

  
206
     <!--template to match physical/distribution and software/implementation/distribution which need to move around access module-->
207
	<xsl:template match="physical/distribution | software/implementation/distribution">
208
		<xsl:call-template name="move-access"/>
209
	</xsl:template>
210
	
211
  <!-- Move the access tree of data file level from additionalMetadata part to physical/distribution or software/implementation/distribution part.
212
           If we find the id of physical/distribution is in aditionalMetadata/describe and it 
213
             has sibling of access subtree, copy the subtree to physical/distribution -->
214
  <xsl:template name="move-access">
215
    <xsl:element name="distribution" namespace="{namespace-uri(.)}">
216
      <xsl:copy-of select="@*"></xsl:copy-of>
217
      <xsl:apply-templates mode="copy-no-ns" select="./*"></xsl:apply-templates>
218
      <!--distribution doesn't have any access node yet. Move the subtree from addtionalMetadata to distribution-->
219
      <!--find the id in addtionalMetacat/describes-->
220
      <xsl:variable name="id" select="@id"></xsl:variable>
221
      <!-- count how many additionalMetadata/access describing same distribution is -->
222
      <xsl:variable name="countAccessTree"
223
        select="count(/*/additionalMetadata[describes=$id]/access | /*/additionalMetadata[describes=$id]/metadata/access)"></xsl:variable>
224
      <xsl:choose>
225
        <xsl:when test="$countAccessTree=1">
226
          <!-- only has one access tree, we need copy it to distribution-->
227
          <xsl:apply-templates mode="copy-no-ns"
228
            select="/*/additionalMetadata[describes=$id]/access | /*/additionalMetadata[describes=$id]/metadata/access"
229
          ></xsl:apply-templates>
230
        </xsl:when>
231
        <xsl:when test="$countAccessTree &gt; 1">
232
          <!-- has more than one access tree, we need merge them-->
233
          <!--This means document have two or more addtionalMetadata
234
					          with access tree describing same distribution.
235
                       		<additionalMetadata>
236
                          		<describes>100</describe>
237
                          		<access>...</access>
238
                        	</additionalMetadata>
239
						 	<additionalMetadata>
240
                          		<describes>100</describe>
241
                          		<access>...</access>
242
                        	</additionalMetadata>-->
243
          <xsl:variable name="totalOrderNumber"
244
            select="count(/*/additionalMetadata[describes=$id]/access | /*/additionalMetadata[describes=$id]/metadata/access)"></xsl:variable>
245
          <xsl:variable name="totalAllowFirstNumber"
246
            select="count(/*/additionalMetadata[describes=$id]/access[@order='allowFirst'] | /*/additionalMetadata[describes=$id]/metadata/access[@order='allowFirst'])"></xsl:variable>
247
          <xsl:variable name="totalDenyFirstNumber"
248
            select="count(/*/additionalMetadata[describes=$id]/access[@order='denyFirst'] | /*/additionalMetadata[describes=$id]/metadata/access[@order='denyFirst'])"></xsl:variable>
249
          <xsl:choose>
250
            <xsl:when
251
              test="$totalOrderNumber=$totalAllowFirstNumber or $totalOrderNumber=$totalDenyFirstNumber">
252
              <!-- all access subtrees have same order, just merge it-->
253
              <xsl:element name="access">
254
                <xsl:copy-of
255
                  select="/*/additionalMetadata[describes=$id]/access/@* | /*/additionalMetadata[describes=$id]/metadata/access/@*"></xsl:copy-of>
256
                <xsl:for-each
257
                  select="/*/additionalMetadata[describes=$id]/access | /*/additionalMetadata[describes=$id]/metadata/access">
258
                  <xsl:apply-templates mode="copy-no-ns" select="./*"></xsl:apply-templates>
259
                </xsl:for-each>
260
              </xsl:element>
261
            </xsl:when>
262
            <xsl:otherwise>
263
              <xsl:message terminate="no">
264
                <xsl:call-template name="output_message1_warn">
265
                <xsl:with-param name="current_node" select="current()"></xsl:with-param>
266
              </xsl:call-template> </xsl:message>
267
            </xsl:otherwise>
268
          </xsl:choose>
269
        </xsl:when>
270
      </xsl:choose>
271
    </xsl:element>
272
  </xsl:template>
273

  
274

  
275
  <!-- copy access tree under dataset(or protocol, software and citation) to the top level -->
276
  <xsl:template mode="copy-top-access-tree" match="*">
277
    <xsl:apply-templates mode="copy-no-ns" select="."></xsl:apply-templates>
278
  </xsl:template>
279

  
280
  <!-- do nothing for this element (removing it)-->
281
  <xsl:template mode="do-nothing" match="*"> </xsl:template>
282

  
283
  <!-- copy node and children without namespace -->
284
  <!--<xsl:template mode="copy-no-ns" match="*">
285
    <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
286
      <xsl:copy-of select="@*"></xsl:copy-of>
287
      <xsl:apply-templates mode="copy-no-ns"></xsl:apply-templates>
288
    </xsl:element>
289
  </xsl:template>-->
290
	
291
	
292
	<!-- copy node and children without showing default namespace. 
293
		But if the namespace is stmml, the namespace will be changed to stmml-1.1 -->
294
  <xsl:template mode="copy-no-ns" match="*">
295
   <xsl:choose>
296
	  <!--handle stmml element and attribute-->
297
	 <xsl:when test="namespace-uri()='http://www.xml-cml.org/schema/stmml'">
298
        <xsl:element name="stmml:{local-name()}" namespace="http://www.xml-cml.org/schema/stmml-1.1">
299
              <xsl:for-each select="@*">
300
	              <xsl:choose>
301
	                 <xsl:when test="namespace-uri()='http://www.w3.org/2001/XMLSchema-instance'">
302
                         <xsl:attribute name="xsi:{local-name()}" namespace="http://www.w3.org/2001/XMLSchema-instance">
303
                              <xsl:variable name="value" select="."></xsl:variable>
304
                                 <xsl:choose>
305
                                      <!--change stmml to stmml-1.1 in attribute-->
306
                                         <xsl:when test="contains($value, &quot;http://www.xml-cml.org/schema/stmml&quot;)">
307
                                              <xsl:call-template name="replace-string">
308
                                                 <xsl:with-param name="text" select="$value"></xsl:with-param>
309
                                                  <xsl:with-param name="replace" select="'http://www.xml-cml.org/schema/stmml'"></xsl:with-param>
310
                                                  <xsl:with-param name="with" select="'http://www.xml-cml.org/schema/stmml-1.1'"></xsl:with-param>
311
                                              </xsl:call-template>
312
                                          </xsl:when>
313
                                          <xsl:otherwise>
314
                                            <xsl:value-of select="."></xsl:value-of>
315
                                          </xsl:otherwise>
316
                              </xsl:choose>
317
                        </xsl:attribute>
318
		           </xsl:when>
319
		           <xsl:otherwise>
320
			           <xsl:copy-of select="."></xsl:copy-of>
321
		           </xsl:otherwise>
322
               </xsl:choose>
323
           </xsl:for-each>
324
           <xsl:apply-templates mode="copy-no-ns"></xsl:apply-templates>
325
        </xsl:element>
326
	 </xsl:when>
327
	  <!--handle non-stmml element-->
328
	 <xsl:otherwise>
329
		 <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
330
            <xsl:copy-of select="@*"></xsl:copy-of>
331
            <xsl:apply-templates mode="copy-no-ns"></xsl:apply-templates>
332
         </xsl:element>
333
     </xsl:otherwise>
334
   </xsl:choose>
335
  </xsl:template>
336
	
337
	<!-- if the element has no element child and value is empty string or whitespace and element name is not recordDelimiter, physicalLineDelimiter and fieldDelimiter,
338
      the tranformation will be terminated. -->
339
  <xsl:template match="*[not(*) and ((text() and not(normalize-space(text()) != '')) or .='') 
340
       and  name(.) != 'recordDelimiter' and name(.) != 'physicalLineDelimiter' and name(.) != 'fieldDelimiter' ]">
341
      <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
342
            <xsl:copy-of select="@*"></xsl:copy-of>
343
            <xsl:value-of select="."/>
344
      </xsl:element>
345
      <xsl:message terminate="no">
346
        <xsl:call-template name="output_message3_warn">
347
          <xsl:with-param name="current_node" select="."/>
348
        </xsl:call-template>
349
      </xsl:message>
350
  </xsl:template>
351
    
352
  <xsl:template mode="copy-no-ns-with-access-move" match="*[not(*) and ((text() and not(normalize-space(text()) != '')) or .='') 
353
       and name(.) != 'recordDelimiter' and name(.) != 'physicalLineDelimiter' and name(.) != 'fieldDelimiter' ]">
354
      <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
355
            <xsl:copy-of select="@*"></xsl:copy-of>
356
            <xsl:value-of select="."/>
357
      </xsl:element>
358
      <xsl:message terminate="no">
359
        <xsl:call-template name="output_message3_warn">
360
          <xsl:with-param name="current_node" select="."/>
361
        </xsl:call-template>
362
      </xsl:message>
363
  </xsl:template>
364
    
365
  <xsl:template mode="copy-no-ns" match="*[not(*) and ((text() and not(normalize-space(text()) != '')) or .='') 
366
       and name(.) != 'recordDelimiter' and name(.) != 'physicalLineDelimiter' and name(.) != 'fieldDelimiter' ]">
367
      <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
368
            <xsl:copy-of select="@*"></xsl:copy-of>
369
            <xsl:value-of select="."/>
370
      </xsl:element>
371
      <xsl:message terminate="no">
372
        <xsl:call-template name="output_message3_warn">
373
          <xsl:with-param name="current_node" select="."/>
374
        </xsl:call-template>
375
      </xsl:message>
376
  </xsl:template>
377

  
378

  
379
  <!--Handle additionMetadata part. Here are 4 scenarios:
380
         1. <additionalMetadata>
381
					<describes>100</describes>
382
                     <foo>.....</foo>
383
             </additionalMetacata>
384
             The result will be (foo deosn't euqal access):
385
             <additionalMetadata>
386
					<describes>100</describes>
387
                     <metadata><foo>.....</foo></metadata>
388
             </additionalMetacata>
389
         2. <additionalMetadata>
390
					<describes>100</describes>
391
					<describes>200</describes>
392
                     <access>.....</access>
393
             </additionalMetacata>
394
            Both 100 and 200 are referenced ids of pysical/distribtuion or software/implementation/distribution.
395
            Since we moved the access part to distribution element. If multiple access rules are present 
396
            which reference the same distribution node, they are combined in th order they appear in 
397
            additionalMetadata sections. A conflict can occur here if  "order" attributes dont match. Fail
398
            with an erroro message.
399
            
400
            Since both are referenced id (and no conflict), we don't need to keep the info. 
401
           So the output is blank - remvoing the additionalMetadata tree.
402
         3. <additionalMetadata>
403
					<describes>300</describes>
404
					<describes>400</describes>
405
                     <access>.....</access>
406
             </additionalMetacata>
407
            300 is the referenced ids of pysical/distribtuion or software/implementation/distribution. 
408
            But 400 is not. So output will be:
409
            <additionalMetadata>
410
					<describes>400</describes>
411
                     <metadata><access>.....</access></metadata>
412
             </additionalMetacata>
413
            And we will give an warning message: message #2 referenced node is a not distribution id .
414
		4. <additionalMetadata>
415
                     <access>.....</access>
416
             </additionalMetacata>
417
            Since no describes, no access tree will move. So output will be:
418
            <additionalMetadata>
419
                     <metadata><access>.....</access></metadata>
420
             </additionalMetacata>
421
            And we will give an warning message:message #2 No distribution id in addtionalMetadata/describes 
422
            .
423
	-->
424
  <xsl:template mode="handle-additionalMetadata" match="*">
425
    <!-- this param for passing a suspicious node to an output message -->
426
    <xsl:param name="current_node"/>
427
    <!-- test if this additionalMetadata part has "access" element-->
428
    <xsl:variable name="accessCount" select="count(access | metadata/access)"></xsl:variable>
429
	
430
    <xsl:choose>
431
      <xsl:when test="$accessCount &lt; 1">
432
        <!-- no access tree here. Scenario 1 -->
433
        <additionalMetadata>
434
          <xsl:for-each select="./*">
435
            <xsl:choose>
436
              <xsl:when test="name()='describes'">
437
                <xsl:apply-templates mode="copy-no-ns" select="."></xsl:apply-templates>
438
              </xsl:when>
439
              <!--if it already has metadata tag under additionalMetadata, just copy it-->
440
              <xsl:when test="name()='metadata'">
441
                <xsl:apply-templates mode="copy-no-ns" select="."></xsl:apply-templates>
442
              </xsl:when>
443
              <xsl:otherwise>
444
                <metadata>
445
                  <xsl:apply-templates mode="copy-no-ns" select="."></xsl:apply-templates>
446
                </metadata>
447
              </xsl:otherwise>
448
            </xsl:choose>
449
          </xsl:for-each>
450
        </additionalMetadata>
451
      </xsl:when>
452
      <xsl:otherwise>
453
        <!--additionalMetadata has EML access child-->
454
        <xsl:variable name="describesCount" select="count(describes)"></xsl:variable>
455
        <xsl:choose>
456
          <xsl:when test="$describesCount=0">
457
            <!-- scenario 4 - only has access but no describes, leave it there-->
458
            <additionalMetadata>
459
              <xsl:for-each select="./*">
460
                <xsl:choose>
461
                  <xsl:when test="name()='metadata'">
462
                    <xsl:apply-templates mode="copy-no-ns" select="."></xsl:apply-templates>
463
                  </xsl:when>
464
                  <xsl:otherwise>
465
                    <metadata>
466
                      <xsl:apply-templates mode="copy-no-ns" select="."></xsl:apply-templates>
467
                    </metadata>
468
                  </xsl:otherwise>
469
                </xsl:choose>
470
              </xsl:for-each>
471
              <xsl:message terminate="no">
472
                <xsl:call-template name="output_message2_warn">
473
                  <xsl:with-param name="current_node" select="current()"></xsl:with-param>
474
                </xsl:call-template>
475
              </xsl:message>
476
            </additionalMetadata>
477
          </xsl:when>
478
          <xsl:otherwise>
479
            <!-- Scenario 2 and 3 -->
480
			 <xsl:variable name="describes" select="./describes"/>
481
            <xsl:call-template name="handle-describe-access-in-additional-metadata">
482
              <!--select node-set of describe which doesn't refer physical/distribtuion or software/implmentation/distribution and it doesn't have both "denyFirst" and "allowFirst"-->
483
              <xsl:with-param name="describes-list"
484
                select="./describes[(not(//physical/distribution/@id =.) and not(//software/implementation/distribution/@id = .)) or
485
				   ((//physical/distribution/@id =. or //software/implementation/distribution/@id = .) and (//additionalMetadata[describes = $describes and (access[@order='allowFirst'] or metadata/access[@order='allowFirst'])] and //additionalMetadata[describes = $describes and (access[@order='denyFirst'] or metadata/access[@order='denyFirst'])]))]"
486
              ></xsl:with-param>
487
            </xsl:call-template>
488
          </xsl:otherwise>
489
        </xsl:choose>
490
      </xsl:otherwise>
491
    </xsl:choose>
492
  </xsl:template>
493

  
494
  <!-- parameter desribes will have the node-set of "describe" which doesn't reference any physical/distribtuion or
495
		software/implmentation/distribution. If size of node-set is zero, the template will do nothing, in other it will
496
		remove the additionalMetadata. If the size is not zero, we will keep the desribes and access-->
497
  <xsl:template name="handle-describe-access-in-additional-metadata">
498
    <xsl:param name="describes-list"></xsl:param>
499
    <xsl:choose>
500
      <xsl:when test="count($describes-list)=0">
501
        <!--Scenario 2: do nothing since all desribes are reference to physical/distribtuion or software/implmentation/distribution-->
502
      </xsl:when>
503
      <xsl:otherwise>
504
        <!--Scenario 3: some desribes doesn't refer to physical/distribtuion or software/implmentation/distribution. We need to keep them-->
505
        <additionalMetadata>
506
          <xsl:call-template name="recursive-describes">
507
            <xsl:with-param name="describes" select="$describes-list"></xsl:with-param>
508
          </xsl:call-template>
509
          <metadata>
510
            <xsl:apply-templates mode="copy-no-ns" select="./access | ./metadata/access"
511
            ></xsl:apply-templates>
512
          </metadata>
513
        </additionalMetadata>
514
      </xsl:otherwise>
515
    </xsl:choose>
516
  </xsl:template>
517

  
518
  <!-- Use a recursive way to print out describes which doesn't refer physical/distribtuion or software/implmentation/distribution -->
519
  <xsl:template name="recursive-describes">
520
    <xsl:param name="describes"></xsl:param>
521
    <xsl:param name="index" select="1"></xsl:param>
522
    <xsl:choose>
523
      <!--finish-->
524
      <xsl:when test="$index > count($describes)">
525
        <!-- do nothing-->
526
      </xsl:when>
527
      <xsl:otherwise>
528
        <describes>
529
          <xsl:value-of select="$describes[$index]"></xsl:value-of>
530
        </describes>
531
        <xsl:call-template name="recursive-describes">
532
          <xsl:with-param name="describes" select="$describes"></xsl:with-param>
533
          <xsl:with-param name="index" select="$index + 1"></xsl:with-param>
534
        </xsl:call-template>
535
      </xsl:otherwise>
536
    </xsl:choose>
537
  </xsl:template>
538

  
539
  <!--Template to replace string "replace" by string "with" in given string "text"-->
540
  <xsl:template name="replace-string">
541
    <xsl:param name="text"></xsl:param>
542
    <xsl:param name="replace"></xsl:param>
543
    <xsl:param name="with"></xsl:param>
544
    <xsl:choose>
545
      <xsl:when test="contains($text,$replace)">
546
        <xsl:value-of select="substring-before($text,$replace)"></xsl:value-of>
547
        <xsl:value-of select="$with"></xsl:value-of>
548
        <xsl:call-template name="replace-string">
549
          <xsl:with-param name="text" select="substring-after($text,$replace)"></xsl:with-param>
550
          <xsl:with-param name="replace" select="$replace"></xsl:with-param>
551
          <xsl:with-param name="with" select="$with"></xsl:with-param>
552
        </xsl:call-template>
553
      </xsl:when>
554
      <xsl:otherwise>
555
        <xsl:value-of select="$text"></xsl:value-of>
556
      </xsl:otherwise>
557
    </xsl:choose>
558
  </xsl:template>
559

  
560
  <!-- 
561
    
562
    these templates output mesages for the user if an additionalMetdata section cant be moved. -->
563
  <!-- 
564
    this message for scenario 1, order attribute conflict -->
565
  <xsl:template name="output_message1_warn">
566
    <xsl:param name="current_node"/>
567
    <xsl:text>
568
      Warning:
569
      The EML 2.0.1 document you wish to transform has multiple access subtrees in addtionalMetadata 
570
      blocks which describe the same entity.  However, their "order" attributes do not match, so these 
571
      access rules cannot be combinded under the entity's distribution node. Please fix the incoming 
572
      (EML 2.0) document so that the  "order" attributes on all access nodes for an entity are the same.
573
      Example content to help locate the problem:     </xsl:text>
574
    <xsl:value-of select="$current_node"/>  </xsl:template>    
575
  <!-- 
576
    
577
    this message for scenario 4  -->
578
  <xsl:template name="output_message2_warn">
579
    <xsl:param name="current_node"/>
580
    <xsl:text>
581
      Warning: 
582
      This document doesn't follow  EML2.0.1 specs for including access trees. It appears to contain an
583
      additonalMetadata section with an access element, but there is no describes element referencing 
584
      the id of a physical/distribution or a software/implementation/distribution element (there might be 
585
      a reference to some other node, however). The rest of the document was successfully converted to 
586
      EML2.1, although the offending access tree was left as is. You should examine your incoming 
587
      document and change it to comply with EML 2.0.1 specs, or move this access tree using some 
588
      other method. 
589
      Example content to help locate a potential problem:     </xsl:text>
590
    <xsl:value-of select="$current_node"/>
591
  </xsl:template>
592
	
593
  <!-- message for empty string element-->
594
  <xsl:template name="output_message3_warn">
595
    <xsl:param name="current_node"/>
596
    <xsl:text>
597
      Warning:
598
      The EML 2.0.1 document has an empty string (or whitespace) in an element which cannot be empty in EML 2.1.0 sepcification - </xsl:text>
599
    <xsl:apply-templates select="$current_node" mode="get-full-path"/>
600
</xsl:template>    
601
	
602
	
603
	<!-- message for reminding  user  that the eml 210 document may be invalid-->
604
  <xsl:template name="output_message4_warn">
605
 
606
    <xsl:text>
607
      Warning:
608
      The EML 2.0.1 document has been transformed into an EML 2.1.0 document. However, you should check if it is valid. 
609
	  See http://knb.ecoinformatics.org/software/eml/eml-2.1.0/eml-210info.html for more information.</xsl:text>
610
    
611
</xsl:template>    
612
  <!-- 
613
    
614
    end of user message templates -->
615
	
616
	<!-- get full path of given element-->
617
    <xsl:template match="node()" mode="get-full-path">
618
      <xsl:for-each select="ancestor-or-self::*">
619
        <xsl:text>/</xsl:text><xsl:value-of select="name()" />
620
      </xsl:for-each>
621
    </xsl:template>
622

  
623

  
624

  
625

  
626

  
627
</xsl:stylesheet>
lib/metacat.properties
336 336
Identify.earliestDatestamp=2000-01-01T00:00:00Z
337 337
Identify.deletedRecord=no
338 338
# Append something unique like .1, .2, etc to 'Identify.description' for each occurrence
339
Identify.description.1=<description><oai-identifier xmlns\="http\://www.openarchives.org/OAI/2.0/oai-identifier" xmlns\:xsi\="http\://www.w3.org/2001/XMLSchema-instance" xsi\:schemaLocation\="http\://www.openarchives.org/OAI/2.0/oai-identifier http\://www.openarchives.org/OAI/2.0/oai-identifier.xsd"><scheme>oai</scheme><repositoryIdentifier>metacat.lternet.edu</repositoryIdentifier><delimiter>\:</delimiter><sampleIdentifier>http\://metacat.lternet.edu/knb/metacat/knb-lter-lno.1</sampleIdentifier></oai-identifier></description>
339
#Identify.description.1=<description><oai-identifier xmlns\="http\://www.openarchives.org/OAI/2.0/oai-identifier" xmlns\:xsi\="http\://www.w3.org/2001/XMLSchema-instance" xsi\:schemaLocation\="http\://www.openarchives.org/OAI/2.0/oai-identifier http\://www.openarchives.org/OAI/2.0/oai-identifier.xsd"><scheme>oai</scheme><repositoryIdentifier>metacat.lternet.edu</repositoryIdentifier><delimiter>\:</delimiter><sampleIdentifier>http\://metacat.lternet.edu/knb/metacat/knb-lter-lno.1</sampleIdentifier></oai-identifier></description>
340 340
# List the supported metadataPrefixes along with the class that performs the associated crosswalk
341 341
Crosswalks.oai_dc=edu.ucsb.nceas.metacat.oaipmh.provider.server.crosswalk.Eml2oai_dc
342
Crosswalks.eml=edu.ucsb.nceas.metacat.oaipmh.provider.server.crosswalk.Eml
342 343

  
343 344
######## Spatial section              #########################################
344 345

  
src/edu/ucsb/nceas/metacat/oaipmh/provider/server/OAIHandler.java
39 39
import org.apache.log4j.Logger;
40 40
import org.apache.log4j.PropertyConfigurator;
41 41

  
42
import edu.ucsb.nceas.metacat.oaipmh.provider.server.crosswalk.Eml;
42 43
import edu.ucsb.nceas.metacat.oaipmh.provider.server.crosswalk.Eml2oai_dc;
43 44
import edu.ucsb.nceas.metacat.service.PropertyService;
44 45
import edu.ucsb.nceas.metacat.service.ServiceException;
......
540 541
    // Initialize the directory path to the crosswalk XSLT files
541 542
    String xsltDirPath = servletContext.getRealPath(XSLT_DIR);
542 543
    Eml2oai_dc.setDirPath(xsltDirPath);
544
    Eml.setDirPath(xsltDirPath);
543 545

  
544 546
    try {
545 547
      HashMap attributes = null;
src/edu/ucsb/nceas/metacat/oaipmh/provider/server/crosswalk/Eml.java
1
/**
2
 * Copyright 2006 OCLC Online Computer Library Center Licensed under the Apache
3
 * License, Version 2.0 (the "License"); you may not use this file except in
4
 * compliance with the License. You may obtain a copy of the License at
5
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or
6
 * agreed to in writing, software distributed under the License is distributed on
7
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
8
 * or implied. See the License for the specific language governing permissions and
9
 * limitations under the License.
10
 */
11
package edu.ucsb.nceas.metacat.oaipmh.provider.server.crosswalk;
12

  
13
import java.io.FileInputStream;
14
import java.io.StringReader;
15
import java.io.StringWriter;
16
import java.util.HashMap;
17
import java.util.Properties;
18

  
19
import javax.xml.transform.Transformer;
20
import javax.xml.transform.TransformerFactory;
21
import javax.xml.transform.stream.StreamResult;
22
import javax.xml.transform.stream.StreamSource;
23

  
24
import org.apache.log4j.Logger;
25

  
26
import ORG.oclc.oai.server.crosswalk.Crosswalk;
27
import ORG.oclc.oai.server.verb.CannotDisseminateFormatException;
28
import ORG.oclc.oai.server.verb.OAIInternalServerError;
29

  
30

  
31
/**
32
 * Provides EML documents in eml-2.1.0 format. For eml-2.1.0 documents, we
33
 * simply return the metadata that was read from Metacat. For eml-2.0.x
34
 * documents, we use the EML Utilities stylesheet to transform the document
35
 * to eml-2.1.0.
36
 */
37
public class Eml extends Crosswalk {
38
  
39
  /* Class fields */
40

  
41
  private static final Logger logger = Logger.getLogger(Eml.class);
42
  private static String dirPath = null;
43
  
44
  // This is a local copy of the stylesheet from the EML Utilities module
45
  private static final String XSLT_NAME = "eml201to210.xsl";
46
  
47
  private static final String SCHEMA_LOCATION =
48
    "eml://ecoinformatics.org/eml-2.1.0 " +
49
    "http://knb.ecoinformatics.org/knb/schema/eml-2.1.0/eml.xsd";
50

  
51

  
52
  /* Instance fields */
53
  
54
  private Transformer transformer = null;
55
  
56
  
57
  /* Constructors */
58

  
59
  /**
60
   * The constructor assigns the schemaLocation associated with this crosswalk.
61
   * Since the crosswalk is trivial in this case, no properties are utilized.
62
   * 
63
   * @param properties
64
   *          properties that are needed to configure the crosswalk.
65
   */
66
  public Eml(Properties properties) throws OAIInternalServerError {
67
    super(SCHEMA_LOCATION);
68
    String xsltPath = dirPath + "/" + XSLT_NAME;
69
    
70
    try {
71
      TransformerFactory tFactory = TransformerFactory.newInstance();
72
      FileInputStream fileInputStream = new FileInputStream(xsltPath);
73
      StreamSource xslSource = new StreamSource(fileInputStream);
74
      this.transformer = tFactory.newTransformer(xslSource);
75
    } 
76
    catch (Exception e) {
77
      e.printStackTrace();
78
      throw new OAIInternalServerError(e.getMessage());
79
    }
80
  }
81
  
82
  
83
  /* Class methods */
84
  
85
  /**
86
   * Set the value of the configuration directory path so that XSLT stylesheets
87
   * can be located on the system.
88
   * 
89
   * @param configDir   the configuration directory path
90
   */
91
  public static void setDirPath(String configDir) {
92
    Eml.dirPath = configDir;
93
  }
94

  
95

  
96
  
97
  /* Instance methods */
98

  
99

  
100
  /**
101
   * Perform the actual crosswalk.
102
   * 
103
   * @param nativeItem  A HashMap object that contains the EML string that was
104
   *                    retrieved from Metacat and stored as the value of the
105
   *                    "recordBytes" key
106
   * @return eml210doc  a String containing the metadata to be stored within 
107
   *                    the <metadata> element in eml 2.1.0 format
108
   * @exception CannotDisseminateFormatException
109
   *              nativeItem doesn't support this format.
110
   */
111
  public String createMetadata(Object nativeItem)
112
      throws CannotDisseminateFormatException {
113
    HashMap recordMap = (HashMap) nativeItem;
114
    String eml210doc = null;
115
    
116
    String docid = (String) recordMap.get("localIdentifier");
117
    String doctype = (String) recordMap.get("doctype");
118
    String xmlRec = (String) recordMap.get("recordBytes");
119

  
120
    /* Transform eml-2.0.x documents to eml-2.1.0 using the stylesheet from
121
     * the EML Utilities module 
122
     */
123
    if ((doctype != null) && (doctype.contains("eml-2.0.0") ||
124
                              doctype.contains("eml-2.0.1")
125
                             )
126
       ) 
127
    {
128
      if (docid != null) {
129
        logger.debug("Transforming " + doctype + " document, " + docid + ", to eml-2.1.0.");
130
      }
131
      
132
      try {
133
        StringReader stringReader = new StringReader(xmlRec);
134
        StreamSource streamSource = new StreamSource(stringReader);
135
        StringWriter stringWriter = new StringWriter();
136
        
137
        synchronized (transformer) {
138
          transformer.transform(streamSource, new StreamResult(stringWriter));
139
        }
140
        eml210doc = stringWriter.toString();
141
      } 
142
      catch (Exception e) {
143
        throw new CannotDisseminateFormatException(e.getMessage());
144
      }
145
    }
146
    else if (xmlRec.contains("eml://ecoinformatics.org/eml-2.1.0")) {
147
        eml210doc = xmlRec;
148
    }
149
    
150
    eml210doc = eml210doc.trim();
151
    
152
    /*
153
     * Remove the lead xml processing instruction because the document is going
154
     * to be placed inside an OAI <metadata> element within a 
155
     */
156
    if (eml210doc.startsWith("<?")) {
157
      int offset = eml210doc.indexOf("?>");
158
      eml210doc = eml210doc.substring(offset + 2);
159
    }
160
      
161
    return eml210doc;
162
  }
163
  
164
  
165
  /**
166
   * Can this nativeItem be represented in 'eml' format?
167
   * 
168
   * @param nativeItem              a record in native format
169
   * @return true if 'eml' format is possible, false otherwise.
170
   */
171
  public boolean isAvailableFor(Object nativeItem) {
172
    // We assume that all EML documents can be represented in eml format
173
    return true;
174
  }
175
  
176
}
src/edu/ucsb/nceas/metacat/oaipmh/provider/server/crosswalk/Eml2oai_dc.java
16 16
import java.util.HashMap;
17 17
import java.util.Properties;
18 18

  
19
import javax.xml.transform.OutputKeys;
20 19
import javax.xml.transform.Transformer;
21 20
import javax.xml.transform.TransformerFactory;
22 21
import javax.xml.transform.stream.StreamResult;
src/edu/ucsb/nceas/metacat/oaipmh/provider/server/catalog/MetacatCatalog.java
323 323
      recordMap = new HashMap<String, String>();
324 324
      recordMap.put("localIdentifier", localIdentifier);
325 325
      recordMap.put("lastModified", dateMap.get(localIdentifier));
326
      recordMap.put("doctype", docTypeMap.get(localIdentifier));
326 327
      return recordMap;
327 328
    }
328 329
    

Also available in: Unified diff