File: addresses2inspire-ad.jinja2

package info (click to toggle)
python-stetl 1.0.9%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 89,428 kB
  • ctags: 720
  • sloc: python: 3,527; xml: 699; sql: 428; makefile: 153; sh: 45
file content (179 lines) | stat: -rw-r--r-- 10,707 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<?xml version="1.0" encoding="UTF-8"?>
{#
This is a Jinja2 template for generating one of the most complex INSPIRE Schema's: Annex I Addresses specified in
http://inspire.jrc.ec.europa.eu/documents/Data_Specifications/INSPIRE_DataSpecification_AD_v3.1.pdf
The GML Application Schema is complex and verbose, but the actual required input is quite small.
At a minimum just 4 variables for a complete address: street, house number, postal code, city plus a point (lat,lon)
for each address. This makes Templating so powerful. The input in Stetl are both records (an array of records (dict's)
called "addresses" originating from a CSV (here addresses.csv) or possibly some database records. The other input is a
JSON file (addresses-globals.json) with global static variables, called "globs" below. The output is plain GML according to
the XSD http://inspire.ec.europa.eu/schemas/ad/3.0/Addresses.xsd to which the output also validates. Note the verbosity:
a one-line CSV address expands to 100 lines/elements of uncommented GML
 #}

{#  Macro's, a very powerful reuse mechanism, e.g. for common elements and structures like INSPIRE id and GeographicalName's. #}
{% import 'templates/macros-inspire.jinja2' as macros_inspire %}

<base:SpatialDataSet xmlns:base="urn:x-inspire:specification:gmlas:BaseTypes:3.2"
                     xmlns:AD="urn:x-inspire:specification:gmlas:Addresses:3.0"
                     xmlns:GN="urn:x-inspire:specification:gmlas:GeographicalNames:3.0"
                     xmlns:gmd="http://www.isotc211.org/2005/gmd"
                     xmlns:xlink="http://www.w3.org/1999/xlink"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xmlns:gml="http://www.opengis.net/gml/3.2"
                     xsi:schemaLocation="urn:x-inspire:specification:gmlas:BaseTypes:3.2 http://inspire.ec.europa.eu/schemas/base/3.2/BaseTypes.xsd
                            urn:x-inspire:specification:gmlas:Addresses:3.0 http://inspire.ec.europa.eu/schemas/ad/3.0/Addresses.xsd
                                urn:x-inspire:specification:gmlas:GeographicalNames:3.0 http://inspire.ec.europa.eu/schemas/gn/3.0/GeographicalNames.xsd"
                     gml:id="{{ globs.namespace }}">
    <base:identifier>
        <base:Identifier>
            <base:localId>0</base:localId>
            <base:namespace>{{ globs.namespace }}</base:namespace>
        </base:Identifier>
    </base:identifier>
    <base:metadata xsi:nil="true"/>
    {# Tracking for Address components that should appear only once, as they are xlinked as AD:component-s #}
    {% set cities = {} %}
    {% set streets = {} %}
    {% set postal_codes = {} %}

    {% for address in addresses %}
    <base:member>
        <AD:Address gml:id="{{ globs.namespace }}.Address.{{ address.address_id }}">
            <gml:identifier
                    codeSpace="{{ globs.inspire_codespace_uri }}">{{ globs.inspire_urn_prefix_id }}:{{ globs.namespace }}.Address.{{ address.address_id }}</gml:identifier>
            <AD:inspireId>
                {{ macros_inspire.render_inspire_id(globs.namespace, address.address_id) }}
            </AD:inspireId>
            <AD:position>
                <AD:GeographicPosition>
                    <AD:geometry>
                        <gml:Point gml:id="{{ globs.namespace }}.Address.{{ address.address_id }}_P"
                                   srsName="{{ globs.srs_name }}">
                            <gml:pos>{{ address.lat }} {{ address.lon }}</gml:pos>
                        </gml:Point>
                    </AD:geometry>
                    <AD:specification>entrance</AD:specification>
                    <AD:method>byOtherParty</AD:method>
                    <AD:default>true</AD:default>
                </AD:GeographicPosition>
            </AD:position>
            <AD:locator>
                <AD:AddressLocator>
                    {# In the Netherlands a house number is always required #}
                    <AD:designator>
                        <AD:LocatorDesignator>
                            <AD:designator>{{ address.house_number }}</AD:designator>
                            <AD:type>{{ globs.locator_designator.house_number }}</AD:type>
                        </AD:LocatorDesignator>
                    </AD:designator>
                    {% if address.house_letter %}
                        <!-- Optional House Letter Addition, e.g. "Huisletter" in The Netherlands -->
                        <AD:designator>
                            <AD:LocatorDesignator>
                                <AD:designator>{{ address.house_letter }}</AD:designator>
                                <AD:type>{{ globs.locator_designator.house_letter }}</AD:type>
                            </AD:LocatorDesignator>
                        </AD:designator>
                    {% endif %}
                    {% if address.house_number_add %}
                        <!-- Optional House Number Addition, e.g. Floornumber "Huisnummertoevoeging" in The Netherlands -->
                        <AD:designator>
                            <AD:LocatorDesignator>
                                <AD:designator>{{ address.house_number_add }}</AD:designator>
                                <AD:type>{{ globs.locator_designator.house_number_add }}</AD:type>
                            </AD:LocatorDesignator>
                        </AD:designator>
                    {% endif %}
                    <AD:level>unitLevel</AD:level>
                </AD:AddressLocator>
            </AD:locator>
            <AD:validFrom>{{ globs.valid_from }}</AD:validFrom>
            <AD:validTo xsi:nil="true" nilReason="other:unpopulated"/>

            <AD:beginLifespanVersion xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:endLifespanVersion xsi:nil="true" nilReason="other:unpopulated"/>
            <!-- Inline reference to address components: street (ThoroughfareName_, city (AddressAreaName)
            and postal code (PostalDescriptor)  -->
            <AD:component xmlns:xlink="http://www.w3.org/1999/xlink"
                       xlink:href="#{{ globs.namespace }}.ThoroughfareName.{{ address.street_id }}"/>
            <AD:component xmlns:xlink="http://www.w3.org/1999/xlink"
                       xlink:href="#{{ globs.namespace }}.AddressAreaName.{{ address.city_id }}"/>
            <AD:component xmlns:xlink="http://www.w3.org/1999/xlink"
                       xlink:href="#{{ globs.namespace }}.PostalDescriptor.{{ address.postal_code }}"/>
        </AD:Address>
    </base:member>
        {% if streets[address.street_id] is not defined %}
          {# Each street (BAG id) may appear only once within the Spatial Dataset.
            Track the unique street id in a map (dict) and check below to add only once. #}
          {% do streets.update({address.street_id:address.street_id}) %}

    <base:member>
        <AD:ThoroughfareName gml:id="{{ globs.namespace }}.ThoroughfareName.{{ address.street_id }}">
            <gml:identifier codeSpace="{{ globs.inspire_codespace_uri }}">
                {{ globs.inspire_urn_prefix_id }}:{{ globs.namespace }}.ThoroughfareName.{{ address.street_id }}
            </gml:identifier>
            <AD:inspireId>
                {{ macros_inspire.render_inspire_id(globs.namespace, address.street_id) }}
            </AD:inspireId>
            <AD:beginLifespanVersion xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:endLifespanVersion xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:validFrom>{{ globs.valid_from }}</AD:validFrom>
            <AD:validTo xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:name>
                <AD:ThoroughfareNameValue>
                    <AD:name>
                        {{ macros_inspire.render_geographical_name(address.street_name, globs.geographical_name) }}
                    </AD:name>
                </AD:ThoroughfareNameValue>
            </AD:name>
        </AD:ThoroughfareName>
    </base:member>
        {% endif %}
        {% if cities[address.city_id] is not defined %}
          {# Each city may appear only once within the Spatial Dataset.
            Track the unique city id in a map (dict) and check below to add only once. #}
          {% do cities.update({address.city_id:address.city_id}) %}
    <base:member>
        <AD:AddressAreaName gml:id="{{ globs.namespace }}.AddressAreaName.{{ address.city_id }}">
            <gml:identifier codeSpace="{{ globs.inspire_codespace_uri }}">
                {{ globs.inspire_urn_prefix_id }}:{{ globs.namespace }}.AddressAreaName.{{ address.city_id }}
            </gml:identifier>
            <AD:inspireId>
                {{ macros_inspire.render_inspire_id(globs.namespace, address.city_id) }}
            </AD:inspireId>
            <AD:beginLifespanVersion xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:endLifespanVersion xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:validFrom>{{ globs.valid_from }}</AD:validFrom>
            <AD:validTo xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:name>
                {{ macros_inspire.render_geographical_name(address.city_name, globs.geographical_name) }}
            </AD:name>
            <AD:namedPlace xsi:nil="true" nilReason="other:unpopulated"/>
        </AD:AddressAreaName>
    </base:member>
        {% endif %}

        {% if postal_codes[address.postal_code] is not defined %}
          {# Each postal code (NL Postcode) may appear only once within the Spatial Dataset.
            Track the unique posatl codes id in a map (dict) and check below to add only once. #}
          {% do postal_codes.update({address.postal_code:address.postal_code}) %}
    <base:member>
        <AD:PostalDescriptor gml:id="{{ globs.namespace }}.PostalDescriptor.{{ address.postal_code }}">
            <gml:identifier codeSpace="{{ globs.inspire_codespace_uri }}">
                {{ globs.inspire_urn_prefix_id }}:{{ globs.namespace }}.PostalDescriptor.{{ address.postal_code }}
            </gml:identifier>
            <AD:inspireId>
                {{ macros_inspire.render_inspire_id(globs.namespace, address.postal_code) }}
           </AD:inspireId>
            <AD:beginLifespanVersion xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:endLifespanVersion xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:validFrom>{{ globs.valid_from }}</AD:validFrom>
            <AD:validTo xsi:nil="true" nilReason="other:unpopulated"/>
            <AD:postCode>{{ address.postal_code }}</AD:postCode>
        </AD:PostalDescriptor>
    </base:member>
        {% endif %}
    {% endfor %}

</base:SpatialDataSet>