UNPKG

terriajs

Version:

Geospatial data visualization platform.

181 lines 7.84 kB
import { createTransformer } from "mobx-utils"; import defined from "terriajs-cesium/Source/Core/defined"; import isDefined from "../../../Core/isDefined"; import loadXML from "../../../Core/loadXML"; import TerriaError from "../../../Core/TerriaError"; import xml2json from "../../../ThirdParty/xml2json"; import { isJsonString } from "../../../Core/Json"; export function getRectangleFromLayer(layer) { const bbox = layer.WGS84BoundingBox; if (bbox) { return { west: bbox.westBoundLongitude, south: bbox.southBoundLatitude, east: bbox.eastBoundLongitude, north: bbox.northBoundLatitude }; } return undefined; } /** * Get CapabilitiesService (in WMS form) */ function getService(json) { const serviceProviderJson = json["ServiceProvider"]; const serviceIdentificationJson = json["ServiceIdentification"]; const serviceAddressJson = serviceProviderJson?.["ServiceContact"]?.["ContactInfo"]?.["Address"]; const service = { Title: serviceIdentificationJson?.["Title"], Abstract: serviceIdentificationJson?.["Abstract"], Fees: serviceIdentificationJson?.["Fees"], AccessConstraints: serviceIdentificationJson?.["AccessConstraints"], KeywordList: { Keyword: serviceIdentificationJson?.["Keywords"]?.["Keyword"] }, ContactInformation: { ContactPersonPrimary: { ContactPerson: serviceProviderJson?.["ServiceContact"]?.["IndividualName"], ContactOrganization: serviceProviderJson?.["ProviderName"] }, ContactPosition: serviceProviderJson?.["ServiceContact"]?.["PositionName"], ContactAddress: { Address: serviceAddressJson?.["DeliveryPoint"], City: serviceAddressJson?.["City"], StateOrProvince: serviceAddressJson?.["AdministrativeArea"], PostCode: serviceAddressJson?.["PostalCode"], Country: serviceAddressJson?.["Country"] }, ContactVoiceTelephone: serviceProviderJson?.["ServiceContact"]?.["ContactInfo"]?.["Phone"]?.["Voice"], ContactFacsimileTelephone: serviceProviderJson?.["ServiceContact"]?.["ContactInfo"]?.["Phone"]?.["Facsimile"], ContactElectronicMailAddress: serviceProviderJson?.["ServiceContact"]?.["ContactInfo"]?.["Address"]?.["ElectronicMailAddress"] } }; return service; } function getFeatureTypes(json) { let featureTypesJson = json.FeatureTypeList?.FeatureType; if (!isDefined(featureTypesJson)) { return []; } if (!Array.isArray(featureTypesJson)) { featureTypesJson = [featureTypesJson]; } return (featureTypesJson.map((json) => { const lowerCorner = json["WGS84BoundingBox"]?.["LowerCorner"].split(" "); const upperCorner = json["WGS84BoundingBox"]?.["UpperCorner"].split(" "); let outputFormats; if (isDefined(json.OutputFormats)) { outputFormats = Array.isArray(json.OutputFormats) ? json.OutputFormats.map((o) => o.Format) : [json.OutputFormats.Format]; } return { Title: json.Title, Name: json.Name, Abstract: json.Abstract, Keyword: json["Keywords"]?.["Keyword"], WGS84BoundingBox: { westBoundLongitude: lowerCorner && parseFloat(lowerCorner[0]), southBoundLatitude: lowerCorner && parseFloat(lowerCorner[1]), eastBoundLongitude: upperCorner && parseFloat(upperCorner[0]), northBoundLatitude: upperCorner && parseFloat(upperCorner[1]) }, OutputFormats: outputFormats }; }) || []); } function getOutputTypes(json) { const outputTypes = json.OperationsMetadata?.Operation?.find((op) => op.name === "GetFeature")?.Parameter?.find((p) => p.name === "outputFormat")?.Value; if (!isDefined(outputTypes)) { return; } return Array.isArray(outputTypes) ? outputTypes : [outputTypes]; } /** * Get the coordinate systems (srsName) supported by the WFS service for each layer. * @param json * returns an object with an array of srsNames for each layer. The first element is the defaultSRS as specified by the WFS service. * TODO: For catalog items that specify which layer we are interested in, why build the array describing the srsNames for all the other layers too? */ function getSrsNames(json) { const layers = json.FeatureTypeList?.FeatureType; let srsNamesByLayer = []; if (Array.isArray(layers)) { srsNamesByLayer = layers.map(buildSrsNameObject); } else { srsNamesByLayer.push(buildSrsNameObject(json.FeatureTypeList?.FeatureType)); } return srsNamesByLayer; } /** * Helper function to build individual objects describing the allowable srsNames for each layer in the WFS * @param layer */ function buildSrsNameObject(layer) { const srsNames = []; if (isJsonString(layer.DefaultSRS)) srsNames.push(layer.DefaultSRS); if (Array.isArray(layer.OtherSRS)) layer.OtherSRS.forEach((item) => { if (isJsonString(item)) srsNames.push(item); }); else if (isJsonString(layer.OtherSRS)) srsNames.push(layer.OtherSRS); return { layerName: layer.Name, srsArray: srsNames }; } export default class WebFeatureServiceCapabilities { static fromUrl = createTransformer((url) => { return loadXML(url).then(function (capabilitiesXml) { const json = xml2json(capabilitiesXml); if (!defined(json.ServiceIdentification)) { throw new TerriaError({ title: "Invalid GetCapabilities", message: `The URL ${url} was retrieved successfully but it does not appear to be a valid Web Feature Service (WFS) GetCapabilities document.` + `\n\nEither the catalog file has been set up incorrectly, or the server address has changed.` }); } return new WebFeatureServiceCapabilities(capabilitiesXml, json); }); }); service; outputTypes; featureTypes; srsNames; constructor(_xml, json) { this.service = getService(json); this.outputTypes = getOutputTypes(json); this.featureTypes = getFeatureTypes(json); this.srsNames = getSrsNames(json); } /** * Finds the layer in GetCapabilities corresponding to a given layer name. Names are * resolved as foll * * The layer has the exact name specified. * * The layer name matches the name in the spec if the namespace portion is removed. * * The name in the spec matches the title of the layer. * * @param {String} name The layer name to resolve. * @returns {CapabilitiesLayer} The resolved layer, or `undefined` if the layer name could not be resolved. */ findLayer(name) { // Look for an exact match on the name. let match = this.featureTypes.find((ft) => ft.Name === name); if (!match) { const colonIndex = name.indexOf(":"); if (colonIndex >= 0) { // This looks like a namespaced name. Such names will (usually?) show up in GetCapabilities // as just their name without the namespace qualifier. const nameWithoutNamespace = name.substring(colonIndex + 1); match = this.featureTypes.find((ft) => ft.Name === nameWithoutNamespace); } } if (!match) { // Try matching by title. match = this.featureTypes.find((ft) => ft.Title === name); } return match; } } //# sourceMappingURL=WebFeatureServiceCapabilities.js.map