--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- almanac_to_commons.xslt - Convert Environment and Climate change Canada
+ historical XML data into a JSON format suitable
+ for Wikimedia Commons.
+ Copyright (C) 2019-2020 Pierre Choffet
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:output method="text" encoding="utf-8" />
+
+ <xsl:template match="/climatedata">
+ <xsl:variable name="station-name">
+ <xsl:call-template name="camel-case">
+ <xsl:with-param name="text" select="/climatedata/stationinformation/name/text()" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="province-name">
+ <xsl:call-template name="camel-case">
+ <xsl:with-param name="text" select="/climatedata/stationinformation/province/text()" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:text>{
+ "license": "CC0-1.0",
+ "description": {
+ "en": "</xsl:text><xsl:value-of select="$station-name" /><xsl:text> average and extreme data",
+ "fr": "Moyennes et extrêmes pour la station météorologique </xsl:text><xsl:value-of select="$station-name" /><xsl:text>"
+ },
+ "sources": "[https://climate.weather.gc.ca/ Environment and Climate Change Canada]",
+ "categories": "[Category:Environment and Climate Change Canada Almanac Data] [Category:Weather Data in </xsl:text>
+ <xsl:value-of select="$province-name" />
+ <xsl:text>]",
+ "schema": {
+ "fields": [
+ {
+ "name": "date",
+ "type": "string",
+ "title": {
+ "ar": "تاريخ",
+ "ca": "Data",
+ "da": "Dato",
+ "de": "Datum",
+ "en": "Date",
+ "es": "Fecha",
+ "fr": "Date",
+ "ru": "Дата",
+ "sr": "Датум"
+ }
+ },
+ {
+ "name": "extremeMax",
+ "type": "number",
+ "title": {
+ "en": "Highest maximum temperature",
+ "fr": "Température maximale la plus élevée"
+ }
+ },
+ {
+ "name": "extremeMin",
+ "type": "number",
+ "title": {
+ "en": "Lowest minimum temperature",
+ "fr": "Température minimale la plus basse"
+ }
+ },
+ {
+ "name": "normalMax",
+ "type": "number",
+ "title": {
+ "en": "Highest normal temperature",
+ "fr": "Température normale haute"
+ }
+ },
+ {
+ "name": "normalMin",
+ "type": "number",
+ "title": {
+ "en": "Lowest normal temperature",
+ "fr": "Température normale basse"
+ }
+ },
+ {
+ "name": "normalMean",
+ "type": "number",
+ "title": {
+ "en": "Mean normal temperature",
+ "fr": "Température normale moyenne"
+ }
+ },
+ {
+ "name": "extremeRainfall",
+ "type": "number",
+ "title": {
+ "en": "Greatest rainfall",
+ "fr": "Pluie maximale"
+ }
+ },
+ {
+ "name": "extremeSnowfall",
+ "type": "number",
+ "title": {
+ "en": "Greatest snowfall",
+ "fr": "Neige maximale"
+ }
+ },
+ {
+ "name": "extremePrecipitation",
+ "type": "number",
+ "title": {
+ "en": "Greatest precipitation",
+ "fr": "Précipitation maximale"
+ }
+ },
+ {
+ "name": "extremeSnowOnGround",
+ "type": "number",
+ "title": {
+ "en": "Most snow on the ground",
+ "fr": "Maximum de neige au sol"
+ }
+ },
+ {
+ "name": "pop",
+ "type": "number",
+ "title": {
+ "en": "Monthly frequency of precipitation",
+ "fr": "Fréquence mensuelle de précipitation"
+ }
+ }
+ ]
+ },
+ "data": [</xsl:text>
+ <xsl:apply-templates select="month" />
+ <xsl:text>]}</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="month">
+ <!-- TODO: Check element has at least one data? -->
+ <xsl:apply-templates select="day">
+ <xsl:with-param name="month" select="format-number(@index, '00')" />
+ </xsl:apply-templates>
+ <xsl:if test="day and following-sibling::month[day]">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="day">
+ <xsl:param name="month" />
+ <xsl:param name="day" select="format-number(@index, '00')" />
+
+ <xsl:text>["</xsl:text>
+ <xsl:value-of select="$month" />-<xsl:value-of select="$day" />
+ <xsl:text>"</xsl:text>
+
+ <!-- Set extremeMax -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="temperature[@class = 'extremeMax']">
+ <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
+ </xsl:apply-templates>
+
+ <!-- Set extremeMin -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="temperature[@class = 'extremeMin']">
+ <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
+ </xsl:apply-templates>
+
+ <!-- Set normalMax -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="temperature[@class = 'normalMax']">
+ <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
+ </xsl:apply-templates>
+
+ <!-- Set normalMin -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="temperature[@class = 'normalMin']">
+ <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
+ </xsl:apply-templates>
+
+ <!-- Set normalMean -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="temperature[@class = 'normalMean']">
+ <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
+ </xsl:apply-templates>
+
+ <!-- Set extremeRainfall -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="precipitation[@class = 'extremeRainfall']">
+ <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
+ </xsl:apply-templates>
+
+ <!-- Set extremeSnowfall -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="precipitation[@class = 'extremeSnowfall']">
+ <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
+ </xsl:apply-templates>
+
+ <!-- Set extremePrecipitation -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="precipitation[@class = 'extremePrecipitation']">
+ <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
+ </xsl:apply-templates>
+
+ <!-- Set extremeSnowOnGround -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="precipitation[@class = 'extremeSnowOnGround']">
+ <xsl:with-param name="date"><xsl:value-of select="$month" />-<xsl:value-of select="$day" /></xsl:with-param>
+ </xsl:apply-templates>
+
+ <!-- Set pop -->
+ <!-- WARNING: This is not daily data, it makes no sense to have it in final dataset -->
+ <xsl:text>, </xsl:text>
+ <xsl:apply-templates select="pop" />
+
+ <xsl:text>]</xsl:text>
+ <xsl:if test="position() != last()">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="temperature[@class = 'extremeMax']">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeMax value</xsl:message>
+ <xsl:value-of select="text()" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="temperature[@class = 'extremeMin']">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeMin value</xsl:message>
+ <xsl:value-of select="text()" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="temperature[@class = 'normalMax']">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message terminate="yes">normalMax value not reviewed</xsl:message>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="temperature[@class = 'normalMin']">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message terminate="yes">normalMin value not reviewed</xsl:message>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="temperature[@class = 'normalMean']">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message terminate="yes">normalMean value not reviewed</xsl:message>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="precipitation[@class = 'extremeRainfall']">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeRainfall value</xsl:message>
+ <xsl:value-of select="text()" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="precipitation[@class = 'extremeSnowfall']">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeSnowfall value</xsl:message>
+ <xsl:value-of select="text()" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="precipitation[@class = 'extremePrecipitation']">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremePrecipitation value</xsl:message>
+ <xsl:value-of select="text()" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="precipitation[@class = 'extremeSnowOnGround']">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="contains(text(), '#')">
+ <xsl:message>WARNING: <xsl:value-of select="$date" />: Discard extremeSnowOnGround containing "#"</xsl:message>
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message>WARNING: <xsl:value-of select="$date" />: Insert not reviewed extremeSnowOnGround value</xsl:message>
+ <xsl:value-of select="text()" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="pop">
+ <xsl:param name="date" />
+
+ <xsl:choose>
+ <xsl:when test="not(text())">
+ <xsl:text>null</xsl:text>
+ </xsl:when>
+ <xsl:when test="@quality = '†'">
+ <xsl:message terminate="yes">pop value not reviewed</xsl:message>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="text()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Camel case -->
+ <xsl:template name="camel-case">
+ <xsl:param name="text" select="."/>
+ <xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
+ <xsl:variable name="lowercase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
+ <xsl:variable name="word" select="substring-before(concat($text, ' '), ' ')" />
+
+ <xsl:value-of select="translate(substring($word, 1, 1), $lowercase, $uppercase)" />
+ <xsl:value-of select="translate(substring($word, 2), $uppercase, $lowercase)" />
+
+ <xsl:if test="contains($text, ' ')">
+ <xsl:text> </xsl:text>
+ <xsl:call-template name="camel-case">
+ <xsl:with-param name="text" select="substring-after($text, ' ')"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:template>
+</xsl:stylesheet>