AIXM
Partial implementation of the Aeronautical Information Exchange Model (AIXM 4.5) and it's dialect Open FlightMaps eXchange format (OFMX 0) for Ruby.
For now, only the parts needed to automize the AIP import of open flightmaps are part of this gem. Most notably, the gem is only a builder for snapshot files and does not parse them.
- Homepage
- API
- Author: Sven Schwyn - Bitcetera
Thank you for supporting free and open-source software by sponsoring on GitHub or on Donorbox. Any gesture is appreciated, from a single Euro for a ☕️ cup of coffee to 🍹 early retirement.
Install
Security
This gem is cryptographically signed in order to assure it hasn't been tampered with. Unless already done, please add the author's public key as a trusted certificate now:
gem cert --add <(curl -Ls https://raw.github.com/svoop/aixm/main/certs/svoop.pem)
Bundler
Add the following to the Gemfile or gems.rb of your Bundler powered Ruby project:
gem 'aixm'
And then install the bundle:
bundle install --trust-policy MediumSecurity
Standalone
If you're only going to use the executables, make sure to have the latest version of Ruby and then install this gem:
gem install aixm --trust-policy MediumSecurity
Usage
Here's how to build a document object, populate it with a simple feature and then render it as AIXM or OFMX:
document = AIXM.document(
region: 'LF'
)
document.add_feature(
AIXM.designated_point(
id: "ABIXI",
xy: AIXM.xy(lat: %q(46°31'54.3"N), long: %q(002°19'55.2"W)),
type: :icao
)
)
AIXM.ofmx!
document.to_xml
You can initialize all elements either traditionally or by use of the corresponding shorthand AIXM class method. The following two statements are identical:
AIXM::Feature::NavigationalAid::DesignatedPoint.new(...)
AIXM.designated_point(...)
See AIXM::CLASSES
for the complete list of shorthand names.
Configuration
AIXM.config.schema
The schema is either :aixm
(default) or :ofmx
:
AIXM.config.schema = :ofmx # =>:ofmx
There are shortcuts to set and get the schema:
AIXM.schema # => :aixm
AIXM.aixm? # => true
AIXM.ofmx! # => :ofmx
AIXM.ofmx? # => true
AIXM.schema # => :ofmx
AIXM.schema(:version) # => 0
AIXM.config.region
The :ofmx
schema requires the region to be set on all core features. You can do so on individual features, however, you might want to configure a default region to simplify your life:
AIXM.ofmx!
AIXM.config.region = 'LF'
⚠️ This setting has no effect when using the :aixm
schema.
AIXM.voice_channel_separation
Define which voice channel separation should be used to validate voice communication frequencies.
AIXM.voice_channel_separation = :any # both 25 and 8.33 kHz (default)
AIXM.voice_channel_separation = 25 # 25 kHz only
AIXM.voice_channel_separation = 833 # 8.33 kHz only
AIXM.config.mid
In order to insert OFMX-compliant mid
attributes into all *Uid
elements, you have set the mid configuration option to true
.
AIXM.ofmx!
AIXM.config.mid = false # don't insert mid attributes (default)
AIXM.config.mid = true # insert mid attributes
⚠️ This setting has no effect when using the :aixm
schema.
AIXM.config.ignored_errors
In case you want to ignore certain XML schema validation errors, set this configuration option to a regular expression which matches the error messages to ignore. By default, no errors are ignored.
AIXM.config.ignored_errors = /invalid date/i
Models
Fundamentals
- Document
- A (angle)
- D (dimension, distance or length)
- F (frequency)
- P (pressure)
- R (rectangle)
- XY (longitude and latitude)
- Z (height, elevation or altitude)
Features
Components
- ApproachLighting
- FATO
- Frequency
- Geometry
- Helipad
- Layer
- Lighting
- Runway
- Service
- Surface
- Timetable
- Timesheet
- VASIS
- Vertical limit
Schedule
Associations
The different models are interwoven with has_many
and has_one
associations.
Please note that has_many
associations are instances AIXM::Concerns::Association::Array
which mostly behave like normal arrays. However, you must not add or remove elements on the array directly but use the corresponding method on the associating model instead:
document.features << airport # => NoMethodError
document.add_feature airport # okay
find_by and find
Use find_by
on has_many
to filter associations by class and optional attribute values:
document.features.find_by(:airport) # => [#<AIXM::Feature::Airport>, #<AIXM::Feature::Airport>]
document.features.find_by(:airport, id: 'LFNT') # => [#<AIXM::Feature::Airport>]
To search a has_many
association for equal objects, use find
:
document.features.find(airport) # => [#<AIXM::Feature::Airport>]
This may seem redundant at first, but keep in mind that two instances of +AIXM::CLASSES+ which implement #to_uid
are considered equal if they are instances of the same class and both their UIDs as calculated by #to_uid
are equal. Attributes which are not part of the #to_uid
calculation are irrelevant!
meta
You can write arbitrary meta information to any feature or component. It won't be used when building the AIXM or OFMX document, in fact, it is not used by this gem at all. But you can store e.g. foreign keys and then later use them to find a feature or component like so:
document.features.find_by(:airport, meta: 1234) # 1234 is the foreign key
duplicates
Equally on has_many
associations, use duplicates
to find identical or equal associations:
document.features.duplicates # => [#<AIXM::Feature::Unit>, #<AIXM::Component::Service>, ...]
XML Comments
All features implement the comment
attribute which accepts any object and converts it #to_s
. When set, an XML comment is inserted right after the opening tag of the feature. This comes in handy e.g. in case you want to include source data facsimile such as NOTAM. Oneline and multiline comments are inserted differently:
<Ase>
<!--
B0330/22 NOTAMR B1756/21
Q) LSAS/QAFLT/V/NBO/E/000/050/4734N00841E005
A) LSAS B) 2203170746 C) 2206242359 EST
-->
<AseUid>
<codeType>RAS</codeType>
<codeId>B0330/22</codeId>
</AseUid>
(...)
</Ase>
<Org>
<!-- Generic organisation -->
<OrgUid>
<txtName>FRANCE</txtName>
</OrgUid>
(...)
</Org>
Payload Hash
OFMX defines a payload hash function used to facilitate association and modification tracking. It is used internally, but you can also use it in your own code:
# Payload hash of XML fragment string
xml = '<xml><a></a></xml>'
AIXM::PayloadHash.new(xml).to_uuid
# Payload hash of Nokogiri XML fragment
document = File.open("file.xml") { Nokogiri::XML(_1) }
AIXM::PayloadHash.new(document).to_uuid
Validation
AIXM::Document#valid?
validates the resulting AIXM or OFMX against its XML schema. If any, you find the errors in AIXM::Document#errors
.
Refinements
By using AIXM::Refinements
you get a few handy extensions to Ruby core classes.
Executables
mkmid
The mkmid
executable reads OFMX files, adds OFMX-compliant mid
values into all *Uid
elements and validates the result against the schema.
mkmid --help
ckmid
The chmid
executable reads OFMX files, validates them against the schema and checks all mid
attributes for OFMX-compliance.
ckmid --help
References
AIXM
OFMX
Tests
Some tests are very time consuming and therefore skipped by default. To run the full test suite, set the environment variable:
export SPEC_SCOPE=all
Development
To install the development dependencies and then run the test suite:
bundle install
bundle exec rake # run tests once
bundle exec guard # run tests whenever files are modified
You're welcome to submit issues and contribute code by forking the project and submitting pull requests.
License
The gem is available as open source under the terms of the MIT License.