POSIMAP is a blend of "POSItional MAPper".
This tool can transform fixed-width positional files into JSON and convert them back.
- Parse fixed-width text files based on a declarative positional schema.
- Convert structured data back into fixed-width text files.
- Easy configuration via YAML.
- Minimal dependencies, fast and lightweight.
- Supports validation and field trimming (optional).
- Supports text encoding conversion (EBCDIC, Unicode, ...).
- Supports OCCURS and REDEFINES in schema definition.
- Supports packed decimal encoding (COMP-3).
Fixed-width files are still widely used in legacy systems, financial data exchanges, and large-scale batch processing. POSIMAP helps bridge the gap between fixed-width formats and structured modern data workflows.
JOHN DOE 1234 ELM STREET SPRINGFIELD, IL 62704
JANE SMITH 56 MAPLE AVENUE RIVERSIDE, CA 92501
This file contains fixed-length records laid out according to the following schema.
| FIRSTNAME | LASTNAME | ADDRESS LINE-1 | ADDRESS LINE-2 | LINE FEED |
|---|---|---|---|---|
| 8 bytes | 8 bytes | 25 bytes | 25 bytes | 1 byte |
We can create a configuration file that maps the record into a nested object structure.
length: 67 # total length of one record
schema:
- name: FIRSTNAME
length: 8
- name: LASTNAME
length: 8
- name: ADDRESS
schema:
- name: LINE-1
length: 25
- name: LINE-2
length: 25
- name: NL # contains the new line separator from the input file
length: 1Using the fold command with the configuration file, the input file's content can be transformed into a JSON Lines (JSONL) structure, where each line is a JSON document representing a record from the input file.
$ posimap fold < person.fixed-width
{"FIRSTNAME":"JOHN","LASTNAME":"DOE","ADDRESS":{"LINE-1":"1234 ELM STREET","LINE-2":"SPRINGFIELD, IL 62704"}}
{"FIRSTNAME":"JANE","LASTNAME":"SMITH","ADDRESS":{"LINE-1":"56 MAPLE AVENUE","LINE-2":"RIVERSIDE, CA 92501"}}From a JSON Lines document, we can also use the unfold command with the same configuration file to generate a fixed-width file containing the corresponding records.
$ posimap unfold < person.json
JOHN DOE 1234 ELM STREET SPRINGFIELD, IL 62704
JANE SMITH 56 MAPLE AVENUE RIVERSIDE, CA 92501Here is another schema configuration containing OCCURS and REDEFINES.
length: 42
schema:
- name: SHOPPING-BAG
schema:
- name: ITEM
occurs: 2 # This field repeats 2 times
schema:
- name: TYPE # 'F' for fruit, 'V' for vegetable
length: 1
- name: DETAILS
length: 20
- name: FRUIT
redefine: DETAILS
when: '{{ index . "TYPE" | eq "F" }}'
schema:
- name: NAME
length: 10
- name: COLOR
length: 5
- name: VEGETABLE
redefine: DETAILS
when: '{{ index . "TYPE" | eq "V" }}'
schema:
- name: NAME
length: 10
- name: FRESHNESS
length: 10Posimap will be able to marshal records from fixed-width files into this data structure
Important points to note :
- The
DETAILS,FRUIT, andVEGETABLEfields share the same underlying data in the record, thanks to theredefineoption in the configuration file. - The
ITEMfield spans a total length of 42 bytes, as it is repeated twice due to theoccursoption in the configuration file. - The
FRUITfield includes aFILLERof 5 bytes, automatically detected by Posimap to ensure all redefined fields maintain the same total length.
If your input file uses separators between each record, you can specify the separator option in the root section of your configuration file instead of using length.
separator: "\n"
schema:
...Sub-schema can refer to an external configuration file.
schema:
- name: FIRSTNAME
length: 8
- name: LASTNAME
length: 8
- name: ADDRESS # configured in an external schema file
schema: schema-address.yaml # path is relative to this fileBy default, Posimap uses the ISO8859_1 character set, but this can be customized using the --charset flag.
posimap fold -c IBM_037 < person.fixed-widthSupported charsets are listed under the charsets command.
$ posimap charsets
CHARSET NAME DESCRIPTION
------------------- ---------------------------------------
IBM_037 IBM Code Page 037
...$ posimap fold --notrim < person.fixed-width
{"FIRSTNAME":"JOHN ","LASTNAME":"DOE ","ADDRESS":{"LINE-1":"1234 ELM STREET ","LINE-2":"SPRINGFIELD, IL 62704 "}}POSIMAP supports packed decimal (COMP-3) encoding, commonly used in mainframe systems. Packed decimal fields typically use half the bytes of their displayed value, plus half a byte for the sign.
When working with packed decimal fields, you need to:
- Specify the
codec: COMP-3attribute - Define the
pictureclause that describes the field format
Example configuration:
- name: AMOUNT
codec: COMP-3
picture: S9(5)V99 # Signed, 5 digits before decimal point, 2 afterThe picture format follows standard COBOL notation:
Sindicates the value is signed9(n)represents n numeric digitsVrepresents an implied decimal point (no actual character in the data)
The COMP-3 codec accepts both . and , as decimal separators from JSON input and outputs JSON using . as the default decimal separator.
When the usecomma flag is enabled, the COMP-3 codec will encode the decimal separator as , in JSON output.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Copyright (C) 2025 CGI France
Posimap is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Posimap is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with posimap. If not, see http://www.gnu.org/licenses/.
