Automatic Maps(3.0)
Automatic mapping is used when all the fields of the external format will be included in the internal format. This does not preclude explicit mapping of selected fields or types. Automatic mapping complies with the following steps for each field in the external format:
Evaluate if the
in_map
contains an explicit mapping for the external field. If so, use that explicit mapping.
If the preceding step fails, evaluate if the
internal
format (if specified) contains a field name that is identical to the external field name. If so, create with appropriate type conversions, a mapping between the two field names.
If the preceding step fails and the external field is not marked as
external_only
, create a new field (with the same field name and the appropriate type) in thetarget_internal
. Then create a mapping from the external field to this new internal field.
The type of the created internal field is controlled by the external field type.
External Type | Ultra Type mapped to |
---|---|
Primitive external | Maps to the corresponding primitive internal type. This depends on the external format specification. |
External format (sub-record) | Unless a |
List | Maps to an internal list type, where the list element type is deduced from the external list element type according to these rules (recursively). |
target_internal
When using automatic
, a new internal format may be automatically generated if any new internal fields are needed for the automatic mapping. The name of this new internal format is given by the target_internal
specification of an in_map
declaration. If no target_internal
name specification is given, the format will still be generated if needed, however without usable name (that is, the format cannot be directly referred to in APL).
If a target_internal
name has been given, this format will be created even if no new fields are created.
If the in_map
has a specified internal format, the generated format is a subtype of this format (hence, inherits all its fields).
Automatic Mapping Specifications
It is possible to modify the behavior of the automatic mapping algorithm when generating the sub-maps. The most direct way to do this is to specify how each external type will be mapped, either by explicitly specifying the sub-map or specifying the internal
and/or target_internal
name.
The syntax for the two forms of mapping specifications is declared as follows:
<external type>: <in_map (target_)internal options> ;
and
<external type>: using in_map <map name>;
Example - Automatic mapping specifications
internal IntBase { int recordSequenceNumber; }; asn_block { ExtDataFile ::= CHOICE( mc MobileCall, dp DataPacket) MobileCall ::= SET ( ... ) DataPacket ::= SET ( ... ) }; in_map InMapDataFile : external(ExtDataFile), target_internal(IntDataFile) { automatic; };
In this case two new internal types will automatically be generated for MobileCall
and DataPacket
. However, they must usually be given a name or in other cases inherit the fields of some declared base internal format. This can be accomplished by adding some automatic mapping specifications:
Example - Adding automatic mapping specifications
in_map InMapDataFile : external(ExtDataFile), target_internal(IntDataFile) { automatic { MobileCall: internal(BaseInt), target_internal(TIMobileCall); DataPacket: internal(BaseInt), target_internal(TIDataPacket); }; };
This could also be done by specifying a using in_map
declaration. For instance, the previous example is equivalent to the more complicated one:
Example - using in_map declaration
in_map MobileCallMap: internal(BaseInt), target_internal(TIMobileCall) { automatic; }; in_map DataPacketMap: internal(BaseInt), target_internal(TIDataPacket) { automatic; }; in_map InMapDataFile : external(ExtDataFile), target_internal(IntDataFile) { automatic { MobileCall: using in_map MobileCallMap; DataPacket: using in_map DataPacketMap; }; };
The type map specifications are inherited by every automatically generated sub-map:
Example - type map specifications inherited
asn_block { ... MobileCall ::= SET (location Location;) ... }; external Location { int longitude; int latitude; }; in_map InMapDataFile : external(ExtDataFile), target_internal(IntDataFile) { automatic { MobileCall: internal(BaseInt), target_internal(TIMobileCall); DataPacket: internal(BaseInt), target_internal(TIDataPacket); Location: internal(BaseInt), target_internal(TILocation); }; };
In this example, even though Location
is not a part of the direct mapping of ExtDataFile
itself, the type map information will still be considered when creating TIMobileCall
.
use_external_names Automatic Option
When declaring a target_internal
name for a large number of sub-formats the use_external_names
option on the automatic
block is a useful option. It will give all generated maps a target_internal
name identical to the name of the external format.
Example - use_external_names option on the automatic block
in_map AMARecord_Map : external(AMARecord), target_internal(AMARecord) { automatic { RecordOwnerType : target_internal(RecordOwnerType); RecordOwnerDN : target_internal(RecordOwnerDN); Package_100 : target_internal(Package_100); Package_101 : target_internal(Package_101); Package_102 : target_internal(Package_102); }; };
The use_external_names
specification will ease the syntax by removing the need of all the target_internal
specifications. The general syntax for a use_external_names
declaration is as follows:
use_external_names(<external 1>, <external 2>, ...)
The previous example includes all of the specified external definitions within the file. Hence, the in_map
could be rewritten as:
Example - in_map
in_map AMARecord_Map : external(AMARecord), target_internal(AMARecord) { automatic : use_external_names; };
It is possible to combine this with automatic mapping specifications. In this case the explicit specifications will override the use_external_names
behavior.
Automatic Block Internal Specification
It is also possible to append internal type specifications to the constructed in_maps
:
Example - Internal type specifications
in_map AMARecord_Map : external(AMARecord), target_internal(AMARecord) { automatic : use_external_names, internal(myInternal); };
If automatic mapping specifications are in use, these will override the internal specifications on the automatic
level (even if they only specify target_internal
).