geonode-pycsw 3.0.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. geonode_pycsw-3.0.0b2.dist-info/METADATA +73 -0
  2. geonode_pycsw-3.0.0b2.dist-info/RECORD +382 -0
  3. geonode_pycsw-3.0.0b2.dist-info/WHEEL +5 -0
  4. geonode_pycsw-3.0.0b2.dist-info/entry_points.txt +2 -0
  5. geonode_pycsw-3.0.0b2.dist-info/licenses/LICENSE.txt +26 -0
  6. geonode_pycsw-3.0.0b2.dist-info/top_level.txt +1 -0
  7. pycsw/__init__.py +33 -0
  8. pycsw/core/__init__.py +29 -0
  9. pycsw/core/admin.py +703 -0
  10. pycsw/core/config.py +621 -0
  11. pycsw/core/etree.py +43 -0
  12. pycsw/core/formats/__init__.py +29 -0
  13. pycsw/core/formats/fmt_json.py +69 -0
  14. pycsw/core/log.py +71 -0
  15. pycsw/core/metadata.py +1996 -0
  16. pycsw/core/pygeofilter_evaluate.py +83 -0
  17. pycsw/core/repository.py +941 -0
  18. pycsw/core/schemas/ogc/cat/csw/3.0/_wrapper.xsd +14 -0
  19. pycsw/core/schemas/ogc/cat/csw/3.0/cswAll.xsd +33 -0
  20. pycsw/core/schemas/ogc/cat/csw/3.0/cswCommon.xsd +71 -0
  21. pycsw/core/schemas/ogc/cat/csw/3.0/cswGetCapabilities.xsd +80 -0
  22. pycsw/core/schemas/ogc/cat/csw/3.0/cswGetDomain.xsd +146 -0
  23. pycsw/core/schemas/ogc/cat/csw/3.0/cswGetRecordById.xsd +58 -0
  24. pycsw/core/schemas/ogc/cat/csw/3.0/cswGetRecords.xsd +391 -0
  25. pycsw/core/schemas/ogc/cat/csw/3.0/cswHarvest.xsd +95 -0
  26. pycsw/core/schemas/ogc/cat/csw/3.0/cswTransaction.xsd +187 -0
  27. pycsw/core/schemas/ogc/cat/csw/3.0/cswUnHarvest.xsd +77 -0
  28. pycsw/core/schemas/ogc/cat/csw/3.0/rec-dcmes.xsd +245 -0
  29. pycsw/core/schemas/ogc/cat/csw/3.0/rec-dcterms.xsd +101 -0
  30. pycsw/core/schemas/ogc/cat/csw/3.0/record.xsd +170 -0
  31. pycsw/core/schemas/ogc/csw/2.0.2/CSW-discovery.xsd +494 -0
  32. pycsw/core/schemas/ogc/csw/2.0.2/CSW-publication.xsd +242 -0
  33. pycsw/core/schemas/ogc/csw/2.0.2/rec-dcmes.xsd +199 -0
  34. pycsw/core/schemas/ogc/csw/2.0.2/rec-dcterms.xsd +94 -0
  35. pycsw/core/schemas/ogc/csw/2.0.2/record.xsd +138 -0
  36. pycsw/core/schemas/ogc/filter/1.1.0/expr.xsd +67 -0
  37. pycsw/core/schemas/ogc/filter/1.1.0/filter.xsd +265 -0
  38. pycsw/core/schemas/ogc/filter/1.1.0/filterCapabilities.xsd +171 -0
  39. pycsw/core/schemas/ogc/filter/1.1.0/sort.xsd +46 -0
  40. pycsw/core/schemas/ogc/filter/2.0/_wrapper.xsd +5 -0
  41. pycsw/core/schemas/ogc/filter/2.0/expr.xsd +44 -0
  42. pycsw/core/schemas/ogc/filter/2.0/filter.xsd +396 -0
  43. pycsw/core/schemas/ogc/filter/2.0/filterAll.xsd +23 -0
  44. pycsw/core/schemas/ogc/filter/2.0/filterCapabilities.xsd +286 -0
  45. pycsw/core/schemas/ogc/filter/2.0/query.xsd +70 -0
  46. pycsw/core/schemas/ogc/filter/2.0/sort.xsd +49 -0
  47. pycsw/core/schemas/ogc/gml/3.1.1/base/basicTypes.xsd +278 -0
  48. pycsw/core/schemas/ogc/gml/3.1.1/base/coordinateOperations.xsd +789 -0
  49. pycsw/core/schemas/ogc/gml/3.1.1/base/coordinateReferenceSystems.xsd +429 -0
  50. pycsw/core/schemas/ogc/gml/3.1.1/base/coordinateSystems.xsd +408 -0
  51. pycsw/core/schemas/ogc/gml/3.1.1/base/coverage.xsd +451 -0
  52. pycsw/core/schemas/ogc/gml/3.1.1/base/dataQuality.xsd +129 -0
  53. pycsw/core/schemas/ogc/gml/3.1.1/base/datums.xsd +484 -0
  54. pycsw/core/schemas/ogc/gml/3.1.1/base/defaultStyle.xsd +454 -0
  55. pycsw/core/schemas/ogc/gml/3.1.1/base/dictionary.xsd +137 -0
  56. pycsw/core/schemas/ogc/gml/3.1.1/base/direction.xsd +72 -0
  57. pycsw/core/schemas/ogc/gml/3.1.1/base/dynamicFeature.xsd +115 -0
  58. pycsw/core/schemas/ogc/gml/3.1.1/base/feature.xsd +199 -0
  59. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryAggregates.xsd +430 -0
  60. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryBasic0d1d.xsd +602 -0
  61. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryBasic2d.xsd +213 -0
  62. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryComplexes.xsd +141 -0
  63. pycsw/core/schemas/ogc/gml/3.1.1/base/geometryPrimitives.xsd +1609 -0
  64. pycsw/core/schemas/ogc/gml/3.1.1/base/gml.xsd +22 -0
  65. pycsw/core/schemas/ogc/gml/3.1.1/base/gmlBase.xsd +294 -0
  66. pycsw/core/schemas/ogc/gml/3.1.1/base/grids.xsd +76 -0
  67. pycsw/core/schemas/ogc/gml/3.1.1/base/measures.xsd +200 -0
  68. pycsw/core/schemas/ogc/gml/3.1.1/base/observation.xsd +96 -0
  69. pycsw/core/schemas/ogc/gml/3.1.1/base/referenceSystems.xsd +211 -0
  70. pycsw/core/schemas/ogc/gml/3.1.1/base/temporal.xsd +332 -0
  71. pycsw/core/schemas/ogc/gml/3.1.1/base/temporalReferenceSystems.xsd +251 -0
  72. pycsw/core/schemas/ogc/gml/3.1.1/base/temporalTopology.xsd +186 -0
  73. pycsw/core/schemas/ogc/gml/3.1.1/base/topology.xsd +459 -0
  74. pycsw/core/schemas/ogc/gml/3.1.1/base/units.xsd +170 -0
  75. pycsw/core/schemas/ogc/gml/3.1.1/base/valueObjects.xsd +361 -0
  76. pycsw/core/schemas/ogc/gml/3.1.1/smil/smil20-language.xsd +117 -0
  77. pycsw/core/schemas/ogc/gml/3.1.1/smil/smil20.xsd +234 -0
  78. pycsw/core/schemas/ogc/gml/3.2.1/basicTypes.xsd +268 -0
  79. pycsw/core/schemas/ogc/gml/3.2.1/coordinateOperations.xsd +525 -0
  80. pycsw/core/schemas/ogc/gml/3.2.1/coordinateReferenceSystems.xsd +373 -0
  81. pycsw/core/schemas/ogc/gml/3.2.1/coordinateSystems.xsd +297 -0
  82. pycsw/core/schemas/ogc/gml/3.2.1/coverage.xsd +292 -0
  83. pycsw/core/schemas/ogc/gml/3.2.1/datums.xsd +287 -0
  84. pycsw/core/schemas/ogc/gml/3.2.1/defaultStyle.xsd +453 -0
  85. pycsw/core/schemas/ogc/gml/3.2.1/deprecatedTypes.xsd +1133 -0
  86. pycsw/core/schemas/ogc/gml/3.2.1/dictionary.xsd +90 -0
  87. pycsw/core/schemas/ogc/gml/3.2.1/direction.xsd +84 -0
  88. pycsw/core/schemas/ogc/gml/3.2.1/dynamicFeature.xsd +109 -0
  89. pycsw/core/schemas/ogc/gml/3.2.1/feature.xsd +94 -0
  90. pycsw/core/schemas/ogc/gml/3.2.1/geometryAggregates.xsd +197 -0
  91. pycsw/core/schemas/ogc/gml/3.2.1/geometryBasic0d1d.xsd +277 -0
  92. pycsw/core/schemas/ogc/gml/3.2.1/geometryBasic2d.xsd +124 -0
  93. pycsw/core/schemas/ogc/gml/3.2.1/geometryComplexes.xsd +95 -0
  94. pycsw/core/schemas/ogc/gml/3.2.1/geometryPrimitives.xsd +846 -0
  95. pycsw/core/schemas/ogc/gml/3.2.1/gml.xsd +20 -0
  96. pycsw/core/schemas/ogc/gml/3.2.1/gmlBase.xsd +185 -0
  97. pycsw/core/schemas/ogc/gml/3.2.1/grids.xsd +64 -0
  98. pycsw/core/schemas/ogc/gml/3.2.1/measures.xsd +68 -0
  99. pycsw/core/schemas/ogc/gml/3.2.1/observation.xsd +95 -0
  100. pycsw/core/schemas/ogc/gml/3.2.1/referenceSystems.xsd +70 -0
  101. pycsw/core/schemas/ogc/gml/3.2.1/temporal.xsd +269 -0
  102. pycsw/core/schemas/ogc/gml/3.2.1/temporalReferenceSystems.xsd +189 -0
  103. pycsw/core/schemas/ogc/gml/3.2.1/temporalTopology.xsd +119 -0
  104. pycsw/core/schemas/ogc/gml/3.2.1/topology.xsd +386 -0
  105. pycsw/core/schemas/ogc/gml/3.2.1/units.xsd +162 -0
  106. pycsw/core/schemas/ogc/gml/3.2.1/valueObjects.xsd +205 -0
  107. pycsw/core/schemas/ogc/ogcapi/records/part1/1.0/ogcapi-records-1.yaml +932 -0
  108. pycsw/core/schemas/ogc/ows/1.0.0/ows19115subset.xsd +222 -0
  109. pycsw/core/schemas/ogc/ows/1.0.0/owsAll.xsd +20 -0
  110. pycsw/core/schemas/ogc/ows/1.0.0/owsCommon.xsd +155 -0
  111. pycsw/core/schemas/ogc/ows/1.0.0/owsDataIdentification.xsd +112 -0
  112. pycsw/core/schemas/ogc/ows/1.0.0/owsExceptionReport.xsd +67 -0
  113. pycsw/core/schemas/ogc/ows/1.0.0/owsGetCapabilities.xsd +108 -0
  114. pycsw/core/schemas/ogc/ows/1.0.0/owsOperationsMetadata.xsd +161 -0
  115. pycsw/core/schemas/ogc/ows/1.0.0/owsServiceIdentification.xsd +55 -0
  116. pycsw/core/schemas/ogc/ows/1.0.0/owsServiceProvider.xsd +46 -0
  117. pycsw/core/schemas/ogc/ows/1.1.0/ows19115subset.xsd +236 -0
  118. pycsw/core/schemas/ogc/ows/1.1.0/owsAll.xsd +23 -0
  119. pycsw/core/schemas/ogc/ows/1.1.0/owsCommon.xsd +158 -0
  120. pycsw/core/schemas/ogc/ows/1.1.0/owsContents.xsd +87 -0
  121. pycsw/core/schemas/ogc/ows/1.1.0/owsDataIdentification.xsd +128 -0
  122. pycsw/core/schemas/ogc/ows/1.1.0/owsDomainType.xsd +280 -0
  123. pycsw/core/schemas/ogc/ows/1.1.0/owsExceptionReport.xsd +77 -0
  124. pycsw/core/schemas/ogc/ows/1.1.0/owsGetCapabilities.xsd +113 -0
  125. pycsw/core/schemas/ogc/ows/1.1.0/owsGetResourceByID.xsd +52 -0
  126. pycsw/core/schemas/ogc/ows/1.1.0/owsInputOutputData.xsd +60 -0
  127. pycsw/core/schemas/ogc/ows/1.1.0/owsManifest.xsd +125 -0
  128. pycsw/core/schemas/ogc/ows/1.1.0/owsOperationsMetadata.xsd +141 -0
  129. pycsw/core/schemas/ogc/ows/1.1.0/owsServiceIdentification.xsd +61 -0
  130. pycsw/core/schemas/ogc/ows/1.1.0/owsServiceProvider.xsd +48 -0
  131. pycsw/core/schemas/ogc/ows/2.0/ows19115subset.xsd +364 -0
  132. pycsw/core/schemas/ogc/ows/2.0/owsAdditionalParameters.xsd +114 -0
  133. pycsw/core/schemas/ogc/ows/2.0/owsAll.xsd +29 -0
  134. pycsw/core/schemas/ogc/ows/2.0/owsCommon.xsd +275 -0
  135. pycsw/core/schemas/ogc/ows/2.0/owsContents.xsd +163 -0
  136. pycsw/core/schemas/ogc/ows/2.0/owsDataIdentification.xsd +202 -0
  137. pycsw/core/schemas/ogc/ows/2.0/owsDomainType.xsd +388 -0
  138. pycsw/core/schemas/ogc/ows/2.0/owsExceptionReport.xsd +126 -0
  139. pycsw/core/schemas/ogc/ows/2.0/owsGetCapabilities.xsd +220 -0
  140. pycsw/core/schemas/ogc/ows/2.0/owsGetResourceByID.xsd +83 -0
  141. pycsw/core/schemas/ogc/ows/2.0/owsInputOutputData.xsd +98 -0
  142. pycsw/core/schemas/ogc/ows/2.0/owsManifest.xsd +181 -0
  143. pycsw/core/schemas/ogc/ows/2.0/owsOperationsMetadata.xsd +234 -0
  144. pycsw/core/schemas/ogc/ows/2.0/owsServiceIdentification.xsd +98 -0
  145. pycsw/core/schemas/ogc/ows/2.0/owsServiceProvider.xsd +64 -0
  146. pycsw/core/schemas/w3c/1999/xlink.xsd +271 -0
  147. pycsw/core/schemas/w3c/2001/xml.xsd +287 -0
  148. pycsw/core/util.py +552 -0
  149. pycsw/oaipmh.py +311 -0
  150. pycsw/ogc/__init__.py +29 -0
  151. pycsw/ogc/api/__init__.py +28 -0
  152. pycsw/ogc/api/oapi.py +558 -0
  153. pycsw/ogc/api/records.py +1414 -0
  154. pycsw/ogc/api/templates/_base.html +76 -0
  155. pycsw/ogc/api/templates/collection.html +44 -0
  156. pycsw/ogc/api/templates/collections.html +45 -0
  157. pycsw/ogc/api/templates/conformance.html +21 -0
  158. pycsw/ogc/api/templates/exception.html +8 -0
  159. pycsw/ogc/api/templates/item.html +228 -0
  160. pycsw/ogc/api/templates/items.html +337 -0
  161. pycsw/ogc/api/templates/landing_page.html +27 -0
  162. pycsw/ogc/api/templates/openapi.html +58 -0
  163. pycsw/ogc/api/templates/queryables.html +50 -0
  164. pycsw/ogc/api/templates/stac_items.html +173 -0
  165. pycsw/ogc/api/templates/static/favicon.ico +0 -0
  166. pycsw/ogc/api/templates/static/logo-horizontal.png +0 -0
  167. pycsw/ogc/api/templates/static/logo-vertical-darkbg.png +0 -0
  168. pycsw/ogc/api/util.py +252 -0
  169. pycsw/ogc/csw/__init__.py +29 -0
  170. pycsw/ogc/csw/cql.py +133 -0
  171. pycsw/ogc/csw/csw2.py +2042 -0
  172. pycsw/ogc/csw/csw3.py +2193 -0
  173. pycsw/ogc/fes/__init__.py +29 -0
  174. pycsw/ogc/fes/fes1.py +433 -0
  175. pycsw/ogc/fes/fes2.py +451 -0
  176. pycsw/ogc/gml/__init__.py +29 -0
  177. pycsw/ogc/gml/gml3.py +240 -0
  178. pycsw/ogc/gml/gml32.py +243 -0
  179. pycsw/opensearch.py +857 -0
  180. pycsw/plugins/__init__.py +29 -0
  181. pycsw/plugins/outputschemas/__init__.py +31 -0
  182. pycsw/plugins/outputschemas/atom.py +143 -0
  183. pycsw/plugins/outputschemas/datacite.py +375 -0
  184. pycsw/plugins/outputschemas/dif.py +213 -0
  185. pycsw/plugins/outputschemas/fgdc.py +180 -0
  186. pycsw/plugins/outputschemas/gm03.py +240 -0
  187. pycsw/plugins/profiles/__init__.py +29 -0
  188. pycsw/plugins/profiles/apiso/__init__.py +29 -0
  189. pycsw/plugins/profiles/apiso/apiso.py +757 -0
  190. pycsw/plugins/profiles/apiso/schemas/ogc/csw/2.0.2/profiles/apiso/1.0.0/apiso.xsd +13 -0
  191. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gco/basicTypes.xsd +429 -0
  192. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gco/gco.xsd +12 -0
  193. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gco/gcoBase.xsd +61 -0
  194. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/applicationSchema.xsd +42 -0
  195. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/citation.xsd +275 -0
  196. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/constraints.xsd +106 -0
  197. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/content.xsd +188 -0
  198. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/dataQuality.xsd +554 -0
  199. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/distribution.xsd +202 -0
  200. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/extent.xsd +205 -0
  201. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/freeText.xsd +122 -0
  202. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/gmd.xsd +12 -0
  203. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/identification.xsd +348 -0
  204. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/maintenance.xsd +86 -0
  205. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/metadataApplication.xsd +175 -0
  206. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/metadataEntity.xsd +70 -0
  207. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/metadataExtension.xsd +99 -0
  208. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/portrayalCatalogue.xsd +36 -0
  209. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/referenceSystem.xsd +100 -0
  210. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmd/spatialRepresentation.xsd +237 -0
  211. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/basicTypes.xsd +267 -0
  212. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/coordinateOperations.xsd +639 -0
  213. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/coordinateReferenceSystems.xsd +526 -0
  214. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/coordinateSystems.xsd +401 -0
  215. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/coverage.xsd +462 -0
  216. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/datums.xsd +342 -0
  217. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/dictionary.xsd +129 -0
  218. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/direction.xsd +80 -0
  219. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/dynamicFeature.xsd +142 -0
  220. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/feature.xsd +215 -0
  221. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryAggregates.xsd +216 -0
  222. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryBasic0d1d.xsd +304 -0
  223. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryBasic2d.xsd +123 -0
  224. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryComplexes.xsd +89 -0
  225. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/geometryPrimitives.xsd +892 -0
  226. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/gml.xsd +14 -0
  227. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/gmlBase.xsd +305 -0
  228. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/grids.xsd +58 -0
  229. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/measures.xsd +167 -0
  230. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/observation.xsd +90 -0
  231. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/referenceSystems.xsd +69 -0
  232. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/temporal.xsd +263 -0
  233. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/temporalReferenceSystems.xsd +183 -0
  234. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/temporalTopology.xsd +124 -0
  235. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/topology.xsd +372 -0
  236. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/units.xsd +156 -0
  237. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gml/valueObjects.xsd +212 -0
  238. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/catalogues.xsd +112 -0
  239. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/codelistItem.xsd +168 -0
  240. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/crsItem.xsd +1030 -0
  241. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/extendedTypes.xsd +75 -0
  242. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/gmx.xsd +2 -0
  243. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/gmxUsage.xsd +127 -0
  244. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gmx/uomItem.xsd +162 -0
  245. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gsr/gsr.xsd +12 -0
  246. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gsr/spatialReferencing.xsd +24 -0
  247. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gss/geometry.xsd +35 -0
  248. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gss/gss.xsd +12 -0
  249. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gts/gts.xsd +12 -0
  250. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/gts/temporalObjects.xsd +34 -0
  251. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/srv/serviceMetadata.xsd +197 -0
  252. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/srv/serviceModel.xsd +220 -0
  253. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20060504/srv/srv.xsd +13 -0
  254. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gco/basicTypes.xsd +431 -0
  255. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gco/gco.xsd +12 -0
  256. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gco/gcoBase.xsd +63 -0
  257. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/applicationSchema.xsd +43 -0
  258. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/citation.xsd +276 -0
  259. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/constraints.xsd +107 -0
  260. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/content.xsd +190 -0
  261. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/dataQuality.xsd +556 -0
  262. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/distribution.xsd +203 -0
  263. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/extent.xsd +206 -0
  264. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/freeText.xsd +123 -0
  265. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/gmd.xsd +12 -0
  266. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/identification.xsd +349 -0
  267. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/maintenance.xsd +87 -0
  268. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/metadataApplication.xsd +176 -0
  269. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/metadataEntity.xsd +71 -0
  270. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/metadataExtension.xsd +100 -0
  271. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/portrayalCatalogue.xsd +37 -0
  272. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/referenceSystem.xsd +101 -0
  273. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmd/spatialRepresentation.xsd +238 -0
  274. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/catalogues.xsd +113 -0
  275. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/codelistItem.xsd +169 -0
  276. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/crsItem.xsd +1031 -0
  277. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/extendedTypes.xsd +76 -0
  278. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/gmx.xsd +12 -0
  279. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/gmxUsage.xsd +128 -0
  280. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gmx/uomItem.xsd +163 -0
  281. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gsr/gsr.xsd +12 -0
  282. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gsr/spatialReferencing.xsd +25 -0
  283. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gss/geometry.xsd +36 -0
  284. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gss/gss.xsd +12 -0
  285. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gts/gts.xsd +12 -0
  286. pycsw/plugins/profiles/apiso/schemas/ogc/iso/19139/20070417/gts/temporalObjects.xsd +35 -0
  287. pycsw/plugins/profiles/ebrim/__init__.py +29 -0
  288. pycsw/plugins/profiles/ebrim/ebrim.py +174 -0
  289. pycsw/plugins/profiles/ebrim/schemas/ogc/csw/2.0.2/profiles/ebrim/1.0/csw-ebrim-iri.xsd +146 -0
  290. pycsw/plugins/profiles/ebrim/schemas/ogc/csw/2.0.2/profiles/ebrim/1.0/csw-ebrim.xsd +104 -0
  291. pycsw/plugins/profiles/iso19115p3/__init__.py +29 -0
  292. pycsw/plugins/profiles/iso19115p3/iso19115p3.py +854 -0
  293. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/cat.xsd +13 -0
  294. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/catalogues.xsd +53 -0
  295. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/codelistItem.xsd +54 -0
  296. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/crsItem.xsd +181 -0
  297. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cat/1.0/uomItem.xsd +38 -0
  298. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cit/1.0/cit.xsd +7 -0
  299. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cit/1.0/citation.xsd +514 -0
  300. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cit/2.0/cit.xsd +10 -0
  301. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/cit/2.0/citation.xsd +523 -0
  302. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gco/1.0/baseTypes2014.xsd +530 -0
  303. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gco/1.0/gco.xsd +16 -0
  304. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gcx/1.0/extendedTypes.xsd +92 -0
  305. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gcx/1.0/extendedTypes_autoFromShapeChange.xsd +60 -0
  306. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gcx/1.0/gcx.xsd +8 -0
  307. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gex/1.0/extent.xsd +241 -0
  308. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gex/1.0/gex.xsd +9 -0
  309. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gmw/1.0/gmlWrapperTypes2014.xsd +159 -0
  310. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/gmw/1.0/gmw.xsd +14 -0
  311. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/lan/1.0/lan.xsd +8 -0
  312. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/lan/1.0/language.xsd +140 -0
  313. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/1.0/acquisitionInformationImagery.xsd +622 -0
  314. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/1.0/mac.xsd +11 -0
  315. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/2.0/acquisitionInformationImagery.xsd +590 -0
  316. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/2.0/event.xsd +108 -0
  317. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mac/2.0/mac.xsd +10 -0
  318. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mas/1.0/applicationSchema.xsd +61 -0
  319. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mas/1.0/mas.xsd +9 -0
  320. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mcc/1.0/AbstractCommonClasses.xsd +358 -0
  321. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mcc/1.0/commonClasses.xsd +220 -0
  322. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mcc/1.0/mcc.xsd +8 -0
  323. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mco/1.0/constraints.xsd +188 -0
  324. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mco/1.0/mco.xsd +8 -0
  325. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/md1/1.0/md1.xsd +9 -0
  326. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/md1/1.0/metadataWExtendedType.xsd +4 -0
  327. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/md2/1.0/md2.xsd +15 -0
  328. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/md2/1.0/metadataWithExtensions.xsd +4 -0
  329. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mda/1.0/mda.xsd +8 -0
  330. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mda/1.0/metadataApplication.xsd +200 -0
  331. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdb/1.0/mdb.xsd +14 -0
  332. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdb/1.0/metadataBase.xsd +98 -0
  333. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdb/2.0/mdb.xsd +20 -0
  334. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdb/2.0/metadataBase.xsd +102 -0
  335. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mds/1.0/mds.xsd +22 -0
  336. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mds/1.0/metadataDataServices.xsd +4 -0
  337. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdt/1.0/mdt.xsd +13 -0
  338. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mdt/1.0/metadataTransfer.xsd +111 -0
  339. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mex/1.0/metadataExtension.xsd +156 -0
  340. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mex/1.0/mex.xsd +8 -0
  341. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mmi/1.0/maintenance.xsd +76 -0
  342. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mmi/1.0/mmi.xsd +8 -0
  343. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mpc/1.0/mpc.xsd +8 -0
  344. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mpc/1.0/portrayalCatalogue.xsd +31 -0
  345. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/1.0/content.xsd +416 -0
  346. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/1.0/contentInformationImagery.xsd +185 -0
  347. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/1.0/mrc.xsd +11 -0
  348. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/2.0/content.xsd +419 -0
  349. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/2.0/contentInformationImagery.xsd +171 -0
  350. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrc/2.0/mrc.xsd +11 -0
  351. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrd/1.0/distribution.xsd +267 -0
  352. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrd/1.0/mrd.xsd +8 -0
  353. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mri/1.0/identification.xsd +517 -0
  354. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mri/1.0/mri.xsd +9 -0
  355. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/1.0/lineage.xsd +147 -0
  356. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/1.0/lineageImagery.xsd +236 -0
  357. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/1.0/mrl.xsd +9 -0
  358. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/2.0/lineage.xsd +147 -0
  359. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/2.0/lineageImagery.xsd +312 -0
  360. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrl/2.0/mrl.xsd +11 -0
  361. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrs/1.0/mrs.xsd +8 -0
  362. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/mrs/1.0/referenceSystem.xsd +47 -0
  363. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/1.0/msr.xsd +10 -0
  364. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/1.0/spatialRepresentation.xsd +375 -0
  365. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/1.0/spatialRepresentationImagery.xsd +119 -0
  366. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/2.0/msr.xsd +15 -0
  367. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/2.0/spatialRepresentation.xsd +381 -0
  368. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/msr/2.0/spatialRepresentationImagery.xsd +120 -0
  369. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/srv/2.0/serviceInformation.xsd +272 -0
  370. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/srv/2.0/srv.xsd +6 -0
  371. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/srv/2.1/serviceInformation.xsd +278 -0
  372. pycsw/plugins/profiles/iso19115p3/schemas/ogc/iso/iso19115-3/srv/2.1/srv.xsd +6 -0
  373. pycsw/plugins/profiles/profile.py +141 -0
  374. pycsw/plugins/repository/__init__.py +29 -0
  375. pycsw/plugins/repository/odc/__init__.py +29 -0
  376. pycsw/plugins/repository/odc/odc.py +153 -0
  377. pycsw/server.py +938 -0
  378. pycsw/sru.py +217 -0
  379. pycsw/stac/__init__.py +29 -0
  380. pycsw/stac/api.py +571 -0
  381. pycsw/wsgi.py +233 -0
  382. pycsw/wsgi_flask.py +345 -0
