Coverage for gws-app/gws/base/ows/server/templatelib.py: 0%
76 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
1"""Helper functions for OWS service templates."""
3from typing import Optional, Callable
5import gws
6import gws.gis.gml
7import gws.lib.mime
8import gws.lib.uom
9import gws.lib.xmlx as xmlx
11from . import core, request
14# OGC 06-121r9 Table 34
15# Ordered sequence of two double values in decimal degrees, with longitude before latitude
16def ows_wgs84_bounding_box(lc: core.LayerCaps):
17 return (
18 'ows:WGS84BoundingBox',
19 ('ows:LowerCorner', coord_dms(lc.layer.wgsExtent[0]), ' ', coord_dms(lc.layer.wgsExtent[1])),
20 ('ows:UpperCorner', coord_dms(lc.layer.wgsExtent[2]), ' ', coord_dms(lc.layer.wgsExtent[3]))
21 )
24# OGC 06-121r3 sec 7.4.4
25def ows_service_identification(ta: request.TemplateArgs):
26 md = ta.service.metadata
28 return (
29 'ows:ServiceIdentification',
30 ('ows:Title', md.title),
31 ('ows:Abstract', md.abstract),
32 ows_keywords(md),
33 ('ows:ServiceType', ta.service.protocol),
34 ('ows:ServiceTypeVersion', ta.version),
35 ('ows:Fees', md.fees) if md.fees else None,
36 ('ows:AccessConstraints', md.accessConstraints[0].title) if md.accessConstraints else None,
37 )
40# OGC 06-121r3 sec 7.4.5
41def ows_service_provider(ta: request.TemplateArgs):
42 md = ta.service.metadata
44 return (
45 'ows:ServiceProvider',
46 ('ows:ProviderName', md.contactProviderName),
47 ('ows:ProviderSite', {'xlink:href': md.contactProviderSite}),
48 (
49 'ows:ServiceContact',
50 ('ows:IndividualName', md.contactPerson),
51 ('ows:PositionName', md.contactPosition),
52 (
53 'ows:ContactInfo',
54 (
55 'ows:Phone',
56 ('ows:Voice', md.contactPhone),
57 ('ows:Facsimile', md.contactFax)
58 ),
59 (
60 'ows:Address',
61 ('ows:DeliveryPoint', md.contactAddress),
62 ('ows:City', md.contactCity),
63 ('ows:AdministrativeArea', md.contactArea),
64 ('ows:PostalCode', md.contactZip),
65 ('ows:Country', md.contactCountry),
66 ('ows:ElectronicMailAddress', md.contactEmail),
67 ),
68 ('ows:OnlineResource', {'xlink:href': md.contactUrl}),
69 ),
70 ('ows:Role', md.contactRole)
71 )
72 )
75# OGC 06-121r3 table 15,16,17
76# OGC 06-121r3 11.2:
77# A URL prefix is defined as a string including... mandatory question mark
79def ows_service_url(ta: request.TemplateArgs, get=True, post=False):
80 if get:
81 yield 'ows:DCP/ows:HTTP/ows:Get', {'xlink:type': 'simple', 'xlink:href': ta.serviceUrl + '?'}
82 if post:
83 yield 'ows:DCP/ows:HTTP/ows:Post', {'xlink:type': 'simple', 'xlink:href': ta.serviceUrl}
86def ows_value(value):
87 return 'ows:Value', value
90def online_resource(url):
91 return 'OnlineResource', {'xlink:type': 'simple', 'xlink:href': url}
94# OGC 01-068r3, 6.2.2
95# The URL prefix shall end in either a '?' (in the absence of additional server-specific parameters) or a '&'.
96# OGC 06-042, 6.3.3
97# A URL prefix is defined... as a string including... mandatory question mark
99def dcp_service_url(ta: request.TemplateArgs):
100 return 'DCPType/HTTP/Get', online_resource(ta.serviceUrl + '?')
103def legend_url(ta: request.TemplateArgs, lc: core.LayerCaps):
104 _, _, name = xmlx.namespace.split_name(lc.layerNameQ)
105 return (
106 'LegendURL',
107 ('Format', 'image/png'),
108 online_resource(f'{ta.serviceUrl}?request=GetLegendGraphic&layer={name}'))
111def ows_keywords(md: gws.Metadata):
112 return _keywords(md, 'ows:Keywords', 'ows:Keyword')
115def keywords(md: gws.Metadata):
116 return _keywords(md, 'KeywordList', 'Keyword')
119def _keywords(md: gws.Metadata, container_name, tag_name):
120 kws = []
122 if md.keywords:
123 for kw in md.keywords:
124 kws.append((tag_name, kw))
125 if md.inspireTheme:
126 kws.append((tag_name, md.inspireThemeNameEn, {'vocabulary': 'GEMET - INSPIRE themes'}))
127 if md.isoTopicCategories:
128 for cat in md.isoTopicCategories:
129 kws.append((tag_name, cat, {'vocabulary': 'ISO 19115:2003'}))
130 if md.inspireMandatoryKeyword:
131 kws.append((tag_name, md.inspireMandatoryKeyword, {'vocabulary': 'ISO'}))
133 if kws:
134 return container_name, kws
137def lon_lat_envelope(lc: core.LayerCaps):
138 return (
139 'lonLatEnvelope',
140 {'srsName': 'urn:ogc:def:crs:OGC:1.3:CRS84'},
141 ('gml:pos', coord_dms(lc.layer.wgsExtent[0]), ' ', coord_dms(lc.layer.wgsExtent[1])),
142 ('gml:pos', coord_dms(lc.layer.wgsExtent[2]), ' ', coord_dms(lc.layer.wgsExtent[3])),
143 )
146# Nested format (WFS 1, WMS):
147# OGC 06-042 7.2.4.6.11
148# The "type" attribute indicates the standard... The enclosed <Format> element... etc
150def meta_links_nested(ta: request.TemplateArgs, md: gws.Metadata):
151 if md.metaLinks:
152 for ml in md.metaLinks:
153 yield meta_url_nested(ta, ml, 'MetadataURL')
156def meta_url_nested(ta: request.TemplateArgs, ml: gws.MetadataLink, name: str):
157 if ml:
158 yield name, {'type': ml.type}, ('Format', ml.format), online_resource(ta.url_for(ml.url))
161# Simple format (WFS 2)
162# OGC 09-025r1 Table 11
163# The xlink:href element shall be used to reference any metadata.
164# The optional about attribute may be used to reference the aspect of the element which includes
165# this wfs:MetadataURL element that this metadata provides more information about.
166# (whatever that means)
168def meta_links_simple(ta: request.TemplateArgs, md: gws.Metadata):
169 if md.metaLinks:
170 for ml in md.metaLinks:
171 yield meta_url_simple(ta, ml, 'MetadataURL')
174def meta_url_simple(ta: request.TemplateArgs, ml: gws.MetadataLink, name: str):
175 if ml:
176 yield name, {'xlink:href': ta.url_for(ml.url), 'about': ml.about}
179# http://inspire.ec.europa.eu/schemas/common/1.0/network.xsd
180# Scenario 2: Mandatory (where appropriate) metadata elements not mapped to standard capabilities,
181# plus mandatory language parameters,
182# plus OPTIONAL MetadataUrl pointing to an INSPIRE Compliant ISO metadata document
184def inspire_extended_capabilities(ta: request.TemplateArgs):
185 md = ta.service.metadata
186 return [
187 (
188 'inspire_common:ResourceLocator',
189 ('inspire_common:URL', ta.serviceUrl),
190 ('inspire_common:MediaType', 'application/xml'),
191 ),
192 ('inspire_common:ResourceType', md.inspireResourceType),
193 ('inspire_common:TemporalReference/inspire_common:DateOfPublication', md.dateCreated),
195 (
196 'inspire_common:Conformity',
197 (
198 'inspire_common:Specification', {'xsi:type': 'inspire_common:citationInspireInteroperabilityRegulation_eng'},
199 ('inspire_common:Title', 'COMMISSION REGULATION (EU) No 1089/2010 of 23 November 2010 implementing Directive 2007/2/EC of the European Parliament and of the Council as regards interoperability of spatial data sets and services'),
200 ('inspire_common:DateOfPublication', '2010-12-08'),
201 ('inspire_common:URI', 'OJ:L:2010:323:0011:0102:EN:PDF'),
202 (
203 'inspire_common:ResourceLocator',
204 ('inspire_common:URL', 'http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=OJ:L:2010:323:0011:0102:EN:PDF'),
205 ('inspire_common:MediaType', 'application/pdf'),
206 ),
207 ),
208 ('inspire_common:Degree', md.inspireDegreeOfConformity),
209 ),
210 (
211 'inspire_common:MetadataPointOfContact',
212 ('inspire_common:OrganisationName', md.contactOrganization),
213 ('inspire_common:EmailAddress', md.contactEmail),
214 ),
216 ('inspire_common:MetadataDate', md.dateCreated),
217 ('inspire_common:SpatialDataServiceType', md.inspireSpatialDataServiceType),
218 ('inspire_common:MandatoryKeyword/inspire_common:KeywordValue', md.inspireMandatoryKeyword),
220 (
221 'inspire_common:Keyword',
222 (
223 'inspire_common:OriginatingControlledVocabulary',
224 ('inspire_common:Title', 'INSPIRE themes'),
225 ('inspire_common:DateOfPublication', '2008-06-01'),
226 ),
227 ('inspire_common:KeywordValue', md.inspireThemeNameEn),
228 ),
230 (
231 'inspire_common:SupportedLanguages',
232 ('inspire_common:DefaultLanguage/inspire_common:Language', md.language3),
233 ('inspire_common:SupportedLanguage/inspire_common:Language', md.language3),
234 ),
236 ('inspire_common:ResponseLanguage/inspire_common:Language', md.language3)
237 ]
240def coord_dms(n):
241 return round(n, gws.lib.uom.DEFAULT_PRECISION[gws.Uom.deg])
244def coord_m(n):
245 return round(n, gws.lib.uom.DEFAULT_PRECISION[gws.Uom.m])
248def to_xml_response(ta: request.TemplateArgs, tag, extra_namespaces: Optional[list[gws.XmlNamespace]] = None) -> gws.ContentResponse:
249 if ta.sr.isSoap:
250 tag = 'soap:Envelope', ('soap:Header', ''), ('soap:Body', tag)
252 el = xmlx.tag(*tag)
253 xml = el.to_string(
254 extra_namespaces=extra_namespaces,
255 with_xml_declaration=True,
256 with_namespace_declarations=True,
257 with_schema_locations=True
258 )
260 return gws.ContentResponse(mime=gws.lib.mime.XML, content=xml)