]> Wikimedia Canada | Git repositories - eccc_to_commons.git/blob - eccc_merger_almanach.xslt
Fix almanach merger with empty pop values
[eccc_to_commons.git] / eccc_merger_almanach.xslt
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <!-- eccc_merger.xslt - Merge XML historical data as provided by
4 Environment and Climate Change Canada
5 Copyright (C) 2020 Pierre Choffet
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
21 Rounding is always done one digit after decimal point.
22
23 Output data is calculated as such:
24 temperature.extremeMax : Greatest of all values
25 temperature.extremeMin : Lowest of all values
26 temperature.normalMax : Greatest of all values
27 temperature.normalMin : Lowest of all values
28 temperature.normalMean : Weighted mean of all values
29 precipitation.extremeRainfall : Greatest of all values
30 precipitation.extremeSnowfall : Greatest of all values
31 precipitation.extremePrecipitation: Greatest of all values
32 precipitation.extremeSnowOnGround : Greatest of all values
33 pop : Weighted mean of all values
34 -->
35
36 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
37 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
38 exclude-result-prefixes="xsi">
39
40 <xsl:output method="xml" encoding="utf-8" />
41
42 <xsl:variable name="input-root" select="/" />
43 <xsl:variable name="merge-doc" select="document($merge-path)" />
44
45 <!-- Idempotence -->
46 <xsl:template match="@*|node()">
47 <xsl:copy>
48 <xsl:apply-templates select="@*|node()" />
49 </xsl:copy>
50 </xsl:template>
51
52 <xsl:template match="/climatedata">
53 <xsl:copy>
54 <!-- Upon first merge, import missing metadata elements -->
55 <xsl:if test="not(lang)">
56 <xsl:apply-templates select="$merge-doc/climatedata/lang" />
57 </xsl:if>
58 <xsl:if test="not(stationinformation)">
59 <xsl:apply-templates select="$merge-doc/climatedata/stationinformation" />
60 </xsl:if>
61
62 <xsl:apply-templates select="@*|node()" />
63 </xsl:copy>
64 </xsl:template>
65
66 <xsl:template match="month">
67 <xsl:copy>
68 <xsl:apply-templates select="@index" />
69
70 <!-- ECCC data may not contain all days element, so we're counting by ourserves -->
71 <xsl:call-template name="loop-day">
72 <xsl:with-param name="day" select="1" />
73 </xsl:call-template>
74 </xsl:copy>
75 </xsl:template>
76
77 <xsl:template match="day">
78 <xsl:copy>
79 <xsl:attribute name="index">
80 <xsl:value-of select="@index" />
81 </xsl:attribute>
82
83 <xsl:apply-templates match="node()" />
84 </xsl:copy>
85 </xsl:template>
86
87 <xsl:template match="temperature[@class = 'extremeMax']">
88 <xsl:variable name="month" select="../../@index" />
89 <xsl:variable name="day" select="../@index" />
90 <xsl:variable name="input-extreme-max" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'extremeMax']" />
91 <xsl:variable name="merge-extreme-max" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'extremeMax']" />
92
93 <xsl:choose>
94 <xsl:when test="$input-extreme-max and (not($merge-extreme-max) or $input-extreme-max/text() &gt;= $merge-extreme-max/text())">
95 <xsl:copy>
96 <xsl:apply-templates select="$input-extreme-max/@*" />
97 <xsl:apply-templates select="$input-extreme-max/node()" />
98 </xsl:copy>
99 </xsl:when>
100 <xsl:otherwise>
101 <xsl:copy>
102 <xsl:apply-templates select="$merge-extreme-max/@*" />
103 <xsl:apply-templates select="$merge-extreme-max/node()" />
104 </xsl:copy>
105 </xsl:otherwise>
106 </xsl:choose>
107 </xsl:template>
108
109 <xsl:template match="temperature[@class = 'extremeMin']">
110 <xsl:variable name="month" select="../../@index" />
111 <xsl:variable name="day" select="../@index" />
112 <xsl:variable name="input-extreme-min" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'extremeMin']" />
113 <xsl:variable name="merge-extreme-min" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'extremeMin']" />
114
115 <xsl:choose>
116 <xsl:when test="$input-extreme-min and (not($merge-extreme-min) or $input-extreme-min/text() &lt;= merge-extreme-min/text())">
117 <xsl:copy>
118 <xsl:apply-templates select="$input-extreme-min/@*" />
119 <xsl:apply-templates select="$input-extreme-min/node()" />
120 </xsl:copy>
121 </xsl:when>
122 <xsl:otherwise>
123 <xsl:copy>
124 <xsl:apply-templates select="$merge-extreme-min/@*" />
125 <xsl:apply-templates select="$merge-extreme-min/node()" />
126 </xsl:copy>
127 </xsl:otherwise>
128 </xsl:choose>
129 </xsl:template>
130
131 <xsl:template match="temperature[@class = 'normalMax']">
132 <xsl:variable name="month" select="../../@index" />
133 <xsl:variable name="day" select="../@index" />
134 <xsl:variable name="input-normal-max" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'normalMax']" />
135 <xsl:variable name="merge-normal-max" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'normalMax']" />
136
137 <xsl:choose>
138 <xsl:when test="$input-normal-max and (not($merge-normal-max) or $input-normal-max/text() &gt;= $merge-normal-max/text())">
139 <xsl:copy>
140 <xsl:apply-templates select="$input-normal-max/@*" />
141 <xsl:apply-templates select="$input-normal-max/node()" />
142 </xsl:copy>
143 </xsl:when>
144 <xsl:otherwise>
145 <xsl:copy>
146 <xsl:apply-templates select="$merge-normal-max/@*" />
147 <xsl:apply-templates select="$merge-normal-max/node()" />
148 </xsl:copy>
149 </xsl:otherwise>
150 </xsl:choose>
151 </xsl:template>
152
153 <xsl:template match="temperature[@class = 'normalMin']">
154 <xsl:variable name="month" select="../../@index" />
155 <xsl:variable name="day" select="../@index" />
156 <xsl:variable name="input-normal-min" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'normalMin']" />
157 <xsl:variable name="merge-normal-min" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'normalMin']" />
158
159 <xsl:choose>
160 <xsl:when test="$input-normal-min and (not($merge-normal-min) or $input-normal-min/text() &lt;= $merge-normal-min/text())">
161 <xsl:copy>
162 <xsl:apply-templates select="$input-normal-min/@*" />
163 <xsl:apply-templates select="$input-normal-min/node()" />
164 </xsl:copy>
165 </xsl:when>
166 <xsl:otherwise>
167 <xsl:copy>
168 <xsl:apply-templates select="$merge-normal-min/@*" />
169 <xsl:apply-templates select="$merge-normal-min/node()" />
170 </xsl:copy>
171 </xsl:otherwise>
172 </xsl:choose>
173 </xsl:template>
174
175 <xsl:template match="temperature[@class = 'normalMean']">
176 <xsl:variable name="month" select="../../@index" />
177 <xsl:variable name="day" select="../@index" />
178 <xsl:variable name="input-normal-mean" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'normalMean']" />
179 <xsl:variable name="merge-normal-mean" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/temperature[@class = 'normalMean']" />
180
181 <xsl:choose>
182 <xsl:when test="$input-normal-mean and $input-normal-mean/text() != '' and $merge-normal-mean and $merge-normal-mean/text() != ''">
183 <xsl:copy>
184 <xsl:apply-templates select="$input-normal-mean/@*" />
185 <xsl:attribute name="values-count"><xsl:value-of select="$input-normal-mean/@values-count + 1" /></xsl:attribute>
186 <xsl:value-of select="format-number(number($input-normal-mean/text() * $input-normal-mean/@values-count + $merge-normal-mean/text()) div number($input-normal-mean/@values-count + 1), '0.0')" />
187 </xsl:copy>
188 </xsl:when>
189 <xsl:when test="$input-normal-mean != '' and (not($merge-normal-mean) or $merge-normal-mean = '')">
190 <xsl:copy>
191 <xsl:apply-templates select="$input-normal-mean/@*" />
192 <xsl:apply-templates select="$input-normal-mean/node()" />
193 </xsl:copy>
194 </xsl:when>
195 <xsl:when test="(not($input-normal-mean) or $input-normal-mean = '') and $merge-normal-mean and $merge-normal-mean != ''">
196 <xsl:copy>
197 <xsl:apply-templates select="$merge-normal-mean/@*" />
198 <xsl:attribute name="values-count">1</xsl:attribute>
199 <xsl:apply-templates select="$merge-normal-mean/node()" />
200 </xsl:copy>
201 </xsl:when>
202 <xsl:when test="$input-normal-mean = '' and $merge-normal-mean = ''">
203 <xsl:copy>
204 <xsl:apply-templates select="$input-normal-mean/@*" />
205 <xsl:apply-templates select="$input-normal-mean/node()" />
206 </xsl:copy>
207 </xsl:when>
208 <xsl:otherwise>
209 <xsl:message terminate="no">
210 <xsl:value-of select="concat($month, '-', $day, ' - normalMean: ', $input-normal-mean, ' ', $merge-normal-mean)" />
211 </xsl:message>
212 <xsl:message terminate="yes">Trapping case not supposed to happend.</xsl:message>
213 </xsl:otherwise>
214 </xsl:choose>
215 </xsl:template>
216
217 <xsl:template match="precipitation[@class = 'extremeRainfall']">
218 <xsl:variable name="month" select="../../@index" />
219 <xsl:variable name="day" select="../@index" />
220 <xsl:variable name="input-precipitation-rainfall" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeRainfall']" />
221 <xsl:variable name="merge-precipitation-rainfall" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeRainfall']" />
222
223 <xsl:choose>
224 <xsl:when test="$input-precipitation-rainfall and (not($merge-precipitation-rainfall) or $input-precipitation-rainfall/text() &gt;= $merge-precipitation-rainfall/text())">
225 <xsl:copy>
226 <xsl:apply-templates select="$input-precipitation-rainfall/@*" />
227 <xsl:apply-templates select="$input-precipitation-rainfall/node()" />
228 </xsl:copy>
229 </xsl:when>
230 <xsl:otherwise>
231 <xsl:copy>
232 <xsl:apply-templates select="$merge-precipitation-rainfall/@*" />
233 <xsl:apply-templates select="$merge-precipitation-rainfall/node()" />
234 </xsl:copy>
235 </xsl:otherwise>
236 </xsl:choose>
237 </xsl:template>
238
239 <xsl:template match="precipitation[@class = 'extremeSnowfall']">
240 <xsl:variable name="month" select="../../@index" />
241 <xsl:variable name="day" select="../@index" />
242 <xsl:variable name="input-precipitation-snowfall" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeSnowfall']" />
243 <xsl:variable name="merge-precipitation-snowfall" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeSnowfall']" />
244
245 <xsl:choose>
246 <xsl:when test="$input-precipitation-snowfall and (not($merge-precipitation-snowfall) or $input-precipitation-snowfall/text() &gt;= $merge-precipitation-snowfall/text())">
247 <xsl:copy>
248 <xsl:apply-templates select="$input-precipitation-snowfall/@*" />
249 <xsl:apply-templates select="$input-precipitation-snowfall/node()" />
250 </xsl:copy>
251 </xsl:when>
252 <xsl:otherwise>
253 <xsl:copy>
254 <xsl:apply-templates select="$merge-precipitation-snowfall/@*" />
255 <xsl:apply-templates select="$merge-precipitation-snowfall/node()" />
256 </xsl:copy>
257 </xsl:otherwise>
258 </xsl:choose>
259 </xsl:template>
260
261 <xsl:template match="precipitation[@class = 'extremePrecipitation']">
262 <xsl:variable name="month" select="../../@index" />
263 <xsl:variable name="day" select="../@index" />
264 <xsl:variable name="input-precipitation-extreme" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremePrecipitation']" />
265 <xsl:variable name="merge-precipitation-extreme" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremePrecipitation']" />
266
267 <xsl:choose>
268 <xsl:when test="$input-precipitation-extreme and (not($merge-precipitation-extreme) or $input-precipitation-extreme/text() &gt;= $merge-precipitation-extreme/text())">
269 <xsl:copy>
270 <xsl:apply-templates select="$input-precipitation-extreme/@*" />
271 <xsl:apply-templates select="$input-precipitation-extreme/node()" />
272 </xsl:copy>
273 </xsl:when>
274 <xsl:otherwise>
275 <xsl:copy>
276 <xsl:apply-templates select="$merge-precipitation-extreme/@*" />
277 <xsl:apply-templates select="$merge-precipitation-extreme/node()" />
278 </xsl:copy>
279 </xsl:otherwise>
280 </xsl:choose>
281 </xsl:template>
282
283 <xsl:template match="precipitation[@class = 'extremeSnowOnGround']">
284 <xsl:variable name="month" select="../../@index" />
285 <xsl:variable name="day" select="../@index" />
286 <xsl:variable name="input-precipitation-snow-ground" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeSnowOnGround']" />
287 <xsl:variable name="merge-precipitation-snow-ground" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeSnowOnGround']" />
288
289 <xsl:choose>
290 <xsl:when test="$input-precipitation-snow-ground and (not($merge-precipitation-snow-ground) or $input-precipitation-snow-ground/text() &gt;= $merge-precipitation-snow-ground/text())">
291 <xsl:copy>
292 <xsl:apply-templates select="$input-precipitation-snow-ground/@*" />
293 <xsl:apply-templates select="$input-precipitation-snow-ground/node()" />
294 </xsl:copy>
295 </xsl:when>
296 <xsl:otherwise>
297 <xsl:copy>
298 <xsl:apply-templates select="$merge-precipitation-snow-ground/@*" />
299 <xsl:apply-templates select="$merge-precipitation-snow-ground/node()" />
300 </xsl:copy>
301 </xsl:otherwise>
302 </xsl:choose>
303 </xsl:template>
304
305 <xsl:template match="pop">
306 <xsl:variable name="month" select="../../@index" />
307 <xsl:variable name="day" select="../@index" />
308 <xsl:variable name="input-pop" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/pop" />
309 <xsl:variable name="merge-pop" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/pop" />
310
311 <xsl:choose>
312 <xsl:when test="$input-pop and $input-pop/text() != '' and $merge-pop and $merge-pop/text() != ''">
313 <xsl:copy>
314 <xsl:apply-templates select="$input-pop/@*" />
315 <xsl:attribute name="values-count"><xsl:value-of select="$input-pop/@values-count + 1" /></xsl:attribute>
316 <xsl:value-of select="format-number(number($input-pop/text() * $input-pop/@values-count + $merge-pop/text()) div number($input-pop/@values-count + 1), '0.0')" />
317 </xsl:copy>
318 </xsl:when>
319 <xsl:when test="$input-pop != '' and (not($merge-pop) or $merge-pop = '')">
320 <xsl:copy>
321 <xsl:apply-templates select="$input-pop/@*" />
322 <xsl:apply-templates select="$input-pop/node()" />
323 </xsl:copy>
324 </xsl:when>
325 <xsl:when test="(not($input-pop) or $input-pop = '') and $merge-pop and $merge-pop/text() != ''">
326 <xsl:copy>
327 <xsl:apply-templates select="$merge-pop/@*" />
328 <xsl:attribute name="values-count">1</xsl:attribute>
329 <xsl:apply-templates select="$merge-pop/node()" />
330 </xsl:copy>
331 </xsl:when>
332 <xsl:when test="(not($input-pop) or $input-pop = '') and (not($merge-pop) or $merge-pop = '')">
333 <xsl:copy>
334 <xsl:apply-templates select="$input-pop/@*" />
335 <xsl:apply-templates select="$input-pop/node()" />
336 </xsl:copy>
337 </xsl:when>
338 <xsl:otherwise>
339 <xsl:message terminate="no">
340 <xsl:value-of select="concat($month, '-', $day, ' - pop: ', $input-pop, ' ', $merge-pop)" />
341 </xsl:message>
342 <xsl:message terminate="yes">Trapping case not supposed to happend.</xsl:message>
343 </xsl:otherwise>
344 </xsl:choose>
345 </xsl:template>
346
347 <xsl:template name="loop-day">
348 <xsl:param name="day" />
349
350 <xsl:variable name="input-day" select="$input-root/climatedata/month[@index = current()/@index]/day[@index = $day]" />
351 <xsl:variable name="merge-day" select="$merge-doc/climatedata/month[@index = current()/@index]/day[@index = $day]" />
352
353 <xsl:choose>
354 <xsl:when test="$input-day">
355 <xsl:apply-templates select="$input-day" />
356 </xsl:when>
357 <xsl:when test="$merge-day">
358 <xsl:apply-templates select="$merge-day" />
359 </xsl:when>
360 </xsl:choose>
361
362 <xsl:if test="$day &lt; 31">
363 <xsl:call-template name="loop-day">
364 <xsl:with-param name="day" select="$day + 1" />
365 </xsl:call-template>
366 </xsl:if>
367 </xsl:template>
368
369 <!-- Almanach files contain no flags -->
370 <xsl:template match="legend" />
371
372 <!-- Remove quality indicator -->
373 <xsl:template match="@quality" />
374 </xsl:stylesheet>