UNPKG

@loaders.gl/wms

Version:

Framework-independent loaders for the WMS (Web Map Service) standard

183 lines 7.12 kB
// loaders.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import { DataSource } from '@loaders.gl/loader-utils'; import { CSWCapabilitiesLoader } from "./csw-capabilities-loader.js"; import { CSWRecordsLoader } from "./csw-records-loader.js"; import { CSWDomainLoader } from "./csw-domain-loader.js"; import { WMSErrorLoader as CSWErrorLoader } from "./wms-error-loader.js"; export const CSWSource = { name: 'CSW', id: 'csw', module: 'wms', version: '0.0.0', extensions: [], mimeTypes: [], type: 'csw', fromUrl: true, fromBlob: false, defaultOptions: { wfs: {} }, testURL: (url) => url.toLowerCase().includes('wfs'), createDataSource: (url, options) => new CSWCatalogSource(url, options) }; /** * The CSWCatalogSource class * - provides type safe methods to form URLs to a CSW service * - provides type safe methods to query and parse results (and errors) from a CSW service * @note Only the URL parameter conversion is supported. XML posts are not supported. */ export class CSWCatalogSource extends DataSource { static type = 'csw'; static testURL = (url) => url.toLowerCase().includes('csw'); capabilities = null; /** A list of loaders used by the CSWCatalogSource methods */ loaders = [CSWErrorLoader, CSWCapabilitiesLoader]; /** Create a CSWCatalogSource */ constructor(url, options) { super(url, options, CSWSource.defaultOptions); } async getMetadata() { const capabilities = await this.getCapabilities(); return this.normalizeMetadata(capabilities); } normalizeMetadata(capabilities) { return capabilities; } async getServiceDirectory(options) { const services = []; const unknownServices = []; const records = await this.getRecords(); for (const record of records.records) { for (const reference of record.references) { const url = reference.value; switch (reference.scheme) { case 'OGC:WMS': services.push({ name: record.title, type: 'ogc-wms-service', ...this._parseOGCUrl(url) }); break; case 'OGC:WMTS': services.push({ name: record.title, type: 'ogc-wmts-service', ...this._parseOGCUrl(url) }); break; case 'OGC:WFS': services.push({ name: record.title, type: 'ogc-wfs-service', ...this._parseOGCUrl(url) }); break; default: unknownServices.push({ name: record.title, type: 'unknown', url: reference.value, scheme: reference.scheme }); } } } return options?.includeUnknown ? services.concat(unknownServices) : services; } _parseOGCUrl(url) { const parts = url.split('?'); return { url: parts[0], params: parts[1] || '' }; } // CSW Service API Stubs /** Get Capabilities */ async getCapabilities(cswParameters, vendorParameters) { const url = this.getCapabilitiesURL(cswParameters, vendorParameters); const response = await this.fetch(url); const arrayBuffer = await response.arrayBuffer(); this._checkResponse(response, arrayBuffer); const capabilities = await CSWCapabilitiesLoader.parse(arrayBuffer, this.options.core.loadOptions); return capabilities; } /** Get Records */ async getRecords(cswParameters, vendorParameters) { const url = this.getRecordsURL(cswParameters, vendorParameters); const response = await this.fetch(url); const arrayBuffer = await response.arrayBuffer(); this._checkResponse(response, arrayBuffer); return await CSWRecordsLoader.parse(arrayBuffer, this.options.core.loadOptions); } /** Get Domain */ async getDomain(cswParameters, vendorParameters) { const url = this.getDomainURL(cswParameters, vendorParameters); const response = await this.fetch(url); const arrayBuffer = await response.arrayBuffer(); this._checkResponse(response, arrayBuffer); return await CSWDomainLoader.parse(arrayBuffer, this.options.core.loadOptions); } // Typed URL creators // For applications that want full control of fetching and parsing /** Generate a URL for the GetCapabilities request */ getCapabilitiesURL(cswParameters, vendorParameters) { const options = { version: '3.0.0', ...cswParameters, ...vendorParameters, service: 'CSW', request: 'GetCapabilities' }; return this._getCSWUrl(options, vendorParameters); } /** Generate a URL for the GetCapabilities request */ getRecordsURL(cswParameters, vendorParameters) { const options = { version: '3.0.0', typenames: 'csw:Record', ...cswParameters, ...vendorParameters, service: 'CSW', request: 'GetRecords' }; return this._getCSWUrl(options, vendorParameters); } /** Generate a URL for the GetCapabilities request */ getDomainURL(cswParameters, vendorParameters) { const options = { version: '3.0.0', ...cswParameters, ...vendorParameters, service: 'CSW', request: 'GetDomain' }; return this._getCSWUrl(options, vendorParameters); } // INTERNAL METHODS /** * @note case _getCSWUrl may need to be overridden to handle certain backends? * */ _getCSWUrl(options, vendorParameters) { let url = this.url; let first = true; for (const [key, value] of Object.entries(options)) { url += first ? '?' : '&'; first = false; if (Array.isArray(value)) { url += `${key.toUpperCase()}=${value.join(',')}`; } else { url += `${key.toUpperCase()}=${value ? String(value) : ''}`; } } return encodeURI(url); } /** Checks for and parses a CSW XML formatted ServiceError and throws an exception */ _checkResponse(response, arrayBuffer) { const contentType = response.headers['content-type']; if (!response.ok || CSWErrorLoader.mimeTypes.includes(contentType)) { const error = CSWErrorLoader.parseSync?.(arrayBuffer, this.options.core.loadOptions); throw new Error(error); } } /** Error situation detected */ _parseError(arrayBuffer) { const error = CSWErrorLoader.parseSync?.(arrayBuffer, this.options.core.loadOptions); return new Error(error); } } //# sourceMappingURL=csw-source.js.map