@@ -0,0 +1,854 @@
1
+ # -*- coding: utf-8 -*-
2
+ # =================================================================
3
+ #
4
+ # Author: Vincent Fazio <vincent.fazio@csiro.au>
5
+ #
6
+ # Copyright (c) 2023 CSIRO Australia
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person
9
+ # obtaining a copy of this software and associated documentation
10
+ # files (the "Software"), to deal in the Software without
11
+ # restriction, including without limitation the rights to use,
12
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ # copies of the Software, and to permit persons to whom the
14
+ # Software is furnished to do so, subject to the following
15
+ # conditions:
16
+ #
17
+ # The above copyright notice and this permission notice shall be
18
+ # included in all copies or substantial portions of the Software.
19
+ #
20
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27
+ # OTHER DEALINGS IN THE SOFTWARE.
28
+ #
29
+ # =================================================================
30
+
31
+ import os
32
+ import json
33
+ from pycsw.core import config, util
34
+ from pycsw.core.etree import etree
35
+ from pycsw.plugins.profiles import profile
36
+
37
+ CODELIST = 'http://standards.iso.org/iso/19115/resources/Codelist/cat/codelists.xml'
38
+
39
+
40
+ class ISO19115p3(profile.Profile):
41
+ """ ISO19115p3 class represents the profile for input and output of ISO 19115 Part 3 XML
42
+ """
43
+ def __init__(self, model, namespaces, context):
44
+ """
45
+ :param model: model
46
+ :param namespaces: namespaces
47
+ :param context: context
48
+ """
49
+ self.context = context
50
+
51
+ self.namespaces = {
52
+ "mdb":"http://standards.iso.org/iso/19115/-3/mdb/2.0",
53
+ "cat":"http://standards.iso.org/iso/19115/-3/cat/1.0",
54
+ "gfc":"http://standards.iso.org/iso/19110/gfc/1.1",
55
+ "cit":"http://standards.iso.org/iso/19115/-3/cit/2.0",
56
+ "gcx":"http://standards.iso.org/iso/19115/-3/gcx/1.0",
57
+ "gex":"http://standards.iso.org/iso/19115/-3/gex/1.0",
58
+ "lan":"http://standards.iso.org/iso/19115/-3/lan/1.0",
59
+ "srv":"http://standards.iso.org/iso/19115/-3/srv/2.1",
60
+ "mas":"http://standards.iso.org/iso/19115/-3/mas/1.0",
61
+ "mcc":"http://standards.iso.org/iso/19115/-3/mcc/1.0",
62
+ "mco":"http://standards.iso.org/iso/19115/-3/mco/1.0",
63
+ "mda":"http://standards.iso.org/iso/19115/-3/mda/1.0",
64
+ "mds":"http://standards.iso.org/iso/19115/-3/mds/2.0",
65
+ "mdt":"http://standards.iso.org/iso/19115/-3/mdt/2.0",
66
+ "mex":"http://standards.iso.org/iso/19115/-3/mex/1.0",
67
+ "mmi":"http://standards.iso.org/iso/19115/-3/mmi/1.0",
68
+ "mpc":"http://standards.iso.org/iso/19115/-3/mpc/1.0",
69
+ "mrc":"http://standards.iso.org/iso/19115/-3/mrc/2.0",
70
+ "mrd":"http://standards.iso.org/iso/19115/-3/mrd/1.0",
71
+ "mri":"http://standards.iso.org/iso/19115/-3/mri/1.0",
72
+ "mrl":"http://standards.iso.org/iso/19115/-3/mrl/2.0",
73
+ "mrs":"http://standards.iso.org/iso/19115/-3/mrs/1.0",
74
+ "msr":"http://standards.iso.org/iso/19115/-3/msr/2.0",
75
+ "mdq":"http://standards.iso.org/iso/19157/-2/mdq/1.0",
76
+ "mac":"http://standards.iso.org/iso/19115/-3/mac/2.0",
77
+ "gco":"http://standards.iso.org/iso/19115/-3/gco/1.0",
78
+ "gml":"http://www.opengis.net/gml",
79
+ "xlink":"http://www.w3.org/1999/xlink",
80
+ "xsi":"http://www.w3.org/2001/XMLSchema-instance"
81
+ }
82
+
83
+ self.inspire_namespaces = {
84
+ }
85
+
86
+ self.repository = {
87
+ 'mdb:MD_Metadata': {
88
+ 'outputschema': 'http://standards.iso.org/iso/19115/-3/mdb/2.0',
89
+ 'queryables': {
90
+ 'SupportedISO19115p3Queryables': {
91
+ 'mdb:Subject': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:topicCategory/mri:MD_TopicCategoryCode',
92
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Keywords']},
93
+ 'mdb:Title': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:citation/cit:CI_Citation/cit:title/gco:CharacterString',
94
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Title']},
95
+ 'mdb:Abstract': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:abstract/gco:CharacterString',
96
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Abstract']},
97
+ 'mdb:Edition': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:citation/cit:CI_Citation/cit:edition/gco:CharacterString',
98
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Edition']},
99
+ 'mdb:Format': {'xpath': 'mdb:distributionInfo/mrd:MD_Distribution/mrd:distributionFormat/mrd:MD_Format/mrd:formatSpecificationCitation/cit:CI_Citation/cit:title/gcx:Anchor',
100
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Format']},
101
+ 'mdb:Identifier': {'xpath': 'mdb:metadataIdentifier/mcc:MD_Identifier/mcc:code/gco:CharacterString',
102
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Identifier']},
103
+ 'mdb:Modified': {'xpath': 'mdb:MD_Metadata/mdb:dateInfo/cit:CI_Date[cit:dateType/cit:CI_DateTypeCode="lastUpdate"]/cit:date/gco:DateTime',
104
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Modified']},
105
+ 'mdb:Type': {'xpath': 'mdb:metadataScope/mdb:MD_MetadataScope/mdb:resourceScope/mcc:MD_ScopeCode/@codeListValue',
106
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Type']},
107
+ # NB: Placeholder only
108
+ 'mdb:BoundingBox': {'xpath': 'mdb:BoundingBox', 'dbcol': self.context.md_core_model['mappings']['pycsw:BoundingBox']},
109
+ 'mdb:VertExtentMin': {'xpath': 'gex:EX_VerticalExtent/gex:minimumValue/gco:Real', 'dbcol': self.context.md_core_model['mappings']['pycsw:VertExtentMin']},
110
+ 'mdb:VertExtentMax': {'xpath': 'gex:EX_VerticalExtent/gex:maximumValue/gco:Real', 'dbcol': self.context.md_core_model['mappings']['pycsw:VertExtentMax']},
111
+ 'mdb:CRS': {'xpath': '''concat("urn:ogc:def:crs:",
112
+ "mdb:referenceSystemInfo/mrs:MD_ReferenceSystem/mrs:referenceSystemIdentifier/mcc:MD_Identifier/mcc:codeSpace/gco:CharacterString",
113
+ ":",
114
+ "mdb:referenceSystemInfo/mrs:MD_ReferenceSystem/mrs:referenceSystemIdentifier/mcc:MD_Identifier/mcc:version/gco:CharacterString",
115
+ ":",
116
+ "mdb:referenceSystemInfo/mrs:MD_ReferenceSystem/mrs:referenceSystemIdentifier/mcc:MD_Identifier/mcc:code/gco:CharacterString")''',
117
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:CRS']},
118
+ 'mdb:AlternateTitle': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:citation/cit:CI_Citation/cit:title/gco:CharacterString',
119
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:AlternateTitle']},
120
+ 'mdb:RevisionDate': {'xpath': 'mdb:dateInfo/cit:CI_Date[cit:dateType/cit:CI_DateTypeCode/@codeListValue="revision"]/cit:date/gco:DateTime',
121
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:RevisionDate']},
122
+ 'mdb:CreationDate': {'xpath': 'mdb:dateInfo/cit:CI_Date[cit:dateType/cit:CI_DateTypeCode/@codeListValue="creation"]/cit:date/gco:DateTime',
123
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:CreationDate']},
124
+ 'mdb:PublicationDate': {'xpath': 'mdb:dateInfo/cit:CI_Date[cit:dateType/cit:CI_DateTypeCode/@codeListValue="publication"]/cit:date/gco:DateTime',
125
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:PublicationDate']},
126
+ 'mdb:OrganisationName': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:pointOfContact/cit:CI_Responsibility/cit:party/cit:CI_Organisation/cit:name/gco:CharacterString',
127
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:OrganizationName']},
128
+ 'mdb:HasSecurityConstraints': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:resourceConstraints/mco:MD_SecurityConstraints',
129
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:SecurityConstraints']},
130
+ 'mdb:Language': {'xpath': 'mdb:defaultLocale/lan:PT_Locale/lan:language/lan:LanguageCode|mdb:defaultLocale/lan:PT_Locale/lan:language/gco:CharacterString',
131
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Language']},
132
+ 'mdb:ParentIdentifier': {'xpath': 'mdb:parentMetadata/cit:CI_Citation/cit:identifier/mcc:MD_Identifier/mcc:code/gco:CharacterString',
133
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:ParentIdentifier']},
134
+ 'mdb:KeywordType': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:descriptiveKeywords/mri:MD_Keywords/mri:type/mri:MD_KeywordTypeCode',
135
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:KeywordType']},
136
+ 'mdb:TopicCategory': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:topicCategory/mri:MD_TopicCategoryCode',
137
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:TopicCategory']},
138
+ 'mdb:ResourceLanguage': {'xpath': 'mdb:defaultLocale/lan:PT_Locale/lan:language/lan:LanguageCode/@codeListValue',
139
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:ResourceLanguage']},
140
+ 'mdb:GeographicDescriptionCode': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:extent/gex:EX_Extent/gex:geographicElement/gex:EX_GeographicDescription/gex:geographicIdentifier/mcc:MD_Identifier/mcc:code/gco:CharacterString',
141
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:GeographicDescriptionCode']},
142
+ 'mdb:Denominator': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:spatialResolution/mri:MD_Resolution/mri:equivalentScale/mri:MD_RepresentativeFraction/mri:denominator/gco:Integer',
143
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Denominator']},
144
+ 'mdb:DistanceValue': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:spatialResolution/mri:MD_Resolution/mri:distance/gco:Distance',
145
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:DistanceValue']},
146
+ 'mdb:DistanceUOM': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:spatialResolution/mri:MD_Resolution/mri:distance/gco:Distance/@uom',
147
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:DistanceUOM']},
148
+ 'mdb:TempExtent_begin': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:extent/gex:EX_Extent/gex:temporalElement/gex:EX_TemporalExtent/mri:extent/gml:TimePeriod/gml:beginPosition',
149
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:TempExtent_begin']},
150
+ 'mdb:TempExtent_end': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:extent/gex:EX_Extent/gex:temporalElement/gex:EX_TemporalExtent/mri:extent/gml:TimePeriod/gml:endPosition',
151
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:TempExtent_end']},
152
+ 'mdb:AnyText': {'xpath': '//',
153
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:AnyText']},
154
+ 'mdb:ServiceType': {'xpath': 'mdb:identificationInfo/srv:SV_ServiceIdentification/srv:serviceType/gco:LocalName',
155
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:ServiceType']},
156
+ 'mdb:ServiceTypeVersion': {'xpath': 'mdb:identificationInfo/srv:SV_ServiceIdentification/srv:serviceTypeVersion/gco:CharacterString',
157
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:ServiceTypeVersion']},
158
+ 'mdb:Operation': {'xpath': 'mdb:identificationInfo/srv:SV_ServiceIdentification/srv:containsOperations/srv:SV_OperationMetadata/srv:operationName/gco:CharacterString',
159
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Operation']},
160
+ 'mdb:CouplingType': {'xpath': 'mdb:identificationInfo/srv:SV_ServiceIdentification/srv:couplingType/srv:SV_CouplingType',
161
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:CouplingType']},
162
+ 'mdb:OperatesOn': {'xpath': 'mdb:identificationInfo/srv:SV_ServiceIdentification/srv:operatesOn/mri:MD_DataIdentification/mri:citation/cit:CI_Citation/cit:identifier/mcc:MD_Identifier/mcc:code/gco:CharacterString',
163
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:OperatesOn']},
164
+ 'mdb:OperatesOnIdentifier': {'xpath': 'mdb:identificationInfo/srv:SV_ServiceIdentification/srv:coupledResource/srv:SV_CoupledResource/srv:identifier/gco:CharacterString',
165
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:OperatesOnIdentifier']},
166
+ 'mdb:OperatesOnName': {'xpath': 'mdb:identificationInfo/srv:SV_ServiceIdentification/srv:coupledResource/srv:SV_CoupledResource/srv:operationName/gco:CharacterString',
167
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:OperatesOnName']},
168
+ },
169
+ 'AdditionalISO19115p3Queryables': {
170
+ 'mdb:Degree': {'xpath': 'mdb:dataQualityInfo/mdq:DQ_DataQuality/mdq:report/mdq:DQ_DomainConsistency/mdq:result/mdq:DQ_ConformanceResult/mdq:pass/gco:Boolean',
171
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Degree']},
172
+ 'mdb:AccessConstraints': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:resourceConstraints/mco:MD_LegalConstraints/mco:accessConstraints/mco:MD_RestrictionCode',
173
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:AccessConstraints']},
174
+ 'mdb:OtherConstraints': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:resourceConstraints/mco:MD_LegalConstraints/mco:otherConstraints/gco:CharacterString',
175
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:OtherConstraints']},
176
+ 'mdb:Classification': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:resourceConstraints/mco:MD_LegalConstraints/mco:accessConstraints/mco:MD_ClassificationCode/@codeListValue',
177
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Classification']},
178
+ 'mdb:ConditionApplyingToAccessAndUse': {'xpath': 'mdb:metadataConstraints/mco:MD_LegalConstraints/mco:useLimitation/gco:CharacterString|mdb:identificationInfo/mri:MD_DataIdentification/mri:resourceConstraints/mco:MD_LegalConstraints/mco:useLimitation/gco:CharacterString',
179
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:ConditionApplyingToAccessAndUse']},
180
+ 'mdb:Lineage': {'xpath': 'mdb:dataQualityInfo/mdq:DQ_DataQuality/mrl:lineage/mrl:LI_Lineage/mrl:statement/gco:CharacterString',
181
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Lineage']},
182
+ 'mdb:ResponsiblePartyRole': {'xpath': 'mdb:contact/cit:CI_Responsiblility/cit:role/cit:CI_RoleCode',
183
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:ResponsiblePartyRole']},
184
+ 'mdb:SpecificationTitle': {'xpath': 'mdb:dataQualityInfo/mdq:DQ_DataQuality/mdq:report/mdq:DQ_DomainConsistency/mdq:result/mdq:DQ_ConformanceResult/mdq:specification/cit:CI_Citation/cit:title/gco:CharacterString',
185
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:SpecificationTitle']},
186
+ 'mdb:SpecificationDate': {'xpath': 'mdb:dataQualityInfo/mdq:DQ_DataQuality/mdq:report/mdq:DQ_DomainConsistency/mdq:result/mdq:DQ_ConformanceResult/mdq:secification/cit:CI_Citation/cit:date/cit:CI_Date/cit:date/gco:Date',
187
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:SpecificationDate']},
188
+ 'mdb:SpecificationDateType': {'xpath': 'mdb:dataQualityInfo/mdq:DQ_DataQuality/mdq:report/mdq:DQ_DomainConsistency/mdq:result/mdq:DQ_ConformanceResult/mdq:specification/cit:CI_Citation/cit:date/cit:CI_Date/cit:dateType/cit:CI_DateTypeCode/@codeListValue',
189
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:SpecificationDateType']},
190
+
191
+ 'mdb:Creator': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:citation/cit:CI_Citation/cit:citedResponsibleParty/cit:CI_Responsibility/cit:role/cit:CI_RoleCode[text()="creator"]',
192
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Creator']},
193
+ 'mdb:Publisher': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:citation/cit:CI_Citation/cit:citedResponsibleParty/cit:CI_Responsibility/cit:role/cit:CI_RoleCode[text()="publisher"]',
194
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Publisher']},
195
+ 'mdb:Contributor': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:citation/cit:CI_Citation/cit:citedResponsibleParty/cit:CI_Responsibility/cit:role/cit:CI_RoleCode[text()="contributor"]',
196
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Contributor']},
197
+ 'mdb:Relation': {'xpath': 'mdb:identificationInfo/mri:MD_DataIdentification/mri:aggregationInfo',
198
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Relation']},
199
+ # 19115-2
200
+ 'mdb:Platform': {'xpath': 'mdb:acquisitionInfo/mac:MI_AcquisitionInformation/mac:platform/mac:MI_Platform/mac:identifier',
201
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Platform']},
202
+ 'mdb:Instrument': {'xpath': 'mdb:acquisitionInfo/mac:MI_AcquisitionInformation/mac:platform/mac:MI_Platform/mac:instrument/mac:MI_Instrument/mac:identifier',
203
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Instrument']},
204
+ 'mdb:SensorType': {'xpath': 'mdb:acquisitionInfo/mac:MI_AcquisitionInformation/mac:platform/mac:MI_Platform/mac:instrument/mac:MI_Instrument/mac:type',
205
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:SensorType']},
206
+ 'mdb:CloudCover': {'xpath': 'mdb:contentInfo/mrc:MD_ImageDescription/mrc:cloudCoverPercentage',
207
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:CloudCover']},
208
+ 'mdb:Bands': {'xpath': 'mdb:contentInfo/mrc:MD_ImageDescription/mrc:attributeGroup/mrc:MD_AttributeGroup/mrc:attribute/mrc:MD_Band/mrc:sequenceIdentifier/gco:MemberName/gco:aName/gco:CharacterString',
209
+ 'dbcol': self.context.md_core_model['mappings']['pycsw:Bands']},
210
+ }
211
+ },
212
+ 'mappings': {
213
+ 'csw:Record': {
214
+ # map MDB queryables to DC queryables
215
+ 'mdb:Title': 'dc:title',
216
+ 'mdb:Creator': 'dc:creator',
217
+ 'mdb:Subject': 'dc:subject',
218
+ 'mdb:Abstract': 'dct:abstract',
219
+ 'mdb:Publisher': 'dc:publisher',
220
+ 'mdb:Contributor': 'dc:contributor',
221
+ 'mdb:Modified': 'dct:modified',
222
+ 'mdb:PublicationDate': 'dc:date',
223
+ 'mdb:Type': 'dc:type',
224
+ 'mdb:Format': 'dc:format',
225
+ 'mdb:Language': 'dc:language',
226
+ 'mdb:Relation': 'dc:relation',
227
+ 'mdb:AccessConstraints': 'dc:rights',
228
+ }
229
+ }
230
+ }
231
+ }
232
+
233
+ profile.Profile.__init__(self,
234
+ name='mdb',
235
+ version='1.0.0',
236
+ title='ISO 19115-3 XML Metadata',
237
+ url='https://www.iso.org/standard/32579.html',
238
+ namespace=self.namespaces['mdb'],
239
+ typename='mdb:MD_Metadata',
240
+ outputschema=self.namespaces['mdb'],
241
+ prefixes=['mdb'],
242
+ model=model,
243
+ core_namespaces=namespaces,
244
+ added_namespaces=self.namespaces,
245
+ repository=self.repository['mdb:MD_Metadata'])
246
+
247
+ def extend_core(self, model, namespaces, config):
248
+ """ Extend core configuration
249
+
250
+ :param model:
251
+ """
252
+
253
+ # update harvest resource types with WMS, since WMS is not a typename,
254
+ if 'Harvest' in model['operations']:
255
+ model['operations']['Harvest']['parameters']['ResourceType']['values'].append('https://schemas.isotc211.org/19115/-3/mdb/2.0/')
256
+
257
+ self.inspire_config = None
258
+
259
+ server_cfg = config.get('server', {})
260
+ self.ogc_schemas_base = server_cfg.get('ogc_schemas_base', 'http://schemas.opengis.net')
261
+ self.url = server_cfg.get('url', 'http://localhost/pycsw/csw.py')
262
+
263
+ def check_parameters(self, kvp):
264
+ """ Check for Language parameter in GetCapabilities request
265
+ Kept for backwards compatibility
266
+ """
267
+ return None
268
+
269
+ def get_extendedcapabilities(self):
270
+ """ Get extended capabilities
271
+ Kept for backwards compatibility
272
+ """
273
+ return None
274
+
275
+ def get_schemacomponents(self):
276
+ """ Return schema components as lxml.etree.Element list
277
+ """
278
+
279
+ node1 = etree.Element(
280
+ util.nspath_eval('csw:SchemaComponent', self.context.namespaces),
281
+ schemaLanguage='XMLSCHEMA', targetNamespace=self.namespace,
282
+ parentSchema='mdb.xsd')
283
+
284
+ # Copied from: https://github.com/geonetwork/core-geonetwork/tree/main/schemas/iso19115-3.2018/src/main/plugin/iso19115-3.2018/schema/standards.iso.org/19115/-3/mdb/2.0
285
+ schema_file = os.path.join(self.context.pycsw_home, 'plugins',
286
+ 'profiles', 'iso19115p3', 'schemas', 'ogc',
287
+ 'iso', 'iso19115-3', 'mdb', '2.0', 'mdb.xsd')
288
+
289
+ schema = etree.parse(schema_file, self.context.parser).getroot()
290
+
291
+ node1.append(schema)
292
+
293
+ node2 = etree.Element(
294
+ util.nspath_eval('csw:SchemaComponent', self.context.namespaces),
295
+ schemaLanguage='XMLSCHEMA', targetNamespace=self.namespace,
296
+ parentSchema='mdb.xsd')
297
+
298
+ schema_file = os.path.join(self.context.pycsw_home, 'plugins',
299
+ 'profiles', 'iso19115p3', 'schemas', 'ogc',
300
+ 'iso', 'iso19115-3', 'srv', '2.1',
301
+ 'serviceInformation.xsd')
302
+
303
+ schema = etree.parse(schema_file, self.context.parser).getroot()
304
+
305
+ node2.append(schema)
306
+
307
+ return [node1, node2]
308
+
309
+ def check_getdomain(self, kvp):
310
+ """ Perform extra profile specific checks in the GetDomain request
311
+ Kept for backwards compatibility
312
+ """
313
+ return None
314
+
315
+ def write_record(self, result, esn, outputschema, queryables, caps=None):
316
+ """ Return csw:SearchResults child as etree.Element
317
+
318
+ :param result: results from repository query (to be written out)
319
+ :param esn: CSW element set name parameter
320
+ :param outputschema: CSW outputschema
321
+ :param queryables: database column mapping for our 'mdb:XXXX'
322
+ :param caps: optional information object gathered from GetCapabilities response
323
+ """
324
+ typename = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Typename'])
325
+ is_mdb_anyway = False
326
+
327
+ xml_blob = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:XML'])
328
+
329
+ #xml_blob_decoded = bytes.fromhex(xml_blob[2:]).decode('utf-8')
330
+
331
+ if isinstance(xml_blob, bytes):
332
+ iso_string = b'<mdb:MD_Metadata>'
333
+ else:
334
+ iso_string = '<mdb:MD_Metadata>'
335
+
336
+ if caps is None and xml_blob is not None and xml_blob.startswith(iso_string):
337
+ is_mdb_anyway = True
338
+
339
+ if (esn == 'full' and (typename == 'mdb:MD_Metadata' or is_mdb_anyway)):
340
+ # dump record as is and exit
341
+ return etree.fromstring(xml_blob, self.context.parser)
342
+
343
+ node = etree.Element(util.nspath_eval('mdb:MD_Metadata', self.namespaces), nsmap=self.namespaces)
344
+ node.attrib[util.nspath_eval('xsi:schemaLocation', self.context.namespaces)] = \
345
+ f"{self.namespace} {self.ogc_schemas_base}/csw/2.0.2/csw.xsd"
346
+
347
+ # identifier
348
+ idval = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Identifier'])
349
+
350
+ meta_identifier = etree.SubElement(node, util.nspath_eval('mdb:metadataIdentifier', self.namespaces))
351
+ md_identifier = etree.SubElement(meta_identifier, util.nspath_eval('mcc:MD_Identifier', self.namespaces))
352
+ code = etree.SubElement(md_identifier, util.nspath_eval('mcc:code', self.namespaces))
353
+ etree.SubElement(code, util.nspath_eval('gco:CharacterString', self.namespaces)).text = idval
354
+
355
+ if esn in ['summary', 'full']:
356
+ # Language must use a code, so preferentially prefer to use 'mdb:ResourceLanguage' which maps to 'gmd:MD_LanguageTypeCode' in older ISO XML standard
357
+ try:
358
+ val = util.getqattr(result, queryables['mdb:ResourceLanguage']['dbcol'])
359
+ except Exception as e:
360
+ print(f"{queryables=}")
361
+ print("exc=", e)
362
+ if val is None:
363
+ val = util.getqattr(result, queryables['mdb:Language']['dbcol'])
364
+ lang_code = build_path(node,['mdb:defaultLocale', 'lan:PT_Locale', 'lan:language', 'lan:LanguageCode'], self.namespaces)
365
+ lang_code.set('codeListValue', val)
366
+ lang_code.set('codeList', 'http://www.loc.gov/standards/iso639-2/')
367
+
368
+ # hierarchyLevel
369
+ mtype = util.getqattr(result, queryables['mdb:Type']['dbcol']) or None
370
+
371
+ if mtype is not None:
372
+ if mtype == 'http://purl.org/dc/dcmitype/Dataset':
373
+ mtype = 'dataset'
374
+ md_scope = etree.SubElement(node, util.nspath_eval('mdb:metadataScope', self.namespaces))
375
+ md_metascope = etree.SubElement(md_scope, util.nspath_eval('mdb:MD_MetadataScope', self.namespaces))
376
+ res_scope = etree.SubElement(md_metascope, util.nspath_eval('mdb:resourceScope', self.namespaces))
377
+ res_scope.append(write_codelist_element('mcc:MD_ScopeCode', mtype, self.namespaces))
378
+
379
+ if esn in ['summary', 'full']:
380
+ # Contact
381
+ ci_resp = build_path(node, ['mdb:contact', 'cit:CI_Responsibility'], self.namespaces)
382
+ ci_org = build_path(ci_resp, ['cit:party', 'cit:CI_Organisation'], self.namespaces)
383
+
384
+ # If 'GetCapability' information is supplied
385
+ if caps is not None:
386
+ ci_contact = build_path(ci_resp, ['cit:contactInfo', 'cit:CI_Contact'], self.namespaces)
387
+ # Name of individual within an organisation
388
+ if hasattr(caps.provider.contact, 'name'):
389
+ path = ['cit:individual', 'cit:CI_Individual', 'cit:name', 'gco:CharacterString']
390
+ ind_name = build_path(ci_org, path, self.namespaces)
391
+ ind_name.text = caps.provider.contact.name
392
+ # Name of organisation
393
+ if hasattr(caps.provider.contact, 'organization'):
394
+ if caps.provider.contact.organization is not None:
395
+ org_val = caps.provider.contact.organization
396
+ else:
397
+ org_val = caps.provider.name
398
+ path = ['cit:name', 'gco:CharacterString']
399
+ org_name = build_path(ci_org, path, self.namespaces)
400
+ org_name.text = org_val
401
+ # Position of individual within organisation
402
+ if hasattr(caps.provider.contact, 'position'):
403
+ path = ['cit:party', 'cit:CI_Organisation', 'cit:positionName', 'cit:CI_Individual', 'cit:individual', 'gco:characterString']
404
+ pos_name = build_path(ci_resp, path, self.namespaces)
405
+ pos_name.text = caps.provider.contact.position
406
+
407
+ # Phone number and fax of individual within an organisation
408
+ if hasattr(caps.provider.contact, 'phone'):
409
+ self._write_contact_phone(ci_contact, caps.provider.contact.phone)
410
+ if hasattr(caps.provider.contact, 'fax'):
411
+ self._write_contact_fax(ci_contact, caps.provider.contact.fax)
412
+
413
+ # Address of organisation
414
+ self._write_contact_address(ci_resp, ci_contact, **vars(caps.provider.contact))
415
+
416
+ # URL of organisation or individual
417
+ contact_url = None
418
+ if hasattr(caps.provider, 'url'):
419
+ contact_url = caps.provider.url
420
+ if hasattr(caps.provider.contact, 'url') and caps.provider.contact.url is not None:
421
+ contact_url = caps.provider.contact.url
422
+ if contact_url is not None:
423
+ path = ['cit:onlineResource', 'cit:CI_OnlineResource', 'cit:linkage', 'gco:characterString']
424
+ url = build_path(ci_contact, path, self.namespaces)
425
+ url.text = contact_url
426
+ # Role
427
+ if hasattr(caps.provider.contact, 'role'):
428
+ role = build_path(ci_resp, ['cit:role', 'cit:CI_RoleCode'], self.namespaces)
429
+ role_val = caps.provider.contact.role
430
+ if role_val is None:
431
+ role_val = 'pointOfContact'
432
+ role.set("codeList", f'{CODELIST}#CI_RoleCode')
433
+ role.set("codeListValue", role_val)
434
+ else:
435
+ # If 'GetCapability' information is not supplied ...
436
+
437
+ # Name of organisation
438
+ org_val = util.getqattr(result, queryables['mdb:OrganisationName']['dbcol'])
439
+ if org_val:
440
+ path = ['cit:name', 'gco:CharacterString']
441
+ org_name = build_path(ci_org, path, self.namespaces)
442
+ org_name.text = org_val
443
+
444
+ # Get address, phone etc. from contacts
445
+ cjson = util.getqattr(result,self.context.md_core_model['mappings']['pycsw:Contacts'])
446
+ if cjson not in [None, '', 'null']:
447
+ try:
448
+ for contact in json.loads(cjson):
449
+ path = ['cit:individual', 'cit:CI_Individual']
450
+ ci_individ = build_path(ci_org, path, self.namespaces)
451
+ # Name and position of individual within organisation
452
+ if contact.get('name', None) != None:
453
+ path = ['cit:name', 'gco:CharacterString']
454
+ name = build_path(ci_individ, path, self.namespaces)
455
+ name.text = contact.get('name')
456
+ if contact.get('position', None) != None:
457
+ path = ['cit:positionName', 'gco:CharacterString']
458
+ position = build_path(ci_individ, path, self.namespaces)
459
+ position.text = contact.get('position')
460
+ # Contact information
461
+ ci_contact = build_path(ci_individ, ['cit:contactInfo', 'cit:CI_Contact'], self.namespaces)
462
+ if contact.get('phone', None) != None:
463
+ self._write_contact_phone(ci_contact, contact.get('phone'))
464
+ if contact.get('fax', None) != None:
465
+ self._write_contact_fax(ci_contact, contact.get('fax'))
466
+ # Organisation address
467
+ self._write_contact_address(ci_resp, ci_contact, **contact)
468
+ except Exception as err:
469
+ print(f"failed to parse contacts json of {cjson}: {err}")
470
+
471
+ # Creation date for record
472
+ val = util.getqattr(result, queryables['mdb:Modified']['dbcol'])
473
+ date = build_path(node, ['mdb:dateInfo'], self.namespaces)
474
+ ci_date = self._write_date(val, 'creation')
475
+ date.append(ci_date)
476
+
477
+ metadatastandardname = 'ISO 19115-1:2014'
478
+ if mtype == 'service':
479
+ metadatastandardname = 'ISO19119:2016'
480
+
481
+ # Metadata standard name and version
482
+ path = ['mdb:metadataStandard', 'cit:CI_Citation', 'cit:title', 'gco:CharacterString']
483
+ standard_name = build_path(node, path, self.namespaces)
484
+ standard_name.text = metadatastandardname
485
+
486
+ # Title
487
+ title_val = util.getqattr(result, queryables['mdb:Title']['dbcol']) or ''
488
+ identification = etree.SubElement(node, util.nspath_eval('mdb:identificationInfo', self.namespaces))
489
+ if mtype == 'service':
490
+ res_tagname = 'srv:SV_ServiceIdentification'
491
+ else:
492
+ res_tagname = 'mri:MD_DataIdentification'
493
+ resident = etree.SubElement(identification, util.nspath_eval(res_tagname, self.namespaces), id=idval)
494
+ ci_citation = build_path(resident, ['mri:citation', 'cit:CI_Citation'], self.namespaces)
495
+ title = build_path(ci_citation, ['cit:title', 'gco:CharacterString'], self.namespaces)
496
+ title.text = title_val
497
+
498
+ # Edition
499
+ edition_val = util.getqattr(result, queryables['mdb:Edition']['dbcol'])
500
+ if edition_val is not None:
501
+ edition = build_path(ci_citation, ['cit:edition', 'gco:CharacterString'], self.namespaces)
502
+ edition.text = edition_val
503
+
504
+ date_info = build_path(node, ['mdb:dateInfo'], self.namespaces)
505
+ # Creation date
506
+ val = util.getqattr(result, queryables['mdb:CreationDate']['dbcol'])
507
+ if val is not None:
508
+ date_info.append(self._write_date(val, 'creation'))
509
+ # Publication date
510
+ val = util.getqattr(result, queryables['mdb:PublicationDate']['dbcol'])
511
+ if val is not None:
512
+ date_info.append(self._write_date(val, 'publication'))
513
+ # Revision date
514
+ val = util.getqattr(result, queryables['mdb:RevisionDate']['dbcol'])
515
+ if val is not None:
516
+ date_info.append(self._write_date(val, 'revision'))
517
+
518
+ if esn in ['summary', 'full']:
519
+ # Abstract
520
+ val = util.getqattr(result, queryables['mdb:Abstract']['dbcol']) or ''
521
+ abstract = build_path(resident, ['mri:abstract', 'gco:characterString'], self.namespaces)
522
+ abstract.text = val
523
+
524
+ # Keywords
525
+ kw = util.getqattr(result, queryables['mdb:Subject']['dbcol'])
526
+ if kw is not None:
527
+ md_keywords = build_path(resident, ['mri:descriptiveKeywords'], self.namespaces)
528
+ md_keywords.append(self._write_keywords(kw))
529
+
530
+ # Spatial resolution
531
+ val = util.getqattr(result, queryables['mdb:Denominator']['dbcol'])
532
+ if val:
533
+ path = ['mri:spatialResolution', 'mri:MD_Resolution', 'mri:equivalentScale',
534
+ 'mri:MD_RepresentativeFraction', 'mri:denominator', 'gco:Integer']
535
+ int_elem = build_path(resident, path, self.namespaces)
536
+ int_elem.text = str(val)
537
+
538
+ # Topic category
539
+ val = util.getqattr(result, queryables['mdb:TopicCategory']['dbcol'])
540
+ topic_cat = build_path(resident, ['mri:topicCategory'], self.namespaces)
541
+ if val:
542
+ for v in val.split(','):
543
+ etree.SubElement(topic_cat, util.nspath_eval('mri:MD_TopicCategoryCode', self.namespaces)).text = val
544
+
545
+ # Bbox and vertical extent
546
+ bbox = util.getqattr(result, queryables['mdb:BoundingBox']['dbcol'])
547
+ vert_ext_min = util.getqattr(result, queryables['mdb:VertExtentMin']['dbcol'])
548
+ vert_ext_max = util.getqattr(result, queryables['mdb:VertExtentMax']['dbcol'])
549
+ # Convert float to string
550
+ if vert_ext_min is not None:
551
+ vert_ext_min = f"{vert_ext_min}"
552
+ if vert_ext_max is not None:
553
+ vert_ext_max = f"{vert_ext_max}"
554
+ bboxel = self._write_extent(bbox, vert_ext_min, vert_ext_max)
555
+ if bboxel is not None and mtype != 'service':
556
+ # Add <mri:extent> element etc.
557
+ resident.append(bboxel)
558
+
559
+ # Service identification
560
+ if mtype == 'service':
561
+ # Service type & service type version
562
+ val = util.getqattr(result, queryables['mdb:ServiceType']['dbcol'])
563
+ val2 = util.getqattr(result, queryables['mdb:ServiceTypeVersion']['dbcol'])
564
+ if val is not None:
565
+ tmp = etree.SubElement(resident, util.nspath_eval('srv:serviceType', self.namespaces))
566
+ etree.SubElement(tmp, util.nspath_eval('gco:LocalName', self.namespaces)).text = val
567
+ tmp = etree.SubElement(resident, util.nspath_eval('srv:serviceTypeVersion', self.namespaces))
568
+ etree.SubElement(tmp, util.nspath_eval('gco:CharacterString', self.namespaces)).text = val2
569
+
570
+ # Keywords
571
+ kw = util.getqattr(result, queryables['mdb:Subject']['dbcol'])
572
+ if kw is not None:
573
+ srv_keywords = etree.SubElement(resident, util.nspath_eval('srv:descriptiveKeywords', self.namespaces))
574
+ srv_keywords.append(self._write_keywords(kw))
575
+
576
+ # Extent and bounding box
577
+ if bboxel is not None:
578
+ # Change <mri:extent> element to <srv:extent> and append
579
+ bboxel.tag = util.nspath_eval('srv:extent', self.namespaces)
580
+ resident.append(bboxel)
581
+
582
+ val = util.getqattr(result, queryables['mdb:CouplingType']['dbcol'])
583
+ if val is not None:
584
+ couplingtype = etree.SubElement(resident, util.nspath_eval('srv:couplingType', self.namespaces))
585
+ etree.SubElement(couplingtype, util.nspath_eval('srv:SV_CouplingType', self.namespaces), codeListValue=val, codeList=f'{CODELIST}#SV_CouplingType').text = val
586
+
587
+ if esn in ['summary', 'full']:
588
+ # all service resources as coupled resources
589
+ coupledresources = util.getqattr(result, queryables['mdb:OperatesOn']['dbcol'])
590
+ operations = util.getqattr(result, queryables['mdb:Operation']['dbcol'])
591
+
592
+ if coupledresources:
593
+ for val2 in coupledresources.split(','):
594
+ coupledres = etree.SubElement(resident, util.nspath_eval('srv:coupledResource', self.namespaces))
595
+ svcoupledres = etree.SubElement(coupledres, util.nspath_eval('srv:SV_CoupledResource', self.namespaces))
596
+ opname = etree.SubElement(svcoupledres, util.nspath_eval('srv:coupledName', self.namespaces))
597
+ etree.SubElement(opname, util.nspath_eval('gco:ScopedName', self.namespaces)).text = get_resource_opname(operations)
598
+ sid = etree.SubElement(svcoupledres, util.nspath_eval('srv:resourceReference', self.namespaces))
599
+ # Unfortunately only have one field to apply
600
+ # <srv:resourceReference> has a <cit:CI_Citation>
601
+ ci_citation = etree.SubElement(sid, util.nspath_eval('cit:CI_Citation', self.namespaces))
602
+ # <cit:CI_Citation> must have a title, insert reference
603
+ title = build_path(cit_citation, ['cit:title', 'gco:CharacterString'], self.namespaces)
604
+ title.text = val2
605
+ # Insert reference as a identifier code
606
+ code = build_path(cit_citation, ['cit:identifer', 'mcc:MD_Identifier', 'mcc:code', 'gco:CharacterString'], self.namespaces)
607
+ code.text = val2
608
+
609
+ # Service operations
610
+ if operations:
611
+ for i in operations.split(','):
612
+ oper = etree.SubElement(resident, util.nspath_eval('srv:containsOperations', self.namespaces))
613
+ sv_opermetadata = etree.SubElement(oper, util.nspath_eval('srv:SV_OperationMetadata', self.namespaces))
614
+
615
+ oper_name = etree.SubElement(sv_opermetadata, util.nspath_eval('srv:operationName', self.namespaces))
616
+ etree.SubElement(oper_name, util.nspath_eval('gco:CharacterString', self.namespaces)).text = i
617
+
618
+ dcp = etree.SubElement(sv_opermetadata, util.nspath_eval('srv:distributedComputingPlatform', self.namespaces))
619
+ dcp_list1 = etree.SubElement(dcp, util.nspath_eval('srv:DCPList', self.namespaces))
620
+ etree.SubElement(dcp_list1, util.nspath_eval('srv:DCPList', self.namespaces), codeList=f'{CODELIST}#DCPList', codeListValue='HTTPGet').text = 'HTTPGet'
621
+
622
+ dcp_list2 = etree.SubElement(dcp, util.nspath_eval('srv:DCPList', self.namespaces))
623
+ etree.SubElement(dcp_list2, util.nspath_eval('srv:DCPList', self.namespaces), codeList=f'{CODELIST}#DCPList', codeListValue='HTTPPost').text = 'HTTPPost'
624
+
625
+ connectpoint = etree.SubElement(sv_opermetadata, util.nspath_eval('srv:connectPoint', self.namespaces))
626
+ onlineres = etree.SubElement(connectpoint, util.nspath_eval('cit:CI_OnlineResource', self.namespaces))
627
+ linkage = etree.SubElement(onlineres, util.nspath_eval('cit:linkage', self.namespaces))
628
+ etree.SubElement(linkage, util.nspath_eval('gco:CharacterString', self.namespaces)).text = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Source'])
629
+
630
+ # operates on resource(s)
631
+ if coupledresources:
632
+ for i in coupledresources.split(','):
633
+ operates_on = etree.SubElement(resident, util.nspath_eval('srv:operatesOn', self.namespaces))
634
+ code = build_path(operates_on, ['mri:MD_DataIdentification','mri:citation','cit:CI_Citation','cit:identifier','mcc:MD_Identifier','mcc:code','gcx:Anchor'], self.namespaces)
635
+ code.text = f"{util.bind_url(self.url)}service=CSW&version=2.0.2&request=GetRecordById&outputschema={self.repository['mdb:MD_Metadata']['outputschema']}&id={idval}-{i}"
636
+
637
+ rlinks = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Links'])
638
+ if rlinks:
639
+ distinfo = etree.SubElement(node, util.nspath_eval('mdb:distributionInfo', self.namespaces))
640
+ distinfo2 = etree.SubElement(distinfo, util.nspath_eval('mrd:MD_Distribution', self.namespaces))
641
+ transopts = etree.SubElement(distinfo2, util.nspath_eval('mrd:transferOptions', self.namespaces))
642
+ dtransopts = etree.SubElement(transopts, util.nspath_eval('mrd:MD_DigitalTransferOptions', self.namespaces))
643
+
644
+ for link in util.jsonify_links(rlinks):
645
+ online = etree.SubElement(dtransopts, util.nspath_eval('mrd:onLine', self.namespaces))
646
+ online2 = etree.SubElement(online, util.nspath_eval('cit:CI_OnlineResource', self.namespaces))
647
+
648
+ linkage = etree.SubElement(online2, util.nspath_eval('cit:linkage', self.namespaces))
649
+ etree.SubElement(linkage, util.nspath_eval('gco:CharacterString', self.namespaces)).text = link['url']
650
+
651
+ protocol = etree.SubElement(online2, util.nspath_eval('cit:protocol', self.namespaces))
652
+ etree.SubElement(protocol, util.nspath_eval('gco:CharacterString', self.namespaces)).text = link.get('protocol', 'WWW:LINK')
653
+
654
+ name = etree.SubElement(online2, util.nspath_eval('cit:name', self.namespaces))
655
+ etree.SubElement(name, util.nspath_eval('gco:CharacterString', self.namespaces)).text = link.get('name')
656
+
657
+ desc = etree.SubElement(online2, util.nspath_eval('cit:description', self.namespaces))
658
+ etree.SubElement(desc, util.nspath_eval('gco:CharacterString', self.namespaces)).text = link.get('description')
659
+ return node
660
+
661
+ def _write_contact_phone(self, ci_contact, phone_num_str):
662
+ """
663
+ Write out a telephone number of a contact within an organisation
664
+
665
+ :param ci_contact: 'cit:CI_Contact' XML etree.Element
666
+ :param phone_num_str: phone number string
667
+ :returns: XML contact phone etree.Element
668
+ """
669
+ phone = build_path(ci_contact, ['cit:phone', 'cit:CI_Telephone'], self.namespaces)
670
+ ph_number = build_path(phone, ['cit:number', 'gco:characterString'], self.namespaces)
671
+ ph_number.text = phone_num_str
672
+ ph_type = build_path(phone, ['cit:numberType', 'cit:CI_TelephoneTypeCode'], self.namespaces)
673
+ ph_type.text = "voice"
674
+
675
+ def _write_contact_fax(self, ci_contact, fax_num_str):
676
+ """
677
+ Write out a fax number of a contact within an organisation
678
+
679
+ :param ci_contact: 'cit:CI_Contact' XML etree.Element
680
+ :param fax_num_str: fax number string
681
+ :returns: XML contact fax etree.Element
682
+ """
683
+ phone = build_path(ci_contact, ['cit:phone', 'cit:CI_Telephone'], self.namespaces, reuse=False)
684
+ ph_number = build_path(phone, ['cit:number', 'gco:characterString'], self.namespaces)
685
+ ph_number.text = fax_num_str
686
+ ph_type = build_path(phone, ['cit:numberType', 'cit:CI_TelephoneTypeCode'], self.namespaces)
687
+ ph_type.text = "facsimile"
688
+
689
+ def _write_contact_address(self, ci_resp, ci_contact, **contact):
690
+ """
691
+ Write out an address of a contact within an organisation
692
+
693
+ :param ci_resp: 'cit:CI_Responsibility' XML etree.Element
694
+ :param ci_contact: 'cit:CI_Contact' XML etree.Element
695
+ :param contact: dict of contact details, keys are 'address' 'city' 'region' 'postcode' 'country' 'email'
696
+ :returns: XML contact address etree.Element
697
+ """
698
+ ci_address = build_path(ci_contact, ['cit:address', 'cit:CI_Address'], self.namespaces)
699
+ if contact.get('address', None) is not None:
700
+ delivery_point = etree.SubElement(ci_address, util.nspath_eval('cit:deliveryPoint', self.namespaces))
701
+ etree.SubElement(delivery_point, util.nspath_eval('gco:CharacterString', self.namespaces)).text = contact['address']
702
+ if contact.get('city', None) is not None:
703
+ city = etree.SubElement(ci_address, util.nspath_eval('cit:city', self.namespaces))
704
+ etree.SubElement(city, util.nspath_eval('gco:CharacterString', self.namespaces)).text = contact['city']
705
+ if contact.get('region', None) is not None:
706
+ admin_area = etree.SubElement(ci_address, util.nspath_eval('cit:administrativeArea', self.namespaces))
707
+ etree.SubElement(admin_area, util.nspath_eval('gco:CharacterString', self.namespaces)).text = contact['region']
708
+ if contact.get('postcode', None) is not None:
709
+ postal_code = etree.SubElement(ci_address, util.nspath_eval('cit:postalCode', self.namespaces))
710
+ etree.SubElement(postal_code, util.nspath_eval('gco:CharacterString', self.namespaces)).text = contact['postcode']
711
+ if contact.get('country', None) is not None:
712
+ country = etree.SubElement(ci_address, util.nspath_eval('cit:country', self.namespaces))
713
+ etree.SubElement(country, util.nspath_eval('gco:CharacterString', self.namespaces)).text = contact['country']
714
+ if contact.get('email', None) is not None:
715
+ email = etree.SubElement(ci_address, util.nspath_eval('cit:electronicMailAddress', self.namespaces))
716
+ etree.SubElement(email, util.nspath_eval('gco:CharacterString', self.namespaces)).text = contact['email']
717
+
718
+ # URL of organisation or individual
719
+ if contact.get('url', None) is not None:
720
+ path = ['cit:onlineResource', 'cit:CI_OnlineResource', 'cit:linkage', 'gco:characterString']
721
+ url = build_path(ci_contact, path, self.namespaces)
722
+ url.text = contact['url']
723
+ # Role
724
+ role = build_path(ci_resp, ['cit:role', 'cit:CI_RoleCode'], self.namespaces)
725
+ role.set("codeList", f'{CODELIST}#CI_RoleCode')
726
+ role_str = 'pointOfContact'
727
+ if contact.get('role', None) is not None:
728
+ role_str = contact.get('role')
729
+ role.set("codeListValue", role_str)
730
+
731
+ def _write_keywords(self, keywords):
732
+ """
733
+ Generate XML mri:MD_Keywords construct
734
+
735
+ :param keywords: keywords CSV string
736
+ :returns: XML as etree.Element
737
+ """
738
+ md_keywords = etree.Element(util.nspath_eval('mri:MD_Keywords', self.namespaces))
739
+ for kw in keywords.split(','):
740
+ keyword = etree.SubElement(md_keywords, util.nspath_eval('mri:keyword', self.namespaces))
741
+ etree.SubElement(keyword, util.nspath_eval('gco:CharacterString', self.namespaces)).text = kw
742
+ return md_keywords
743
+
744
+ def _write_extent(self, bbox, vert_ext_min, vert_ext_max):
745
+ """
746
+ Generate XML for a bounding box in 2 dimensions
747
+ or a bounding box and vertical extent in 3 dimensions
748
+
749
+ :param bbox: bounding box in EWKT (Extended Well Known Text) format
750
+ :param vert_ext_min: vertical extent minimum, pass in None for 2D
751
+ :param vert_extent_max: vertical extent maximum, pass in None for 2D
752
+ :returns: XML as etree.Element
753
+ """
754
+ if bbox is not None:
755
+ try:
756
+ bbox2 = util.wkt2geom(bbox)
757
+ except:
758
+ return None
759
+ extent = etree.Element(util.nspath_eval('mri:extent', self.namespaces))
760
+ ex_extent = etree.SubElement(extent, util.nspath_eval('gex:EX_Extent', self.namespaces))
761
+ gbb = build_path(ex_extent, ['gex:geographicElement', 'gex:EX_GeographicBoundingBox'], self.namespaces)
762
+ west = etree.SubElement(gbb, util.nspath_eval('gex:westBoundLongitude', self.namespaces))
763
+ east = etree.SubElement(gbb, util.nspath_eval('gex:eastBoundLongitude', self.namespaces))
764
+ south = etree.SubElement(gbb, util.nspath_eval('gex:southBoundLatitude', self.namespaces))
765
+ north = etree.SubElement(gbb, util.nspath_eval('gex:northBoundLatitude', self.namespaces))
766
+
767
+ etree.SubElement(west, util.nspath_eval('gco:Decimal', self.namespaces)).text = str(bbox2[0])
768
+ etree.SubElement(south, util.nspath_eval('gco:Decimal', self.namespaces)).text = str(bbox2[1])
769
+ etree.SubElement(east, util.nspath_eval('gco:Decimal', self.namespaces)).text = str(bbox2[2])
770
+ etree.SubElement(north, util.nspath_eval('gco:Decimal', self.namespaces)).text = str(bbox2[3])
771
+
772
+ # If there is a vertical extent
773
+ if vert_ext_min is not None and vert_ext_max is not None:
774
+ vert_ext = build_path(ex_extent, ['gex:verticalElement', 'gex:EX_VerticalExtent'], self.namespaces)
775
+ min_val = build_path(vert_ext, ['gex:minimumValue', 'gco:Real'], self.namespaces)
776
+ min_val.text = vert_ext_min
777
+ max_val = build_path(vert_ext, ['gex:maximumValue', 'gco:Real'], self.namespaces)
778
+ max_val.text = vert_ext_max
779
+
780
+ return extent
781
+ return None
782
+
783
+ def _write_date(self, dateval, datetypeval):
784
+ """
785
+ Generate XML date elements
786
+
787
+ :param dateval: date string
788
+ :param datetypeval: date type code string
789
+ :returns: date XML etree.Element
790
+ """
791
+ date1 = etree.Element(util.nspath_eval('cit:CI_Date', self.namespaces))
792
+ date2 = etree.SubElement(date1, util.nspath_eval('cit:date', self.namespaces))
793
+ if dateval.find('T') != -1:
794
+ dateel = 'gco:DateTime'
795
+ else:
796
+ dateel = 'gco:Date'
797
+ etree.SubElement(date2, util.nspath_eval(dateel, self.namespaces)).text = dateval
798
+ datetype = etree.SubElement(date1, util.nspath_eval('cit:dateType', self.namespaces))
799
+ datetype.append(write_codelist_element('cit:CI_DateTypeCode', datetypeval, self.namespaces))
800
+ return date1
801
+
802
+ # END of class
803
+
804
+
805
+
806
+ def get_resource_opname(operations):
807
+ """
808
+ Looks for resource opename in a CSV string
809
+
810
+ :param operations: CSV string of operations
811
+ :returns: operation name
812
+ """
813
+ for op in operations.split(','):
814
+ if op in ['GetMap', 'GetFeature', 'GetCoverage', 'GetObservation']:
815
+ return op
816
+ return None
817
+
818
+ def write_codelist_element(codelist_element, codelist_value, nsmap):
819
+ """
820
+ Generic routine to write codelist artributes into an element
821
+
822
+ :param codelist_element: codelist element
823
+ :param codelist_value: codelist values
824
+ :param nsmap: namespace map, namepace str -> namespace URI
825
+ :returns: lxml.etree.Element
826
+ """
827
+ # Get tag name without namespace
828
+ namespace, no_ns_tag = codelist_element.split(':')
829
+ element = etree.Element(util.nspath_eval(codelist_element, nsmap),
830
+ codeSpace='http://standards.iso.org/iso/19115', codeList=f'{CODELIST}#{no_ns_tag}', codeListValue=codelist_value)
831
+ element.text = codelist_value
832
+ return element
833
+
834
+
835
+ def build_path(node, path_list, nsmap, reuse=True):
836
+ """
837
+ Generic routine to build an etree.Element path
838
+ Set reuse=False if you want to create duplicates
839
+
840
+ :param node: add elements to this Element
841
+ :param path_list: list of xml tags of new path to create, list of strings
842
+ :param reuse: if False will always create new Elements along this path
843
+ :return: returns the last etree.Element in the new Element path
844
+ """
845
+ tail = node
846
+ for elem_name in path_list:
847
+ # Does the next node in the path exist?
848
+ next_node = node.find(elem_name, namespaces=nsmap)
849
+ # If next node does not exist or reuse flag is False then create it
850
+ if next_node is None or not reuse:
851
+ tail = etree.SubElement(tail, util.nspath_eval(elem_name, nsmap))
852
+ else:
853
+ tail = next_node
854
+ return tail