]> Wikimedia Canada | Git repositories - eccc_to_commons.git/blob - almanac_to_commons.xslt
Rewrite almanach merge logic
[eccc_to_commons.git] / almanac_to_commons.xslt
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <!-- almanac_to_commons.xslt - Convert Environment and Climate change Canada
4 historical XML data into a JSON format suitable
5 for Wikimedia Commons.
6 Copyright (C) 2019-2020 Pierre Choffet
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 -->
21
22 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
23 <xsl:output method="text" encoding="utf-8" />
24
25 <xsl:template match="/climatedata">
26 <xsl:variable name="station-name">
27 <xsl:call-template name="camel-case">
28 <xsl:with-param name="text" select="/climatedata/stationinformation/name/text()" />
29 </xsl:call-template>
30 </xsl:variable>
31 <xsl:variable name="province-name">
32 <xsl:call-template name="camel-case">
33 <xsl:with-param name="text" select="/climatedata/stationinformation/province/text()" />
34 </xsl:call-template>
35 </xsl:variable>
36
37 <xsl:text>{
38 "license": "CC-BY-4.0",
39 "description": {
40 "en": "</xsl:text><xsl:value-of select="$station-name" /><xsl:text> average and extreme data",
41 "fr": "Moyennes et extrêmes pour la station météorologique </xsl:text><xsl:value-of select="$station-name" /><xsl:text>"
42 },
43 "sources": "[https://climate.weather.gc.ca/ Environment and Climate Change Canada]",
44 "schema": {
45 "fields": [
46 {
47 "name": "date",
48 "type": "string",
49 "title": {
50 "ar": "تاريخ",
51 "ca": "Data",
52 "da": "Dato",
53 "de": "Datum",
54 "en": "Date",
55 "es": "Fecha",
56 "fr": "Date",
57 "ru": "Дата",
58 "sr": "Датум"
59 }
60 },
61 {
62 "name": "extremeMax",
63 "type": "number",
64 "title": {
65 "en": "Highest maximum temperature",
66 "fr": "Température maximale la plus élevée"
67 }
68 },
69 {
70 "name": "extremeMin",
71 "type": "number",
72 "title": {
73 "en": "Lowest minimum temperature",
74 "fr": "Température minimale la plus basse"
75 }
76 },
77 {
78 "name": "normalMax",
79 "type": "number",
80 "title": {
81 "en": "Highest normal temperature",
82 "fr": "Température normale haute"
83 }
84 },
85 {
86 "name": "normalMin",
87 "type": "number",
88 "title": {
89 "en": "Lowest normal temperature",
90 "fr": "Température normale basse"
91 }
92 },
93 {
94 "name": "normalMean",
95 "type": "number",
96 "title": {
97 "en": "Mean normal temperature",
98 "fr": "Température normale moyenne"
99 }
100 },
101 {
102 "name": "extremeRainfall",
103 "type": "number",
104 "title": {
105 "en": "Greatest rainfall",
106 "fr": "Pluie maximale"
107 }
108 },
109 {
110 "name": "extremeSnowfall",
111 "type": "number",
112 "title": {
113 "en": "Greatest snowfall",
114 "fr": "Neige maximale"
115 }
116 },
117 {
118 "name": "extremePrecipitation",
119 "type": "number",
120 "title": {
121 "en": "Greatest precipitation",
122 "fr": "Précipitation maximale"
123 }
124 },
125 {
126 "name": "extremeSnowOnGround",
127 "type": "number",
128 "title": {
129 "en": "Most snow on the ground",
130 "fr": "Maximum de neige au sol"
131 }
132 },
133 {
134 "name": "pop",
135 "type": "number",
136 "title": {
137 "en": "Monthly frequency of precipitation",
138 "fr": "Fréquence mensuelle de précipitation"
139 }
140 }
141 ]
142 },
143 "data": [</xsl:text>
144 <xsl:apply-templates select="month" />
145 <xsl:text>]}</xsl:text>
146 </xsl:template>
147
148 <xsl:template match="month">
149 <!-- TODO: Check element has at least one data? -->
150 <xsl:apply-templates select="day">
151 <xsl:with-param name="month" select="format-number(@index, '00')" />
152 </xsl:apply-templates>
153 <xsl:if test="day and following-sibling::month[day]">
154 <xsl:text>, </xsl:text>
155 </xsl:if>
156 </xsl:template>
157
158 <xsl:template match="day">
159 <xsl:param name="month" />
160 <xsl:param name="day" select="format-number(@index, '00')" />
161
162 <xsl:text>["</xsl:text>
163 <xsl:value-of select="$month" />-<xsl:value-of select="$day" />
164 <xsl:text>"</xsl:text>
165
166 <!-- Set extremeMax -->
167 <xsl:text>, </xsl:text>
168 <xsl:apply-templates select="temperature[@class = 'extremeMax']">
169 <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
170 </xsl:apply-templates>
171
172 <!-- Set extremeMin -->
173 <xsl:text>, </xsl:text>
174 <xsl:apply-templates select="temperature[@class = 'extremeMin']">
175 <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
176 </xsl:apply-templates>
177
178 <!-- Set normalMax -->
179 <xsl:text>, </xsl:text>
180 <xsl:apply-templates select="temperature[@class = 'normalMax']">
181 <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
182 </xsl:apply-templates>
183
184 <!-- Set normalMin -->
185 <xsl:text>, </xsl:text>
186 <xsl:apply-templates select="temperature[@class = 'normalMin']">
187 <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
188 </xsl:apply-templates>
189
190 <!-- Set normalMean -->
191 <xsl:text>, </xsl:text>
192 <xsl:apply-templates select="temperature[@class = 'normalMean']">
193 <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
194 </xsl:apply-templates>
195
196 <!-- Set extremeRainfall -->
197 <xsl:text>, </xsl:text>
198 <xsl:apply-templates select="precipitation[@class = 'extremeRainfall']">
199 <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
200 </xsl:apply-templates>
201
202 <!-- Set extremeSnowfall -->
203 <xsl:text>, </xsl:text>
204 <xsl:apply-templates select="precipitation[@class = 'extremeSnowfall']">
205 <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
206 </xsl:apply-templates>
207
208 <!-- Set extremePrecipitation -->
209 <xsl:text>, </xsl:text>
210 <xsl:apply-templates select="precipitation[@class = 'extremePrecipitation']">
211 <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
212 </xsl:apply-templates>
213
214 <!-- Set extremeSnowOnGround -->
215 <xsl:text>, </xsl:text>
216 <xsl:apply-templates select="precipitation[@class = 'extremeSnowOnGround']">
217 <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
218 </xsl:apply-templates>
219
220 <!-- Set pop -->
221 <!-- WARNING: This is not daily data, it makes no sense to have it in final dataset -->
222 <xsl:text>, </xsl:text>
223 <xsl:apply-templates select="pop" />
224
225 <xsl:text>]</xsl:text>
226 <xsl:if test="position() != last()">
227 <xsl:text>, </xsl:text>
228 </xsl:if>
229 </xsl:template>
230
231 <xsl:template match="temperature[@class = 'extremeMax']">
232 <xsl:param name="date" />
233
234 <xsl:choose>
235 <xsl:when test="not(text())">
236 <xsl:text>null</xsl:text>
237 </xsl:when>
238 <xsl:when test="@quality = '†'">
239 <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeMax value</xsl:message>
240 <xsl:value-of select="text()" />
241 </xsl:when>
242 <xsl:otherwise>
243 <xsl:value-of select="text()" />
244 </xsl:otherwise>
245 </xsl:choose>
246 </xsl:template>
247
248 <xsl:template match="temperature[@class = 'extremeMin']">
249 <xsl:param name="date" />
250
251 <xsl:choose>
252 <xsl:when test="not(text())">
253 <xsl:text>null</xsl:text>
254 </xsl:when>
255 <xsl:when test="@quality = '†'">
256 <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeMin value</xsl:message>
257 <xsl:value-of select="text()" />
258 </xsl:when>
259 <xsl:otherwise>
260 <xsl:value-of select="text()" />
261 </xsl:otherwise>
262 </xsl:choose>
263 </xsl:template>
264
265 <xsl:template match="temperature[@class = 'normalMax']">
266 <xsl:param name="date" />
267
268 <xsl:choose>
269 <xsl:when test="not(text())">
270 <xsl:text>null</xsl:text>
271 </xsl:when>
272 <xsl:when test="@quality = '†'">
273 <xsl:message terminate="yes">normalMax value not reviewed</xsl:message>
274 </xsl:when>
275 <xsl:otherwise>
276 <xsl:value-of select="text()" />
277 </xsl:otherwise>
278 </xsl:choose>
279 </xsl:template>
280
281 <xsl:template match="temperature[@class = 'normalMin']">
282 <xsl:param name="date" />
283
284 <xsl:choose>
285 <xsl:when test="not(text())">
286 <xsl:text>null</xsl:text>
287 </xsl:when>
288 <xsl:when test="@quality = '†'">
289 <xsl:message terminate="yes">normalMin value not reviewed</xsl:message>
290 </xsl:when>
291 <xsl:otherwise>
292 <xsl:value-of select="text()" />
293 </xsl:otherwise>
294 </xsl:choose>
295 </xsl:template>
296
297 <xsl:template match="temperature[@class = 'normalMean']">
298 <xsl:param name="date" />
299
300 <xsl:choose>
301 <xsl:when test="not(text())">
302 <xsl:text>null</xsl:text>
303 </xsl:when>
304 <xsl:when test="@quality = '†'">
305 <xsl:message terminate="yes">normalMean value not reviewed</xsl:message>
306 </xsl:when>
307 <xsl:otherwise>
308 <xsl:value-of select="text()" />
309 </xsl:otherwise>
310 </xsl:choose>
311 </xsl:template>
312
313 <xsl:template match="precipitation[@class = 'extremeRainfall']">
314 <xsl:param name="date" />
315
316 <xsl:choose>
317 <xsl:when test="not(text())">
318 <xsl:text>null</xsl:text>
319 </xsl:when>
320 <xsl:when test="@quality = '†'">
321 <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeRainfall value</xsl:message>
322 <xsl:value-of select="text()" />
323 </xsl:when>
324 <xsl:otherwise>
325 <xsl:value-of select="text()" />
326 </xsl:otherwise>
327 </xsl:choose>
328 </xsl:template>
329
330 <xsl:template match="precipitation[@class = 'extremeSnowfall']">
331 <xsl:param name="date" />
332
333 <xsl:choose>
334 <xsl:when test="not(text())">
335 <xsl:text>null</xsl:text>
336 </xsl:when>
337 <xsl:when test="@quality = '†'">
338 <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeSnowfall value</xsl:message>
339 <xsl:value-of select="text()" />
340 </xsl:when>
341 <xsl:otherwise>
342 <xsl:value-of select="text()" />
343 </xsl:otherwise>
344 </xsl:choose>
345 </xsl:template>
346
347 <xsl:template match="precipitation[@class = 'extremePrecipitation']">
348 <xsl:param name="date" />
349
350 <xsl:choose>
351 <xsl:when test="not(text())">
352 <xsl:text>null</xsl:text>
353 </xsl:when>
354 <xsl:when test="@quality = '†'">
355 <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremePrecipitation value</xsl:message>
356 <xsl:value-of select="text()" />
357 </xsl:when>
358 <xsl:otherwise>
359 <xsl:value-of select="text()" />
360 </xsl:otherwise>
361 </xsl:choose>
362 </xsl:template>
363
364 <xsl:template match="precipitation[@class = 'extremeSnowOnGround']">
365 <xsl:param name="date" />
366
367 <xsl:choose>
368 <xsl:when test="not(text())">
369 <xsl:text>null</xsl:text>
370 </xsl:when>
371 <xsl:when test="contains(text(), '#')">
372 <xsl:message>WARNING: <xsl:value-of select="$date" />: Discard extremeSnowOnGround containing "#"</xsl:message>
373 <xsl:text>null</xsl:text>
374 </xsl:when>
375 <xsl:when test="@quality = '†'">
376 <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeSnowOnGround value</xsl:message>
377 <xsl:value-of select="text()" />
378 </xsl:when>
379 <xsl:otherwise>
380 <xsl:value-of select="text()" />
381 </xsl:otherwise>
382 </xsl:choose>
383 </xsl:template>
384
385 <xsl:template match="pop">
386 <xsl:param name="date" />
387
388 <xsl:choose>
389 <xsl:when test="not(text())">
390 <xsl:text>null</xsl:text>
391 </xsl:when>
392 <xsl:when test="@quality = '†'">
393 <xsl:message terminate="yes">pop value not reviewed</xsl:message>
394 </xsl:when>
395 <xsl:otherwise>
396 <xsl:value-of select="text()" />
397 </xsl:otherwise>
398 </xsl:choose>
399 </xsl:template>
400
401 <!-- Camel case -->
402 <xsl:template name="camel-case">
403 <xsl:param name="text" select="."/>
404 <xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
405 <xsl:variable name="lowercase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
406 <xsl:variable name="word" select="substring-before(concat($text, ' '), ' ')" />
407
408 <xsl:value-of select="translate(substring($word, 1, 1), $lowercase, $uppercase)" />
409 <xsl:value-of select="translate(substring($word, 2), $uppercase, $lowercase)" />
410
411 <xsl:if test="contains($text, ' ')">
412 <xsl:text> </xsl:text>
413 <xsl:call-template name="camel-case">
414 <xsl:with-param name="text" select="substring-after($text, ' ')"/>
415 </xsl:call-template>
416 </xsl:if>
417 </xsl:template>
418 </xsl:stylesheet>