[](https://rubygems.org/gems/aixm)
[](https://github.com/svoop/aixm/actions?workflow=Test)
[](https://codeclimate.com/github/svoop/aixm/)
[](https://donorbox.org/bitcetera)
# AIXM
Partial implementation of the [Aeronautical Information Exchange Model (AIXM 4.5)](http://aixm.aero) and it's dialect [Open FlightMaps eXchange format (OFMX 0)](https://gitlab.com/openflightmaps/ofmx/wikis) for Ruby.
For now, only the parts needed to automize the AIP import of [open flightmaps](https://openflightmaps.org) are part of this gem. Most notably, the gem is only a builder for snapshot files and does not parse them.
* [Homepage](https://github.com/svoop/aixm)
* [API](https://www.rubydoc.info/gems/aixm)
* Author: [Sven Schwyn - Bitcetera](http://www.bitcetera.com)
## Install
### Security
This gem is [cryptographically signed](https://guides.rubygems.org/security/#using-gems) 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/master/certs/svoop.pem)
```
### Bundler
Add the following to the Gemfile or gems.rb of your [Bundler](https://bundler.io) powered Ruby project:
```ruby
gem aixm
```
And then install the bundle:
```
bundle install --trust-policy MediumSecurity
```
### Standalone
If you're only going to use [the executables](#executables), make sure to have the [latest version of Ruby](https://www.ruby-lang.org/en/documentation/installation/) 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:
```ruby
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:
```ruby
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`:
```ruby
AIXM.config.schema = :ofmx # =>:ofmx
```
There are shortcuts to set and get the schema:
```ruby
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](https://gitlab.com/openflightmaps/ofmx/wikis/Features#core-features). You can do so on individual features, however, you might want to configure a default region to simplify your life:
```ruby
AIXM.ofmx!
AIXM.region = 'LF'
```
:warning: This setting has no effect when using the `:aixm` schema.
### AIXM.config.mid
In order to insert [OFMX-compliant `mid` attributes](https://gitlab.com/openflightmaps/ofmx/wikis/Features#mid) into all `*Uid` elements, you have set the mid configuration option to `true`.
```ruby
AIXM.ofmx!
AIXM.config.mid # => false - don't insert mid attributes by default
AIXM.config.mid = true # => true - insert mid attributes
```
:warning: 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.
```ruby
AIXM.config.ignored_errors = /invalid date/i
```
## Models
### Fundamentals
* [Document](https://www.rubydoc.info/gems/aixm/AIXM/Document.html)
* [XY (longitude and latitude)](https://www.rubydoc.info/gems/aixm/AIXM/XY.html)
* [Z (height, elevation or altitude)](https://www.rubydoc.info/gems/aixm/AIXM/Z.html)
* [D (distance or length)](https://www.rubydoc.info/gems/aixm/AIXM/D.html)
* [F (frequency)](https://www.rubydoc.info/gems/aixm/AIXM/F.html)
* [A (angle)](https://www.rubydoc.info/gems/aixm/AIXM/A.html)
### Features
* [Address](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Address.html)
* [Organisation](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Organisation.html)
* [Unit](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Unit.html)
* [Service](https://www.rubydoc.info/gems/aixm/AIXM/Component/Service.html)
* [Airport](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Airport.html)
* [Airspace](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Airspace.html)
* [Navigational aid](https://www.rubydoc.info/gems/aixm/AIXM/NavigationalAid.html)
* [Designated point](https://www.rubydoc.info/gems/aixm/AIXM/Feature/DesignatedPoint.html)
* [DME](https://www.rubydoc.info/gems/aixm/AIXM/Feature/DME.html)
* [Marker](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Marker.html)
* [NDB](https://www.rubydoc.info/gems/aixm/AIXM/Feature/NDB.html)
* [TACAN](https://www.rubydoc.info/gems/aixm/AIXM/Feature/TACAN.html)
* [VOR](https://www.rubydoc.info/gems/aixm/AIXM/Feature/VOR.html)
* [Obstacle and obstacle group](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Obstacle.html)
### Components
* [Frequency](https://www.rubydoc.info/gems/aixm/AIXM/Component/Frequency.html)
* [Geometry](https://www.rubydoc.info/gems/aixm/AIXM/Component/Geometry.html)
* [Point](https://www.rubydoc.info/gems/aixm/AIXM/Component/Point.html)
* [Arc](https://www.rubydoc.info/gems/aixm/AIXM/Component/Arc.html)
* [Border](https://www.rubydoc.info/gems/aixm/AIXM/Component/Border.html)
* [Circle](https://www.rubydoc.info/gems/aixm/AIXM/Component/Circle.html)
* [Runway](https://www.rubydoc.info/gems/aixm/AIXM/Component/Runway.html)
* [Helipad](https://www.rubydoc.info/gems/aixm/AIXM/Component/Helipad.html)
* [FATO](https://www.rubydoc.info/gems/aixm/AIXM/Component/FATO.html)
* [Surface](https://www.rubydoc.info/gems/aixm/AIXM/Component/Surface.html)
* [Layer](https://www.rubydoc.info/gems/aixm/AIXM/Component/Layer.html)
* [Vertical limit](https://www.rubydoc.info/gems/aixm/AIXM/Component/VerticalLimit.html)
* [Timetable](https://www.rubydoc.info/gems/aixm/AIXM/Component/Timetable.html)
## Associations
The different models are interwoven with [`has_many` and `has_one` associations](https://www.rubydoc.info/gems/aixm/AIXM/Association).
Please note that `has_many` associations are instances `AIXM::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:
```ruby
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:
```ruby
document.features.find_by(:airport) # => [#, #]
document.features.find_by(:airport, id: 'LFNT') # => [#]
```
To search a `has_many` association for equal objects, use `find`:
```ruby
document.features.find(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!
### duplicates
Equally on `has_many` associations, use `duplicates` to find identical or equal associations:
```ruby
document.features.duplicates # => [#, #, ...]
```
## Payload Hash
OFMX defines a [payload hash function](https://gitlab.com/openflightmaps/ofmx/wikis/Functions) used to facilitate association and modification tracking. It is used internally, but you can also use it in your own code:
```ruby
# Payload hash of XML fragment string
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](https://www.rubydoc.info/gems/aixm/AIXM/Refinements.html).
## Executables
### mkmid
The `mkmid` executable reads an OFMX file, adds [OFMX-compliant `mid` values](https://gitlab.com/openflightmaps/ofmx/wikis/Features#mid) into all `*Uid` elements and validates the result against the schema.
```
mkmid --help
```
### ckmid
The `chmid` executable reads an OFMX file, validates it against the schema and checks all `mid` attributes for [OFMX-compliance](https://gitlab.com/openflightmaps/ofmx/wikis/Features#mid).
```
ckmid --help
```
## References
### AIXM
* [AIXM](http://aixm.aero)
* [AICM 4.5 documentation](https://openflightmaps.gitlab.io/ofmx/aixm/4.5/manual/aicm/)
* [AIXM 4.5 specification](http://aixm.aero/document/aixm-45-specification)
### OFMX
* [OFMX](https://gitlab.com/openflightmaps/ofmx)
* [OFMX documentation](https://gitlab.com/openflightmaps/ofmx/wikis)
* [open flightmaps](https://openflightmaps.org)
## 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
```
Please submit issues on:
https://github.com/svoop/aixm/issues
To contribute code, fork the project on Github, add your code and submit a pull request:
https://help.github.com/articles/fork-a-repo
## License
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).