diff --git a/app/src/components/wfs/WfsFeatureTypeInfo.vue b/app/src/components/wfs/WfsFeatureTypeInfo.vue index 12ee38a..cb96ba6 100644 --- a/app/src/components/wfs/WfsFeatureTypeInfo.vue +++ b/app/src/components/wfs/WfsFeatureTypeInfo.vue @@ -54,6 +54,9 @@ export default { ...('geometryType' in this.featureType && { 'geometry type': this.featureType.geometryType, }), + ...('keywords' in this.featureType && { + keywords: this.featureType.keywords, + }), }; }, featureProperties() { diff --git a/app/src/components/wms/WmsLayerInfo.vue b/app/src/components/wms/WmsLayerInfo.vue index 5fc78d3..1c0aef7 100644 --- a/app/src/components/wms/WmsLayerInfo.vue +++ b/app/src/components/wms/WmsLayerInfo.vue @@ -64,6 +64,7 @@ export default { this.layer.attribution.title && { attribution: this.layer.attribution.title, }), + ...(this.layer.keywords && { keywords: this.layer.keywords }), }; }, fullMapSrc() { diff --git a/fixtures/wms/capabilities-brgm-1-1-1.xml b/fixtures/wms/capabilities-brgm-1-1-1.xml index 7e9c65c..f8b810d 100644 --- a/fixtures/wms/capabilities-brgm-1-1-1.xml +++ b/fixtures/wms/capabilities-brgm-1-1-1.xml @@ -139,6 +139,9 @@ BRGM INSPIRE:ViewService infoMapAccessService + WMS 1.1.1 + WMS 1.3.0 + SLD 1.1.0 EPSG:4326 CRS:84 @@ -187,6 +190,7 @@ Geologie INSPIRE:Geology + Geology EPSG:4326 EPSG:3857 @@ -243,6 +247,7 @@ Geologie INSPIRE:Geology + Geology EPSG:4326 EPSG:3857 @@ -277,6 +282,7 @@ Geologie INSPIRE:Geology + Geology EPSG:4326 EPSG:3857 diff --git a/src/wfs/capabilities.spec.ts b/src/wfs/capabilities.spec.ts index 61cc015..67f50ab 100644 --- a/src/wfs/capabilities.spec.ts +++ b/src/wfs/capabilities.spec.ts @@ -35,6 +35,7 @@ describe('WFS capabilities', () => { abstract: 'Registre Parcellaire Graphique 2010 en Aquitaine - Agence de Service et de Paiement', defaultCrs: 'EPSG:2154', + keywords: ['features', 'rpg2010'], latLonBoundingBox: [ -1.9540704007796161, 42.73286181824404, 1.496463327812538, 45.717071228823876, @@ -53,6 +54,7 @@ describe('WFS capabilities', () => { abstract: 'Représentation des moyennes journalières des trafics routiers sur les routes départementales de la\n Charente (16) au 1er Janvier 2021.\n\n Mise à jour : Mars 2021\n ', defaultCrs: 'EPSG:2154', + keywords: ['features', 'comptages_routiers_l'], latLonBoundingBox: [ -0.4906009184568518, 45.175543885638376, 0.9778719979726385, 46.14349349624617, @@ -72,6 +74,7 @@ describe('WFS capabilities', () => { abstract: 'Hiérarchisation du réseau routier départemental en fonction des caractéristiques de chaque section\n de route et de son usage au 1er Janvier 2021.\n\n Mise à jour : Mars 2021\n ', defaultCrs: 'EPSG:2154', + keywords: ['features', 'hierarchisation_l'], latLonBoundingBox: [ -0.4832134559131876, 45.18037755571674, 0.9725372441782966, 46.13877580094452, @@ -131,6 +134,7 @@ describe('WFS capabilities', () => { expect(featureTypes[0]).toEqual({ abstract: 'Domaine public', defaultCrs: 'EPSG:2154', + keywords: ['domaine_public_hdf_com', 'domaine', 'public'], latLonBoundingBox: [ 1.3472171890368316, 48.82764887581316, 4.285589467078578, 51.0896786738123, diff --git a/src/wfs/capabilities.ts b/src/wfs/capabilities.ts index bfd6059..ea7445a 100644 --- a/src/wfs/capabilities.ts +++ b/src/wfs/capabilities.ts @@ -158,6 +158,16 @@ function parseFeatureType( 'Format' ).map(getElementText); + const keywords = serviceVersion.startsWith('1.0') + ? getElementText(findChildElement(featureTypeEl, 'Keywords')) + .split(',') + .map((keyword) => keyword.trim()) + : findChildrenElement( + findChildElement(featureTypeEl, 'Keywords'), + 'Keyword' + ) + .map(getElementText) + .filter((v, i, arr) => arr.indexOf(v) === i); return { name: getElementText(findChildElement(featureTypeEl, 'Name')), title: getElementText(findChildElement(featureTypeEl, 'Title')), @@ -171,5 +181,6 @@ function parseFeatureType( latLonBoundingBox: serviceVersion.startsWith('1.0') ? parseBBox100() : parseBBox(), + keywords: keywords, }; } diff --git a/src/wfs/endpoint.spec.ts b/src/wfs/endpoint.spec.ts index 9b79b14..a6ebd86 100644 --- a/src/wfs/endpoint.spec.ts +++ b/src/wfs/endpoint.spec.ts @@ -131,6 +131,7 @@ describe('WfsEndpoint', () => { 46.13877580094452, ], defaultCrs: 'EPSG:2154', + keywords: ['features', 'hierarchisation_l'], otherCrs: ['EPSG:32615', 'EPSG:32616', 'EPSG:32617', 'EPSG:32618'], outputFormats: [ 'application/gml+xml; version=3.2', @@ -170,6 +171,7 @@ describe('WfsEndpoint', () => { 46.13877580094452, ], defaultCrs: 'EPSG:2154', + keywords: ['features', 'hierarchisation_l'], otherCrs: ['EPSG:32615', 'EPSG:32616', 'EPSG:32617', 'EPSG:32618'], outputFormats: [ 'application/gml+xml; version=3.2', diff --git a/src/wfs/endpoint.ts b/src/wfs/endpoint.ts index f76f6fd..d5e3a92 100644 --- a/src/wfs/endpoint.ts +++ b/src/wfs/endpoint.ts @@ -124,6 +124,7 @@ export default class WfsEndpoint { defaultCrs: featureType.defaultCrs, otherCrs: featureType.otherCrs, outputFormats: featureType.outputFormats, + keywords: featureType.keywords, } as WfsFeatureTypeSummary; } diff --git a/src/wfs/featuretypeinfo.ts b/src/wfs/featuretypeinfo.ts index 2d7fde8..8555643 100644 --- a/src/wfs/featuretypeinfo.ts +++ b/src/wfs/featuretypeinfo.ts @@ -30,6 +30,7 @@ export function parseFeatureTypeInfo( otherCrs, outputFormats, latLonBoundingBox: boundingBox, + keywords, } = featureType; const hitsAttr = serviceVersion.startsWith('2.0') @@ -77,6 +78,7 @@ export function parseFeatureTypeInfo( ...(geometryName && { geometryName }), ...(geometryType && { geometryType }), ...(!Number.isNaN(objectCount) && { objectCount }), + ...(keywords && { keywords }), }; } diff --git a/src/wfs/model.ts b/src/wfs/model.ts index 4c78a82..85ea446 100644 --- a/src/wfs/model.ts +++ b/src/wfs/model.ts @@ -10,6 +10,7 @@ export type WfsFeatureTypeInternal = { otherCrs: CrsCode[]; outputFormats: MimeType[]; latLonBoundingBox?: BoundingBox; + keywords?: string[]; }; export type FeaturePropertyType = string | number | boolean; @@ -44,6 +45,7 @@ export type WfsFeatureTypeSummary = { defaultCrs: CrsCode; otherCrs: CrsCode[]; outputFormats: MimeType[]; + keywords?: string[]; }; export type WfsFeatureTypeFull = { @@ -73,6 +75,7 @@ export type WfsFeatureTypeFull = { * Not defined if object count could not be determined */ objectCount?: number; + keywords?: string[]; }; export type WfsFeatureWithProps = { diff --git a/src/wms/capabilities.spec.ts b/src/wms/capabilities.spec.ts index 3b6525f..8eb5e38 100644 --- a/src/wms/capabilities.spec.ts +++ b/src/wms/capabilities.spec.ts @@ -53,6 +53,15 @@ describe('WMS capabilities', () => { 'EPSG:4171': ['-180', '-90', '180', '90'], 'EPSG:4326': ['-180', '-90', '180', '90'], }, + keywords: [ + 'Géologie', + 'BRGM', + 'INSPIRE:ViewService', + 'infoMapAccessService', + 'WMS 1.1.1', + 'WMS 1.3.0', + 'SLD 1.1.0', + ], name: 'GEOSERVICES_GEOLOGIE', styles: [ { @@ -76,6 +85,7 @@ describe('WMS capabilities', () => { 'EPSG:4171': ['-180', '-90', '180', '90'], 'EPSG:4326': ['-180', '-90', '180', '90'], }, + keywords: [], name: 'GEOLOGIE', styles, title: 'Cartes géologiques', @@ -117,6 +127,7 @@ describe('WMS capabilities', () => { ], 'EPSG:4326': ['-5.86764', '41.1701', '11.0789', '51.1419'], }, + keywords: ['Geologie', 'INSPIRE:Geology', 'Geology'], name: 'SCAN_F_GEOL1M', styles: [ { @@ -167,6 +178,7 @@ describe('WMS capabilities', () => { ], 'EPSG:4326': ['-6.20495', '41.9671', '12.2874', '51.2917'], }, + keywords: ['Geologie', 'INSPIRE:Geology', 'Geology'], name: 'SCAN_F_GEOL250', styles, title: 'Carte géologique image de la France au 1/250000', @@ -204,6 +216,7 @@ describe('WMS capabilities', () => { ], 'EPSG:4326': ['-12.2064', '40.681', '11.894', '52.1672'], }, + keywords: ['Geologie', 'INSPIRE:Geology', 'Geology'], name: 'SCAN_D_GEOL50', styles, title: 'Carte géologique image de la France au 1/50 000e', @@ -229,6 +242,7 @@ describe('WMS capabilities', () => { 'EPSG:4171': ['-180', '-90', '180', '90'], 'EPSG:4326': ['-180', '-90', '180', '90'], }, + keywords: [], name: 'INHERIT_BBOX', styles: [ { diff --git a/src/wms/capabilities.ts b/src/wms/capabilities.ts index 10ab8a8..450f8d2 100644 --- a/src/wms/capabilities.ts +++ b/src/wms/capabilities.ts @@ -132,6 +132,14 @@ function parseLayer( Object.keys(boundingBoxes).length > 0 || inheritedBoundingBoxes === null ? boundingBoxes : inheritedBoundingBoxes; + + const keywords = findChildrenElement( + findChildElement(layerEl, 'KeywordList'), + 'Keyword' + ) + .map(getElementText) + .filter((v, i, arr) => arr.indexOf(v) === i); + const children = findChildrenElement(layerEl, 'Layer').map((layer) => parseLayer(layer, version, availableCrs, styles, attribution, boundingBoxes) ); @@ -143,6 +151,7 @@ function parseLayer( styles, attribution, boundingBoxes, + keywords, ...(children.length && { children }), }; } diff --git a/src/wms/endpoint.spec.ts b/src/wms/endpoint.spec.ts index 7ad9034..820b6d7 100644 --- a/src/wms/endpoint.spec.ts +++ b/src/wms/endpoint.spec.ts @@ -131,6 +131,7 @@ describe('WmsEndpoint', () => { 'EPSG:4171': ['-180', '-90', '180', '90'], 'EPSG:4326': ['-180', '-90', '180', '90'], }, + keywords: [], name: 'GEOLOGIE', styles: [ { diff --git a/src/wms/model.ts b/src/wms/model.ts index 68341f3..e462ac4 100644 --- a/src/wms/model.ts +++ b/src/wms/model.ts @@ -33,6 +33,7 @@ export type WmsLayerFull = { */ boundingBoxes: Record; attribution?: WmsLayerAttribution; + keywords?: string[]; /** * Not defined if the layer is a leaf in the tree */