]> Wikimedia Canada | Git repositories - eccc_to_commons.git/blob - eccc_merger_almanach.xslt
Add ECCC almanach XML merger
[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/text() = '')">
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) and $merge-normal-mean and $merge-normal-mean/text() != ''">
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:choose>
203 </xsl:template>
204
205 <xsl:template match="precipitation[@class = 'extremeRainfall']">
206 <xsl:variable name="month" select="../../@index" />
207 <xsl:variable name="day" select="../@index" />
208 <xsl:variable name="input-precipitation-rainfall" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeRainfall']" />
209 <xsl:variable name="merge-precipitation-rainfall" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeRainfall']" />
210
211 <xsl:choose>
212 <xsl:when test="$input-precipitation-rainfall and (not($merge-precipitation-rainfall) or $input-precipitation-rainfall/text() &gt;= $merge-precipitation-rainfall/text())">
213 <xsl:copy>
214 <xsl:apply-templates select="$input-precipitation-rainfall/@*" />
215 <xsl:apply-templates select="$input-precipitation-rainfall/node()" />
216 </xsl:copy>
217 </xsl:when>
218 <xsl:otherwise>
219 <xsl:copy>
220 <xsl:apply-templates select="$merge-precipitation-rainfall/@*" />
221 <xsl:apply-templates select="$merge-precipitation-rainfall/node()" />
222 </xsl:copy>
223 </xsl:otherwise>
224 </xsl:choose>
225 </xsl:template>
226
227 <xsl:template match="precipitation[@class = 'extremeSnowfall']">
228 <xsl:variable name="month" select="../../@index" />
229 <xsl:variable name="day" select="../@index" />
230 <xsl:variable name="input-precipitation-snowfall" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeSnowfall']" />
231 <xsl:variable name="merge-precipitation-snowfall" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeSnowfall']" />
232
233 <xsl:choose>
234 <xsl:when test="$input-precipitation-snowfall and (not($merge-precipitation-snowfall) or $input-precipitation-snowfall/text() &gt;= $merge-precipitation-snowfall/text())">
235 <xsl:copy>
236 <xsl:apply-templates select="$input-precipitation-snowfall/@*" />
237 <xsl:apply-templates select="$input-precipitation-snowfall/node()" />
238 </xsl:copy>
239 </xsl:when>
240 <xsl:otherwise>
241 <xsl:copy>
242 <xsl:apply-templates select="$merge-precipitation-snowfall/@*" />
243 <xsl:apply-templates select="$merge-precipitation-snowfall/node()" />
244 </xsl:copy>
245 </xsl:otherwise>
246 </xsl:choose>
247 </xsl:template>
248
249 <xsl:template match="precipitation[@class = 'extremePrecipitation']">
250 <xsl:variable name="month" select="../../@index" />
251 <xsl:variable name="day" select="../@index" />
252 <xsl:variable name="input-precipitation-extreme" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremePrecipitation']" />
253 <xsl:variable name="merge-precipitation-extreme" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremePrecipitation']" />
254
255 <xsl:choose>
256 <xsl:when test="$input-precipitation-extreme and (not($merge-precipitation-extreme) or $input-precipitation-extreme/text() &gt;= $merge-precipitation-extreme/text())">
257 <xsl:copy>
258 <xsl:apply-templates select="$input-precipitation-extreme/@*" />
259 <xsl:apply-templates select="$input-precipitation-extreme/node()" />
260 </xsl:copy>
261 </xsl:when>
262 <xsl:otherwise>
263 <xsl:copy>
264 <xsl:apply-templates select="$merge-precipitation-extreme/@*" />
265 <xsl:apply-templates select="$merge-precipitation-extreme/node()" />
266 </xsl:copy>
267 </xsl:otherwise>
268 </xsl:choose>
269 </xsl:template>
270
271 <xsl:template match="precipitation[@class = 'extremeSnowOnGround']">
272 <xsl:variable name="month" select="../../@index" />
273 <xsl:variable name="day" select="../@index" />
274 <xsl:variable name="input-precipitation-snow-ground" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeSnowOnGround']" />
275 <xsl:variable name="merge-precipitation-snow-ground" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/precipitation[@class = 'extremeSnowOnGround']" />
276
277 <xsl:choose>
278 <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())">
279 <xsl:copy>
280 <xsl:apply-templates select="$input-precipitation-snow-ground/@*" />
281 <xsl:apply-templates select="$input-precipitation-snow-ground/node()" />
282 </xsl:copy>
283 </xsl:when>
284 <xsl:otherwise>
285 <xsl:copy>
286 <xsl:apply-templates select="$merge-precipitation-snow-ground/@*" />
287 <xsl:apply-templates select="$merge-precipitation-snow-ground/node()" />
288 </xsl:copy>
289 </xsl:otherwise>
290 </xsl:choose>
291 </xsl:template>
292
293 <xsl:template match="pop">
294 <xsl:variable name="month" select="../../@index" />
295 <xsl:variable name="day" select="../@index" />
296 <xsl:variable name="input-pop" select="$input-root/climatedata/month[@index = $month]/day[@index = $day]/pop" />
297 <xsl:variable name="merge-pop" select="$merge-doc/climatedata/month[@index = $month]/day[@index = $day]/pop" />
298
299 <xsl:choose>
300 <xsl:when test="$input-pop and $input-pop/text() != '' and $merge-pop and $merge-pop/text() != ''">
301 <xsl:copy>
302 <xsl:apply-templates select="$input-pop/@*" />
303 <xsl:attribute name="values-count"><xsl:value-of select="$input-pop/@values-count + 1" /></xsl:attribute>
304 <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')" />
305 </xsl:copy>
306 </xsl:when>
307 <xsl:when test="$input-pop and (not($merge-pop) or $merge-pop/text() = '')">
308 <xsl:copy>
309 <xsl:apply-templates select="$input-pop/@*" />
310 <xsl:apply-templates select="$input-pop/node()" />
311 </xsl:copy>
312 </xsl:when>
313 <xsl:when test="not($input-pop) and $merge-pop and $merge-pop/text() != ''">
314 <xsl:copy>
315 <xsl:apply-templates select="$merge-pop/@*" />
316 <xsl:attribute name="values-count">1</xsl:attribute>
317 <xsl:apply-templates select="$merge-pop/node()" />
318 </xsl:copy>
319 </xsl:when>
320 </xsl:choose>
321 </xsl:template>
322
323 <xsl:template name="loop-day">
324 <xsl:param name="day" />
325
326 <xsl:variable name="input-day" select="$input-root/climatedata/month[@index = current()/@index]/day[@index = $day]" />
327 <xsl:variable name="merge-day" select="$merge-doc/climatedata/month[@index = current()/@index]/day[@index = $day]" />
328
329 <xsl:choose>
330 <xsl:when test="$input-day">
331 <xsl:apply-templates select="$input-day" />
332 </xsl:when>
333 <xsl:when test="$merge-day">
334 <xsl:apply-templates select="$merge-day" />
335 </xsl:when>
336 </xsl:choose>
337
338 <xsl:if test="$day &lt; 31">
339 <xsl:call-template name="loop-day">
340 <xsl:with-param name="day" select="$day + 1" />
341 </xsl:call-template>
342 </xsl:if>
343 </xsl:template>
344
345 <!-- Almanach files contain no flags -->
346 <xsl:template match="legend" />
347
348 <!-- Remove quality indicator -->
349 <xsl:template match="@quality" />
350 </xsl:stylesheet>