1 <?xml version=
"1.0" encoding=
"UTF-8"?>
3 <!-- eccc_merger.xslt - Merge XML historical data as provided by
4 Environment and Climate Change Canada
5 Copyright (C) 2020 Pierre Choffet
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.
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.
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/>.
21 Rounding is always done one digit after decimal point.
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
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">
40 <xsl:output method=
"xml" encoding=
"utf-8" />
42 <xsl:variable name=
"input-root" select=
"/" />
43 <xsl:variable name=
"merge-doc" select=
"document($merge-path)" />
46 <xsl:template match=
"@*|node()">
48 <xsl:apply-templates select=
"@*|node()" />
52 <xsl:template match=
"/climatedata">
54 <!-- Upon first merge, import missing metadata elements -->
55 <xsl:if test=
"not(lang)">
56 <xsl:apply-templates select=
"$merge-doc/climatedata/lang" />
58 <xsl:if test=
"not(stationinformation)">
59 <xsl:apply-templates select=
"$merge-doc/climatedata/stationinformation" />
62 <xsl:apply-templates select=
"@*|node()" />
66 <xsl:template match=
"month">
68 <xsl:apply-templates select=
"@index" />
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" />
77 <xsl:template match=
"day">
79 <xsl:attribute name=
"index">
80 <xsl:value-of select=
"@index" />
83 <xsl:apply-templates match=
"node()" />
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']" />
94 <xsl:when test=
"$input-extreme-max and (not($merge-extreme-max) or $input-extreme-max/text() >= $merge-extreme-max/text())">
96 <xsl:apply-templates select=
"$input-extreme-max/@*" />
97 <xsl:apply-templates select=
"$input-extreme-max/node()" />
102 <xsl:apply-templates select=
"$merge-extreme-max/@*" />
103 <xsl:apply-templates select=
"$merge-extreme-max/node()" />
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']" />
116 <xsl:when test=
"$input-extreme-min and (not($merge-extreme-min) or $input-extreme-min/text() <= merge-extreme-min/text())">
118 <xsl:apply-templates select=
"$input-extreme-min/@*" />
119 <xsl:apply-templates select=
"$input-extreme-min/node()" />
124 <xsl:apply-templates select=
"$merge-extreme-min/@*" />
125 <xsl:apply-templates select=
"$merge-extreme-min/node()" />
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']" />
138 <xsl:when test=
"$input-normal-max and (not($merge-normal-max) or $input-normal-max/text() >= $merge-normal-max/text())">
140 <xsl:apply-templates select=
"$input-normal-max/@*" />
141 <xsl:apply-templates select=
"$input-normal-max/node()" />
146 <xsl:apply-templates select=
"$merge-normal-max/@*" />
147 <xsl:apply-templates select=
"$merge-normal-max/node()" />
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']" />
160 <xsl:when test=
"$input-normal-min and (not($merge-normal-min) or $input-normal-min/text() <= $merge-normal-min/text())">
162 <xsl:apply-templates select=
"$input-normal-min/@*" />
163 <xsl:apply-templates select=
"$input-normal-min/node()" />
168 <xsl:apply-templates select=
"$merge-normal-min/@*" />
169 <xsl:apply-templates select=
"$merge-normal-min/node()" />
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']" />
182 <xsl:when test=
"$input-normal-mean and $input-normal-mean/text() != '' and $merge-normal-mean and $merge-normal-mean/text() != ''">
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')" />
189 <xsl:when test=
"$input-normal-mean != '' and (not($merge-normal-mean) or $merge-normal-mean = '')">
191 <xsl:apply-templates select=
"$input-normal-mean/@*" />
192 <xsl:apply-templates select=
"$input-normal-mean/node()" />
195 <xsl:when test=
"(not($input-normal-mean) or $input-normal-mean = '') and $merge-normal-mean and $merge-normal-mean != ''">
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()" />
202 <xsl:when test=
"$input-normal-mean = '' and $merge-normal-mean = ''">
204 <xsl:apply-templates select=
"$input-normal-mean/@*" />
205 <xsl:apply-templates select=
"$input-normal-mean/node()" />
209 <xsl:message terminate=
"no">
210 <xsl:value-of select=
"concat($month, '-', $day, ' - normalMean: ', $input-normal-mean, ' ', $merge-normal-mean)" />
212 <xsl:message terminate=
"yes">Trapping case not supposed to happend.
</xsl:message>
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']" />
224 <xsl:when test=
"$input-precipitation-rainfall and (not($merge-precipitation-rainfall) or $input-precipitation-rainfall/text() >= $merge-precipitation-rainfall/text())">
226 <xsl:apply-templates select=
"$input-precipitation-rainfall/@*" />
227 <xsl:apply-templates select=
"$input-precipitation-rainfall/node()" />
232 <xsl:apply-templates select=
"$merge-precipitation-rainfall/@*" />
233 <xsl:apply-templates select=
"$merge-precipitation-rainfall/node()" />
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']" />
246 <xsl:when test=
"$input-precipitation-snowfall and (not($merge-precipitation-snowfall) or $input-precipitation-snowfall/text() >= $merge-precipitation-snowfall/text())">
248 <xsl:apply-templates select=
"$input-precipitation-snowfall/@*" />
249 <xsl:apply-templates select=
"$input-precipitation-snowfall/node()" />
254 <xsl:apply-templates select=
"$merge-precipitation-snowfall/@*" />
255 <xsl:apply-templates select=
"$merge-precipitation-snowfall/node()" />
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']" />
268 <xsl:when test=
"$input-precipitation-extreme and (not($merge-precipitation-extreme) or $input-precipitation-extreme/text() >= $merge-precipitation-extreme/text())">
270 <xsl:apply-templates select=
"$input-precipitation-extreme/@*" />
271 <xsl:apply-templates select=
"$input-precipitation-extreme/node()" />
276 <xsl:apply-templates select=
"$merge-precipitation-extreme/@*" />
277 <xsl:apply-templates select=
"$merge-precipitation-extreme/node()" />
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']" />
290 <xsl:when test=
"$input-precipitation-snow-ground and (not($merge-precipitation-snow-ground) or $input-precipitation-snow-ground/text() >= $merge-precipitation-snow-ground/text())">
292 <xsl:apply-templates select=
"$input-precipitation-snow-ground/@*" />
293 <xsl:apply-templates select=
"$input-precipitation-snow-ground/node()" />
298 <xsl:apply-templates select=
"$merge-precipitation-snow-ground/@*" />
299 <xsl:apply-templates select=
"$merge-precipitation-snow-ground/node()" />
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" />
312 <xsl:when test=
"$input-pop and $input-pop/text() != '' and $merge-pop and $merge-pop/text() != ''">
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')" />
319 <xsl:when test=
"$input-pop != '' and (not($merge-pop) or $merge-pop = '')">
321 <xsl:apply-templates select=
"$input-pop/@*" />
322 <xsl:apply-templates select=
"$input-pop/node()" />
325 <xsl:when test=
"(not($input-pop) or $input-pop = '') and $merge-pop and $merge-pop/text() != ''">
327 <xsl:apply-templates select=
"$merge-pop/@*" />
328 <xsl:attribute name=
"values-count">1</xsl:attribute>
329 <xsl:apply-templates select=
"$merge-pop/node()" />
332 <xsl:when test=
"(not($input-pop) or $input-pop = '') and (not($merge-pop) or $merge-pop = '')">
334 <xsl:apply-templates select=
"$input-pop/@*" />
335 <xsl:apply-templates select=
"$input-pop/node()" />
339 <xsl:message terminate=
"no">
340 <xsl:value-of select=
"concat($month, '-', $day, ' - pop: ', $input-pop, ' ', $merge-pop)" />
342 <xsl:message terminate=
"yes">Trapping case not supposed to happend.
</xsl:message>
347 <xsl:template name=
"loop-day">
348 <xsl:param name=
"day" />
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]" />
354 <xsl:when test=
"$input-day">
355 <xsl:apply-templates select=
"$input-day" />
357 <xsl:when test=
"$merge-day">
358 <xsl:apply-templates select=
"$merge-day" />
362 <xsl:if test=
"$day < 31">
363 <xsl:call-template name=
"loop-day">
364 <xsl:with-param name=
"day" select=
"$day + 1" />
369 <!-- Almanach files contain no flags -->
370 <xsl:template match=
"legend" />
372 <!-- Remove quality indicator -->
373 <xsl:template match=
"@quality" />