Coverage for gws-app/gws/plugin/ows_server/csw/templates/iso/record.py: 94%
67 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 23:09 +0200
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 23:09 +0200
1""" "CSW Record template (gmd:MD_Metadata, ISO)."""
3import gws
4import gws.base.ows.server as server
5import gws.base.ows.server.templatelib as tpl
7ML_GMX_CODELISTS = 'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml'
10def record(ta: server.TemplateArgs, md: gws.Metadata):
11 def w_code(wrap, lst, value, text=None):
12 return (
13 f'gmd:{wrap}/gmd:{lst}',
14 {'codeList': ML_GMX_CODELISTS + '#' + lst, 'codeListValue': value},
15 text or value,
16 )
18 def w_date(d, typ):
19 return (
20 'gmd:date/gmd:CI_Date',
21 ('gmd:date/gco:Date', tpl.iso_date(d)),
22 w_code(
23 'dateType',
24 'CI_DateTypeCode',
25 typ,
26 ),
27 )
29 def w_lang():
30 return (
31 'gmd:language/gmd:LanguageCode',
32 {'codeList': 'http://www.loc.gov/standards/iso639-2/', 'codeListValue': md.language3},
33 md.languageName,
34 )
36 def w_bbox(ext):
37 return (
38 'gmd:EX_GeographicBoundingBox',
39 ('gmd:westBoundLongitude/gco:Decimal', tpl.coord_dms(ext[0])),
40 ('gmd:eastBoundLongitude/gco:Decimal', tpl.coord_dms(ext[2])),
41 ('gmd:southBoundLatitude/gco:Decimal', tpl.coord_dms(ext[1])),
42 ('gmd:northBoundLatitude/gco:Decimal', tpl.coord_dms(ext[3])),
43 )
45 def contact():
46 yield (
47 'gmd:CI_ResponsibleParty',
48 ('gmd:organisationName/gco:CharacterString', md.contactOrganization),
49 ('gmd:positionName/gco:CharacterString', md.contactPosition),
50 (
51 'gmd:contactInfo/gmd:CI_Contact',
52 (
53 'gmd:phone/gmd:CI_Telephone',
54 ('gmd:voice/gco:CharacterString', md.contactPhone),
55 ('gmd:facsimile/gco:CharacterString', md.contactFax),
56 ),
57 (
58 'gmd:address/gmd:CI_Address',
59 ('gmd:deliveryPoint/gco:CharacterString', md.contactAddress),
60 ('gmd:city/gco:CharacterString', md.contactCity),
61 ('gmd:administrativeArea/gco:CharacterString', md.contactArea),
62 ('gmd:postalCode/gco:CharacterString', md.contactZip),
63 ('gmd:country/gco:CharacterString', md.contactCountry),
64 ('gmd:electronicMailAddress/gco:CharacterString', md.contactEmail),
65 ),
66 ('gmd:onlineResource/gmd:CI_OnlineResource/gmd:linkage/gmd:URL', md.contactUrl),
67 ),
68 w_code('role', 'CI_RoleCode', md.contactRole),
69 )
71 def identification():
72 yield (
73 'gmd:citation/gmd:CI_Citation',
74 ('gmd:title/gco:CharacterString', md.title),
75 w_date(md.dateCreated, 'publication'),
76 w_date(md.dateUpdated, 'revision'),
77 ('gmd:identifier/gmd:MD_Identifier/gmd:code/gco:CharacterString', md.catalogCitationUid),
78 )
80 yield 'gmd:abstract/gco:CharacterString', md.abstract
82 yield 'gmd:pointOfContact', contact()
84 if md.inspireSpatialScope:
85 lst = 'http://inspire.ec.europa.eu/metadata-codelist/SpatialScope/'
86 yield (
87 'gmd:descriptiveKeywords/gmd:MD_Keywords',
88 ('gmd:keyword/gmx:Anchor', {'xlink:href': lst + md.inspireSpatialScope}, md.inspireSpatialScopeName),
89 (
90 'gmd:thesaurusName/gmd:CI_Citation',
91 ('gmd:title/gmx:Anchor', {'xlink:href': lst + 'SpatialScope'}, 'Spatial scope'),
92 w_date('2019-05-22', 'publication'),
93 ),
94 )
96 if md.inspireTheme:
97 yield (
98 'gmd:descriptiveKeywords/gmd:MD_Keywords',
99 ('gmd:keyword/gco:CharacterString', md.inspireThemeNameEn),
100 w_code('type', 'MD_KeywordTypeCode', 'theme'),
101 (
102 'gmd:thesaurusName/gmd:CI_Citation',
103 ('gmd:title/gco:CharacterString', 'GEMET - INSPIRE themes, version 1.0'),
104 w_date('2008-06-01', 'publication'),
105 ),
106 )
108 if md.keywords:
109 yield (
110 'gmd:descriptiveKeywords/gmd:MD_Keywords',
111 [('gmd:keyword/gco:CharacterString', kw) for kw in md.keywords],
112 )
114 yield (
115 'gmd:resourceConstraints/gmd:MD_LegalConstraints',
116 w_code('useConstraints', 'MD_RestrictionCode', 'otherRestrictions'),
117 ('gmd:otherConstraints/gco:CharacterString', md.accessConstraints),
118 ('gmd:otherConstraints/gco:CharacterString', md.license),
119 )
121 yield w_code(
122 'spatialRepresentationType',
123 'MD_SpatialRepresentationTypeCode',
124 md.isoSpatialRepresentationType,
125 )
127 if md.isoSpatialResolution:
128 yield (
129 'gmd:spatialResolution/gmd:MD_Resolution/gmd:equivalentScale/gmd:MD_RepresentativeFraction/gmd:denominator/gco:Integer',
130 md.isoSpatialResolution,
131 )
133 yield w_lang()
134 yield w_code('characterSet', 'MD_CharacterSetCode', 'utf8')
136 if md.isoTopicCategories:
137 for cat in md.isoTopicCategories:
138 yield 'gmd:topicCategory/gmd:MD_TopicCategoryCode', cat
140 if md.wgsExtent:
141 yield 'gmd:extent/gmd:EX_Extent/gmd:geographicElement', w_bbox(md.wgsExtent)
143 # @TODO
144 # if md.bounding_polygon_element:
145 # yield (
146 # 'gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_BoundingPolygon/gmd:polygon',
147 # md.bounding_polygon_element
148 # )
150 if md.temporalBegin:
151 yield (
152 'gmd:extent/gmd:EX_Extent/gmd:temporalElement/gmd:EX_TemporalExtent/gmd:extent/gml:TimePeriod',
153 ('gml:beginPosition', md.temporalBegin),
154 ('gml:endPosition', md.temporalEnd),
155 )
157 def distributionInfo():
158 for link in md.metaLinks:
159 if link.format:
160 yield (
161 'gmd:distributionFormat/gmd:MD_Format',
162 ('gmd:name/gco:CharacterString', link.format),
163 ('gmd:version/gco:CharacterString', link.formatVersion),
164 )
166 for link in md.metaLinks:
167 yield (
168 'gmd:transferOptions/gmd:MD_DigitalTransferOptions',
169 (
170 'gmd:onLine/gmd:CI_OnlineResource',
171 ('gmd:linkage/gmd:URL', ta.url_for(link.url)),
172 w_code('function', 'CI_OnLineFunctionCode', link.function),
173 ),
174 )
176 def dataQualityInfo():
177 yield 'gmd:scope/gmd:DQ_Scope', w_code('level', 'MD_ScopeCode', md.isoScope)
179 if md.isoQualityConformanceQualityPass:
180 yield (
181 'gmd:report/gmd:DQ_DomainConsistency/gmd:result/gmd:DQ_ConformanceResult',
182 (
183 'gmd:specification/gmd:CI_Citation',
184 ('gmd:title/gco:CharacterString', md.isoQualityConformanceSpecificationTitle),
185 w_date(md.isoQualityConformanceSpecificationDate, 'publication'),
186 ),
187 ('gmd:explanation/gco:CharacterString', md.isoQualityConformanceExplanation),
188 ('gmd:pass/gco:Boolean', md.isoQualityConformanceQualityPass),
189 )
191 if md.isoQualityLineageStatement:
192 yield (
193 'gmd:lineage/gmd:LI_Lineage',
194 ('gmd:statement/gco:CharacterString', md.isoQualityLineageStatement),
195 (
196 'gmd:source/gmd:LI_Source',
197 ('gmd:description/gco:CharacterString', md.isoQualityLineageSource),
198 ('gmd:scaleDenominator/gmd:MD_RepresentativeFraction/gmd:denominator/gco:Integer', md.isoQualityLineageSourceScale),
199 ),
200 )
202 def content():
203 yield 'gmd:fileIdentifier/gco:CharacterString', md.catalogUid
205 w_lang()
206 yield w_code('characterSet', 'MD_CharacterSetCode', 'utf8')
208 yield w_code('hierarchyLevel', 'MD_ScopeCode', md.isoScope)
209 yield 'gmd:hierarchyLevelName/gco:CharacterString', md.isoScopeName
211 yield 'gmd:contact', contact()
213 yield 'gmd:dateStamp/gco:Date', tpl.iso_date(md.dateUpdated)
215 yield 'gmd:metadataStandardName/gco:CharacterString', 'ISO19115'
216 yield 'gmd:metadataStandardVersion/gco:CharacterString', '2003/Cor.1:2006'
218 if md.crs:
219 yield (
220 'gmd:referenceSystemInfo/gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:code/gco:CharacterString',
221 md.crs.uri,
222 )
224 yield 'gmd:identificationInfo/gmd:MD_DataIdentification', identification()
225 yield 'gmd:distributionInfo/gmd:MD_Distribution', distributionInfo()
226 yield 'gmd:dataQualityInfo/gmd:DQ_DataQuality', dataQualityInfo()
228 ##
230 return 'gmd:MD_Metadata', content()