@npm9912/s-gml
Version:
TypeScript library for parsing, converting, and validating GML 2.1.2/3.0/3.2
364 lines (300 loc) • 11.6 kB
Markdown
# @npm9912/s-gml
[](https://badge.fury.io/js/@npm9912/s-gml)
[](https://opensource.org/licenses/MIT)
[](https://www.typescriptlang.org/)
**TypeScript-Bibliothek zum Parsen, Konvertieren und Validieren von GML 2.1.2/3.0/3.2** –
inkl. **Envelope, Box, Curve, Surface, LinearRing**, WFS-Unterstützung und Docker-CLI.
---
## ✨ Features
| Feature | Beschreibung |
| -------------------------- | ----------------------------------------------------- |
| **GML → GeoJSON** | Parsen aller GML-Elemente nach GeoJSON |
| **Versionen konvertieren** | GML 2.1.2 ↔ 3.2 (inkl. FeatureCollections) |
| **WFS-Unterstützung** | Parsen von WFS-FeatureCollections |
| **URL-Unterstützung** | Direktes Laden von GML-Daten aus URLs |
| **OWS Exception Handling** | Automatische Erkennung und Behandlung von WFS-Fehlern |
| **XSD-Validierung** | Prüfung gegen offizielle GML-Schemata |
| **Neue GML-Elemente** | `Envelope`, `Box`, `Curve`, `Surface`, `LinearRing` |
| **Docker-CLI** | Bereit als Container-Image für Batch-Verarbeitung |
---
## 📦 Installation
```bash
pnpm install @npm9912/s-gml
```
---
## 🚀 Usage
### GML → GeoJSON parsen
```typescript
import { GmlParser } from '@npm9912/s-gml';
const parser = new GmlParser();
const geojson = await parser.parse(`
<gml\:Point xmlns\:gml="http://www.opengis.net/gml/3.2" srsName="EPSG:4326">
<gml\:pos>10.0 20.0</gml\:pos>
</gml\:Point>
`);
console.log(geojson);
// { type: 'Point', coordinates: [10, 20] }
```
### GML von URL parsen
```typescript
const parser = new GmlParser();
// WFS GetFeature Request
const geojson = await parser.parseFromUrl(
'https://example.com/wfs?service=WFS&request=GetFeature&typeName=water_areas'
);
console.log(geojson.type); // 'FeatureCollection'
```
### GML Envelope parsen
```typescript
const envelope = await parser.parse(`
<gml\:Envelope xmlns\:gml="http://www.opengis.net/gml/3.2" srsName="EPSG:4326">
<gml\:lowerCorner>10.0 20.0</gml\:lowerCorner>
<gml\:upperCorner>30.0 40.0</gml\:upperCorner>
</gml\:Envelope>
`);
console.log(envelope.bbox);
// [10, 20, 30, 40]
```
### GML Curve parsen
```typescript
const curve = await parser.parse(`
<gml\:Curve xmlns\:gml="http://www.opengis.net/gml/3.2">
<gml\:segments>
<gml\:LineStringSegment>
<gml\:posList>10.0 20.0 15.0 25.0 20.0 30.0</gml\:posList>
</gml\:LineStringSegment>
</gml\:segments>
</gml\:Curve>
`);
console.log(curve);
// { type: 'LineString', coordinates: [[10, 20], [15, 25], [20, 30]] }
```
### GML Surface parsen
```typescript
const surface = await parser.parse(`
<gml\:Surface xmlns\:gml="http://www.opengis.net/gml/3.2">
<gml\:patches>
<gml\:PolygonPatch>
<gml\:exterior>
<gml\:LinearRing>
<gml\:posList>0 0 10 0 10 10 0 10 0 0</gml\:posList>
</gml\:LinearRing>
</gml\:exterior>
</gml\:PolygonPatch>
</gml\:patches>
</gml\:Surface>
`);
console.log(surface.type);
// "MultiPolygon"
```
### GML Versionen konvertieren
```typescript
const parser = new GmlParser();
// Lokale Konvertierung
const gml32 = `<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2"><gml:pos>10 20</gml:pos></gml:Point>`;
const gml212 = await parser.convert(gml32, { outputVersion: '2.1.2', prettyPrint: true });
console.log(gml212);
// <gml:Point xmlns:gml="http://www.opengis.net/gml"><gml:coordinates>10,20</gml:coordinates></gml:Point>
// Von URL konvertieren
const converted = await parser.convertFromUrl('https://example.com/data.gml', {
outputVersion: '2.1.2',
prettyPrint: true
});
```
### OWS Exception Reports behandeln
```typescript
import { GmlParser, OwsExceptionError } from '@npm9912/s-gml';
const parser = new GmlParser();
try {
const geojson = await parser.parse(wfsResponse);
console.log(geojson);
} catch (error) {
if (error instanceof OwsExceptionError) {
console.error('WFS Error:', error.message);
// OWS Exception [InvalidParameterValue]: Failed to find response for output format GML23
console.error('All errors:', error.getAllMessages());
// Zeigt alle Exceptions mit Details an
console.log('Exception Report:', error.report);
// Zugriff auf das vollständige Report-Objekt
}
}
```
---
## 📖 Unterstützte GML-Elemente
| Element | GML 2.1.2 | GML 3.0/3.2 | GeoJSON-Ausgabe | Beschreibung |
| ------------------- | --------- | ----------- | ------------------- | ---------------------- |
| `Point` | ✅ | ✅ | `Point` | Einzelner Punkt |
| `LineString` | ✅ | ✅ | `LineString` | Linie mit Punkten |
| `Polygon` | ✅ | ✅ | `Polygon` | Geschlossene Fläche |
| `LinearRing` | ✅ | ✅ | `LineString` | Geschlossener Ring |
| `Envelope` | ✅ | ✅ | `Feature` + `bbox` | Begrenzungsbox |
| `Box` | ✅ | ✅ | `Feature` + `bbox` | 2D/3D-Box |
| `Curve` | ❌ | ✅ | `LineString` | Kurve mit Segmenten |
| `Surface` | ❌ | ✅ | `MultiPolygon` | 3D-Oberfläche |
| `MultiSurface` | ❌ | ✅ | `MultiPolygon` | Sammlung von Flächen |
| `MultiPoint` | ✅ | ✅ | `MultiPoint` | Sammlung von Punkten |
| `MultiLineString` | ✅ | ✅ | `MultiLineString` | Sammlung von Linien |
| `MultiPolygon` | ✅ | ✅ | `MultiPolygon` | Sammlung von Polygonen |
| `FeatureCollection` | ✅ | ✅ | `FeatureCollection` | Sammlung von Features |
---
## 🛠 CLI-Tool (Docker)
### Docker-Image bauen
```bash
docker build -t s-gml-cli .
```
### GML → GeoJSON konvertieren
**Lokale Datei:**
```bash
docker run --rm -v $(pwd)/test/gml:/data s-gml-cli parse /data/wfs-gml3-1-f.xml --verbose --output /data/output.geojson
```
**Von URL:**
```bash
docker run --rm s-gml-cli parse https://example.com/data.gml --output /data/output.geojson
```
### GML-Versionen konvertieren (3.2 → 2.1.2)
**Lokale Datei:**
```bash
docker run --rm -v $(pwd):/data s-gml-cli convert /data/input.gml \
--version 2.1.2 --pretty > output.gml
```
**Von URL:**
```bash
docker run --rm s-gml-cli convert https://example.com/data.gml \
--version 2.1.2 --pretty > output.gml
```
### GML validieren
**Lokale Datei:**
```bash
docker run --rm -v $(pwd):/data s-gml-cli validate /data/input.gml --gml-version 3.2
```
**Von URL:**
```bash
docker run --rm s-gml-cli validate https://example.com/data.gml --gml-version 3.2
```
---
## 📖 API
### `GmlParser`
| Methode | Beschreibung | Rückgabe |
| -------------------------------------- | --------------------------------------- | ----------------------- |
| `parse(gml: string)` | Parsed GML zu GeoJSON/FeatureCollection | `Promise<GeoJSON>` |
| `parseFromUrl(url: string)` | Lädt und parsed GML von URL | `Promise<GeoJSON>` |
| `convert(gml: string, options)` | Konvertiert GML zwischen Versionen | `Promise<string>` (XML) |
| `convertFromUrl(url: string, options)` | Lädt und konvertiert GML von URL | `Promise<string>` (XML) |
| `convertGeometry(gmlObject, options)` | Konvertiert GML-Objekte zu XML | `Promise<string>` |
**`GmlConvertOptions`**:
```typescript
{
outputVersion: '2.1.2' | '3.2', // Zielversion
prettyPrint?: boolean, // Formatiertes XML
inputVersion?: '2.1.2' | '3.0' | '3.2' // Manuelle Versionsangabe
}
```
### Custom Builder erstellen
Du kannst eigene Builder implementieren, um GML in andere Formate als GeoJSON zu konvertieren:
```typescript
import { Builder, GmlPoint, GmlLineString, GmlPolygon, GmlFeature, GmlFeatureCollection } from '@npm9912/s-gml';
class MyCustomBuilder implements Builder {
buildPoint(gml: GmlPoint) {
return {
type: 'CustomPoint',
x: gml.coordinates[0],
y: gml.coordinates[1]
};
}
buildLineString(gml: GmlLineString) {
return {
type: 'CustomLineString',
points: gml.coordinates
};
}
buildPolygon(gml: GmlPolygon) {
return {
type: 'CustomPolygon',
rings: gml.coordinates
};
}
// ... alle anderen Builder-Methoden implementieren
// (siehe Builder Interface in types.ts)
}
// Builder direkt im Constructor übergeben
const parser = new GmlParser(new MyCustomBuilder());
const result = await parser.parse(gmlXml);
// Gibt jetzt dein Custom Format zurück
```
**Builder Interface:**
```typescript
interface Builder<TGeometry, TFeature, TFeatureCollection> {
buildPoint(gml: GmlPoint): TGeometry;
buildLineString(gml: GmlLineString): TGeometry;
buildPolygon(gml: GmlPolygon): TGeometry;
buildMultiPoint(gml: GmlMultiPoint): TGeometry;
buildMultiLineString(gml: GmlMultiLineString): TGeometry;
buildMultiPolygon(gml: GmlMultiPolygon): TGeometry;
buildLinearRing(gml: GmlLinearRing): TGeometry;
buildEnvelope(gml: GmlEnvelope): TFeature;
buildBox(gml: GmlBox): TFeature;
buildCurve(gml: GmlCurve): TGeometry;
buildSurface(gml: GmlSurface): TGeometry;
buildFeature(gml: GmlFeature): TFeature;
buildFeatureCollection(gml: GmlFeatureCollection): TFeatureCollection;
}
```
### `validateGml(gml: string, version: string)`
→ `Promise<boolean>`
### OWS Exception Handling
**`OwsExceptionError`** - Wird geworfen, wenn ein WFS-Server einen Exception Report zurückgibt:
```typescript
class OwsExceptionError extends Error {
report: OwsExceptionReport; // Vollständiger Report
getAllMessages(): string; // Alle Fehlermeldungen formatiert
}
```
**Hilfsfunktionen**:
- `isOwsExceptionReport(xml: string): boolean` - Prüft, ob XML ein Exception Report ist
- `parseOwsExceptionReport(xml: string): OwsExceptionReport` - Parst Exception Report manuell
---
## 🛠 Entwicklung
### Vorraussetzungen
- Node.js ≥ 16
- TypeScript ≥ 5.0
- Docker (für CLI-Tool)
### Build & Test
```bash
git clone https://github.com/pt9912/s-gml
cd s-gml
pnpm install
pnpm run build
pnpm test
# optional: Coverage-Report
pnpm run test:coverage
```
### Docker-CLI lokal testen
```bash
# Image bauen
docker build -t s-gml-cli .
# Testen mit Beispieldatei
echo '<gml\:Point xmlns\:gml="http://www.opengis.net/gml/3.2"><gml\:pos>10 20</gml\:pos></gml\:Point>' > test.gml
docker run --rm -v \$(pwd):/data s-gml-cli parse /data/test.gml
```
---
## 📂 Beispiel-GML-Dateien
### `envelope.gml`
```xml
<gml\:Envelope xmlns\:gml="http://www.opengis.net/gml/3.2" srsName="EPSG:4326">
<gml\:lowerCorner>10.0 20.0</gml\:lowerCorner>
<gml\:upperCorner>30.0 40.0</gml\:upperCorner>
</gml\:Envelope>
```
### `curve.gml`
```xml
<gml\:Curve xmlns\:gml="http://www.opengis.net/gml/3.2">
<gml\:segments>
<gml\:LineStringSegment>
<gml\:posList>10.0 20.0 15.0 25.0 20.0 30.0</gml\:posList>
</gml\:LineStringSegment>
</gml\:segments>
</gml\:Curve>
```
---
## 📄 Lizenz
[MIT](LICENSE) © Dietmar Burkard