UNPKG

geojson-to-gml-3

Version:

a package to translate geojson to GML 3.2.1

467 lines (433 loc) 11.7 kB
// ©️ Steven Kalt // Spdx-License-Identifier: PolyForm-Noncommercial-1.0.0 OR PolyForm-Free-Trial-1.0.0 /** * A library of functions to convert geojson to GML. * @module geojson-to-gml-3 */ import type { BBox, Geometry, GeometryCollection, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon, } from 'geojson'; import { type Name, NsRegistry, tag, attrs, type Xml, type Text, } from 'minimxml'; import { type CoordOrderParam, gmlGeometry, gmlGeometryCollection, gmlLineString, gmlMultiLineString, gmlMultiPoint, gmlMultiPolygon, gmlPoint, gmlPolygon, type IdParam, type NsParam, type SrsDimensionParam, type SrsNameParam, useCoords, withGmlNamespace, } from './internal.js'; export const GML = 'http://www.opengis.net/gml/3.2' as const; export type Gml = Xml<typeof GML>; export type ToGml = (r?: NsRegistry) => Gml; // TODO: document, test export const bbox = /* @__PURE__ */ (bbox: BBox, params: Params): ToGml => (namespaces?: NsRegistry): Gml => { namespaces = namespaces ?? new NsRegistry(); const { ns = 'gml' as Name, srsDimension, srsName } = params; const gml = namespaces.getOrInsert(ns, GML); return tag( gml.qualify('Envelope' as Name), attrs({ srsDimension, srsName, }), tag( gml.qualify('lowerCorner'), [], bbox .slice(0, bbox.length / 2) // safe since `BBox["length"]` must be either 4 or 6 .join(' ') as Text, // safe since `BBox` is composed entirely of numbers ), tag( gml.qualify('upperCorner'), [], bbox.slice(bbox.length / 2).join(' ') as Text, ), )(namespaces); }; /** The signature of all public geojson-to-gml conversion functions. Note this can only convert what geojson can store: simple feature types, not GML coverage, topology, etc. */ export type Converter<Geom extends Geometry = Geometry> = ( geom: Geom, params?: Params, ) => ToGml; /** Optional parameters for conversion of geojson to gml geometries */ export type Params = Partial< NsParam & IdParam & CoordOrderParam & SrsNameParam & SrsDimensionParam > & {}; /** * geojson coordinates are in longitude/easting, latitude/northing [,elevation] * order by [RFC-7946 § 3.1.1]{@link https://tools.ietf.org/html/rfc7946#section-3.1.1}. * however, you may use a CRS that follows a latitude/easting, * longitude/northing, [,elevation, [...etc]] order. * @see https://macwright.com/lonlat/ */ export const enum CoordinateOrder { /** Geojson's default order */ LON_LAT = 'lon,lat', LAT_LON = 'lat,lon', } export type MultiGeometry = | MultiPoint | MultiLineString | MultiPolygon | GeometryCollection; /*!! use-example file://./../tests/point.example.ts */ /** Converts an input geojson Point geometry to GML @function @param geom the {@link Point} to render to GML @param params @see Params @returns a GML string representing the input Point @example ```ts import { type Point } from 'geojson'; import { expect, test } from 'vitest'; import { point } from 'geojson-to-gml-3'; test('point', () => { const geom: Point = { type: 'Point', coordinates: [102.0, 0.5] }; expect(point(geom)()).toBe('' + `<gml:Point>` + `<gml:pos>` + `102 0.5` + `</gml:pos>` + `</gml:Point>` ); }); ``` */ export const point: Converter<Point> = /* @__PURE__ */ withGmlNamespace<Point>( useCoords(gmlPoint), ); /*!! use-example file://./../tests/lineString.example.ts */ /** Convert an input geojson LineString geometry to gml @function @param line the coordinates member of the geojson geometry @param gmlId the gml:id @param params optional parameters; @see {@link Params} @returns a string containing gml representing the input geometry @example ```ts import { type LineString } from 'geojson'; import { expect, test } from 'vitest'; import { lineString } from 'geojson-to-gml-3'; test('lineString', () => { const geom: LineString = { type: 'LineString', coordinates: [ [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0], ], }; expect(lineString(geom)()).toBe('' + `<gml:LineString>` + `<gml:posList>` + `102 0 103 1 104 0 105 1` + `</gml:posList>` + `</gml:LineString>` ); }); ``` */ export const lineString: Converter<LineString> = /* @__PURE__ */ withGmlNamespace<LineString>(useCoords(gmlLineString)); /*!! use-example file://./../tests/polygon.example.ts */ /** Converts an input geojson Polygon geometry to gml @function @param geom the {@link Polygon} to convert to gml @param params @see Params @returns a string containing gml representing the input geometry @example ```ts import { type Polygon } from 'geojson'; import { expect, test } from 'vitest'; import { polygon } from 'geojson-to-gml-3'; test('polygon', () => { const geom: Polygon = { type: 'Polygon', coordinates: [ [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0], ], ], }; expect(polygon(geom)()).toBe('' + `<gml:Polygon>` + `<gml:exterior>` + `<gml:LinearRing>` + `<gml:posList>` + `100 0 101 0 101 1 100 1 100 0` + `</gml:posList>` + `</gml:LinearRing>` + `</gml:exterior>` + `</gml:Polygon>` ); }); ``` */ export const polygon: Converter<Polygon> = /* @__PURE__ */ withGmlNamespace<Polygon>(useCoords(gmlPolygon)); /*!! use-example file://./../tests/multiPoint.example.ts */ /** Converts an input geojson MultiPoint geometry to gml @function @param geom the {@link MultiPoint} to convert to gml @param params @see Params @returns a string containing gml representing the input geometry @example ```ts import { type MultiPoint } from 'geojson'; import { expect, test } from 'vitest'; import { multiPoint } from 'geojson-to-gml-3'; test('multiPoint', () => { const geom: MultiPoint = { type: 'MultiPoint', coordinates: [ [100.0, 0.0], [101.0, 1.0], ], }; expect(multiPoint(geom)()).toBe('' + `<gml:MultiPoint>` + `<gml:pointMembers>` + `<gml:Point>` + `<gml:pos>` + `100 0` + `</gml:pos>` + `</gml:Point>` + `<gml:Point>` + `<gml:pos>` + `101 1` + `</gml:pos>` + `</gml:Point>` + `</gml:pointMembers>` + `</gml:MultiPoint>` ); }); ``` */ export const multiPoint: Converter<MultiPoint> = /* @__PURE__ */ withGmlNamespace<MultiPoint>(gmlMultiPoint); /*!! use-example file://./../tests/multiLineString.example.ts */ /** Converts an input geojson MultiLineString geometry to gml @function @param coords the coordinates member of the geojson geometry @param params @see Params @returns a string containing gml representing the input geometry @example ```ts import { MultiLineString } from 'geojson'; import { expect, test } from 'vitest'; import { multiLineString } from '../src'; test('multiLineString', () => { const geom: MultiLineString = { type: 'MultiLineString', coordinates: [ [ [100.0, 0.0], [101.0, 1.0], ], [ [102.0, 2.0], [103.0, 3.0], ], ], }; expect(multiLineString(geom)()).toBe('' + `<gml:MultiCurve>` + `<gml:curveMembers>` + `<gml:LineString>` + `<gml:posList>` + `100 0 101 1` + `</gml:posList>` + `</gml:LineString>` + `<gml:LineString>` + `<gml:posList>` + `102 2 103 3` + `</gml:posList>` + `</gml:LineString>` + `</gml:curveMembers>` + `</gml:MultiCurve>` ); }); ``` */ export const multiLineString: Converter<MultiLineString> = /* @__PURE__ */ withGmlNamespace<MultiLineString>(gmlMultiLineString); /*!! use-example file://./../tests/multiPolygon.example.ts */ /** Converts an input geojson `MultiPolygon` geometry to GML @function @param geom the {@link MultiPolygon} to convert to GML @param params @see Params @returns a string containing GML representing the input geometry @example ```ts import { type MultiPolygon } from 'geojson'; import { expect, test } from 'vitest'; import { multiPolygon } from 'geojson-to-gml-3'; import { point } from 'geojson-to-gml-3'; test('multiPolygon', () => { const geom: MultiPolygon = { type: 'MultiPolygon', coordinates: [ [ [ [102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0], ], ], [ [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0], ], [ [100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2], ], ], ], }; expect(multiPolygon(geom)()).toBe('' + `<gml:MultiSurface>` + `<gml:surfaceMembers>` + `<gml:Polygon>` + `<gml:exterior>` + `<gml:LinearRing>` + `<gml:posList>` + `102 2 103 2 103 3 102 3 102 2` + `</gml:posList>` + `</gml:LinearRing>` + `</gml:exterior>` + `</gml:Polygon>` + `<gml:Polygon>` + `<gml:exterior>` + `<gml:LinearRing>` + `<gml:posList>` + `100 0 101 0 101 1 100 1 100 0` + `</gml:posList>` + `</gml:LinearRing>` + `</gml:exterior>` + `<gml:interior>` + `<gml:LinearRing>` + `<gml:posList>` + `100.2 0.2 100.8 0.2 100.8 0.8 100.2 0.8 100.2 0.2` + `</gml:posList>` + `</gml:LinearRing>` + `</gml:interior>` + `</gml:Polygon>` + `</gml:surfaceMembers>` + `</gml:MultiSurface>` ); }); ``` */ export const multiPolygon = /* @__PURE__ */ withGmlNamespace<MultiPolygon>(gmlMultiPolygon); /** * Converts an any input geojson geometry into a GML string. * @function * @param geom the {@link Geometry} to convert to GML */ export const geometry: Converter<Geometry> = /* @__PURE__ */ withGmlNamespace<Geometry>(gmlGeometry); export default geometry; /*!! use-example file://./../tests/geometryCollection.example.ts */ /** Converts an input geojson GeometryCollection geometry to GML @function @param geom the {@link GeometryCollection} to convert to GML @param params @see Params @returns a string containing GML representing the input geometry\ @example ```ts import { type GeometryCollection } from 'geojson'; import { expect, test } from 'vitest'; import { geometryCollection } from 'geojson-to-gml-3'; test('geometryCollection', () => { const geom: GeometryCollection = { type: 'GeometryCollection', geometries: [ { type: 'Point', coordinates: [100.0, 0.0] }, { type: 'LineString', coordinates: [ [101.0, 0.0], [102.0, 1.0], ], }, ], }; expect(geometryCollection(geom)()).toBe('' + `<gml:MultiGeometry>` + `<gml:geometryMembers>` + `<gml:Point>` + `<gml:pos>` + `100 0` + `</gml:pos>` + `</gml:Point>` + `<gml:LineString>` + `<gml:posList>` + `101 0 102 1` + `</gml:posList>` + `</gml:LineString>` + `</gml:geometryMembers>` + `</gml:MultiGeometry>` ); }); ``` */ export const geometryCollection: Converter<GeometryCollection> = /* @__PURE__ */ withGmlNamespace<GeometryCollection>(gmlGeometryCollection);