An open-source SkyAlgorithm project.
Minimal OFMX → PostGIS importer for OpenFlightMaps snapshots.
Lightweight importer for OpenFlightMaps OFMX data into PostgreSQL/PostGIS. The goal is a small, auditable pipeline that parses OFMX XML, normalizes geometries, and loads core aviation features into a spatial schema.
Importer and schema are functional for LKAA and ED snapshots. Data is fetched on demand and CI validates parser behavior and the Docker import path.
- Keep the pipeline small and auditable.
- Favor explicit schemas over implicit inference.
- Make data fetching and imports reproducible.
pip install -e .installs the package and thepsycopgdependency.config/ofmx2pgsql.example.inishows the supported config keys.Dockerfilebuilds a container that downloads a snapshot and imports it into PostGIS.scripts/fetch_ofmx.shdownloads and extracts a snapshot locally for CLI testing.
src/ofmx2pgsql/application package (CLI, parsing, DB loaders).sql/migrations/PostGIS schema migrations.config/example configuration files.tests/minimal unit tests for parser and CLI.scripts/helper scripts for fetching data and container workflows.
- Streaming XML parsing for OFMX datasets (Ahp, Rwy, Rdn, Ase, Dpn, Ndb/Vor/Dme).
- ARINC 424 parsing for airports, runways, runway ends, airspaces, navaids, and waypoints.
- Airspace shapes parsed from OFM shape extension XML.
- ARINC airspace imports load metadata only (no polygon geometry).
- OpenAIR parsing for ARINC airspace polygons when supplied via
--openair. - PostGIS schema and import pipeline for airports, runways, runway ends, airspaces, navaids, and waypoints.
- CLI for scan/import/validate, with dry-run, verbose summaries, and JSON output.
python -m unittest discover -s testsruns the minimal CLI smoke tests intests/.python -m ofmx2pgsql --helpverifies the CLI entry point is wired.scripts/fetch_ofmx.shdownloads and extracts the LK snapshot intodata/.python -m ofmx2pgsql scan data/ofmx_lk/isolatedlists.ofmxfiles.python -m ofmx2pgsql scan data/ofmx_lk/isolated --schema ofmxprints a schema label before the list.python -m ofmx2pgsql import --dsn \"postgresql://...\" --schema ofmx --ofmx data/ofmx_lk/isolated/ofmx_lk.ofmx --shapes data/ofmx_lk/isolated/ofmx_lk_ofmShapeExtension.xml --apply-migrations --verboseloads the sample dataset.python -m ofmx2pgsql import --dsn \"postgresql://...\" --ofmx data/ofmx_lk/isolated/ofmx_lk.ofmx --shapes data/ofmx_lk/isolated/ofmx_lk_ofmShapeExtension.xml --dry-run --verboseparses without writing to the database.python -m ofmx2pgsql validate --dsn \"postgresql://...\" --schema ofmx --ofmx data/ofmx_lk/isolated/ofmx_lk.ofmx --shapes data/ofmx_lk/isolated/ofmx_lk_ofmShapeExtension.xmlcompares parsed counts with stored counts.python -m ofmx2pgsql validate --dsn \"postgresql://...\" --ofmx data/ofmx_lk/isolated/ofmx_lk.ofmx --output-jsonemits validation output as JSON.python -m ofmx2pgsql import --config config/ofmx2pgsql.example.ini --dry-run --verboseuses config values with CLI overrides.python -m ofmx2pgsql validate --config config/ofmx2pgsql.example.ini --output-jsonuses config defaults with JSON output.
Build the image and run it with database credentials. The container downloads the snapshot URL and imports it.
docker build -t ofmx2pgsql .
docker run --rm \
-e PG_DSN="postgresql://user:pass@host:5432/db" \
-e OFMX_URL="https://snapshots.openflightmaps.org/live/2513/ofmx/lkaa/latest/ofmx_lk.zip" \
-e PG_SCHEMA="ofmx" \
-e APPLY_MIGRATIONS="true" \
ofmx2pgsqlThe LK sample data is fetched on demand into data/ofmx_lk/ via scripts/fetch_ofmx.sh and is ignored by git.
Airspace records in the LK sample reuse AseUid/@mid, so ofmx.airspaces.ofmx_id is not unique. The schema uses a composite uniqueness constraint on (ofmx_id, region, code_id, code_type, name) to preserve distinct entries while keeping imports idempotent.
OpenFlightMaps does not publish OFMX for Switzerland (LS). Use ARINC 424 plus OpenAIR shapes for this region.
ARINC + OpenAIR (Switzerland) import with the Docker image:
docker run --rm \
-e PG_DSN="postgresql://user:pass@host:5432/db" \
-e ARINC_URL="https://snapshots.openflightmaps.org/live/2601/arinc424/lsas/latest/arinc_ls.zip" \
-e OPENAIR_URL="https://snapshots.openflightmaps.org/live/2601/openair/lsas/latest/openair_ls.zip" \
-e PG_SCHEMA="ofmx" \
-e APPLY_MIGRATIONS="true" \
ofmx2pgsqlARINC command-line examples:
python -m ofmx2pgsql import --dsn \"postgresql://...\" --arinc data/arinc_ls/isolated/arinc_ls.pc --apply-migrations --verboseimports ARINC 424 data into the same tables.python -m ofmx2pgsql import --dsn \"postgresql://...\" --arinc /path/to/arinc_ls.zip --dry-run --verboseparses a ZIP-contained ARINC dataset without writing to the database.python -m ofmx2pgsql import --dsn \"postgresql://...\" --arinc /path/to/arinc_ls.zip --openair /path/to/openair_ls.zip --apply-migrations --verboseenriches ARINC airspaces with OpenAIR polygons.python -m ofmx2pgsql validate --dsn \"postgresql://...\" --arinc /path/to/arinc_ls.zip --filter-source arinc --filter-cycle 2601 --output-jsonvalidates only rows imported from ARINC cycle 2601.
Validation compares parsed counts to database row counts in the selected schema. If you import multiple regions into the same schema, raw totals won't match a single file. For ARINC imports we tag rows with:
source='arinc'cycle='2601'(or whatever cycle is in the ARINC file)
Use those tags to validate only the rows from a specific import:
python -m ofmx2pgsql validate \
--dsn "postgresql://..." \
--arinc /path/to/arinc_ls.zip \
--filter-source arinc \
--filter-cycle 2601 \
--output-jsonSee CONTRIBUTING.md for workflow and style notes used by maintainers.
See SECURITY.md for reporting guidance.
- Expand parser coverage for additional OFMX features (procedures, routes, obstacles).
- Add integration tests that validate full imports against a disposable PostGIS instance.
MIT. See LICENSE.
OFMX data is sourced from OpenFlightMaps snapshots. Review their terms and attribution requirements before redistribution.