...
Headers and Trailers (which are included in the
external
code block)external
internal
in_map
decoder
out_map
encoder
external
Both headers and trailers as well as record types should be included in the external
code block.
Headers and Trailers
Since headers and trailers are treated as records, the same syntax as for external records apply. APL syntax can also be used within UFDL code.
Code Block |
---|
external FileHeader { ascii header : terminated_by(0xA); }; |
...
The identified_by
for the trailer is not crucial, however, it provides additional validation during decoding, since it evaluates that the trailer really starts with "Date".
Record Types
The definitions of TypeA and TypeB are fairly straight forward. No encode_value
for RecordType is set, since this is evaluated from the internal UDR during encoding (see the section below, internal).
Code Block |
---|
external TypeA : identified_by( RecordType == "A" ), terminated_by(0xA) { ascii RecordType : static_size(2), terminated_by(":"); ascii A_number : terminated_by(":"); ascii B_number : terminated_by(":"); ascii SequenceNumber : terminated_by(":"); ascii Duration : terminated_by(0xA); }; external TypeB : identified_by( RecordType == "B" ), terminated_by(0xA) { ascii RecordType : static_size(2), terminated_by(","); ascii CallingCountry : terminated_by(","); ascii SequenceNumber : terminated_by(","); ascii LocalAreaCode : terminated_by(","); ascii A_number : terminated_by(","); ascii B_number : terminated_by(","); ascii CauseForOutput : terminated_by(","); ascii CalledCountry : terminated_by(0xA); }; |
internal
Anchor | ||||
---|---|---|---|---|
|
Suppose it is desired to output one record type as a replacement for the incoming types A and B the simplest way is to create a mutual internal.
...
Both TypeA and TypeB records are mapped to MyInternal. The common fields will always be set. The others are defined as optional, hence, their presence depends on the record type. The RecordType in the internal type is required for encoding, since the encoder needs to evaluate the record type to decide whether to encode as TypeA or TypeB.
in_map
Both record types A and B are mapped to the same internal. This approach is useful to simplify APL syntax within processing (a lot of if-statements used to determine the record type, can be eliminated), or in case one resulting output type is produced.
...
Code Block |
---|
in_map Header_in : external( FileHeader ), target_internal( Header ), discard_output { automatic; }; // The trailer gets a special record type. in_map Trailer_in : external( FileTrailer ), target_internal( Trailer ) { automatic; }; |
decoder
The following constructed decoder definition will expect all batches to start with a header, end with a trailer and have zero/one/several A and B records in between. If not, the decoder will abort.
Code Block |
---|
// The sub-decoders. decoder Records : in_map( TypeA_in ), in_map( TypeB_in ); decoder Header : in_map( Header_in ); decoder Trailer : in_map( Trailer_in ); // The total (file) decoder. // '*' means zero/one/several records are expected between // one header and one trailer for each file collected. decoder Total { decoder Header; decoder Records *; decoder Trailer; }; |
out_map
Suppose you are required to encode back to the original format.
...
Note | ||
---|---|---|
| ||
TypeA and TypeB both are encoded from MyInternal. Which type to use depends on the value of the RecordType field. |
encoder
A constructed encoder cannot be created. Hence, the following encoder definition will not care for the order of arriving records, nor that all types must be present in the output file.
Code Block |
---|
encoder Total: out_map( TypeA_out ), out_map( TypeB_out ), out_map( Header_out ), out_map( Trailer_out ); |
Scroll pagebreak |
---|