A flexible data transformation CLI tool that maps and transforms data between JSON, CSV, and XML formats using JSONPath expressions and configurable transformers.
aux4 aux4 pkger install aux4/adapter
Parse a standard CSV file with column headers and map each column to JSON fields.
config:
simple:
format: csv
mapping:
name: $.name
age: $.age
birthdate: $.birthdate
gender: $.gender
city: $.city
cat content.csv | aux4 adapter map --configFile config-csv.yaml --config simple
Process CSV files that use pipe (|) as delimiter instead of commas.
config:
pipe:
format: csv
delimiter: "|"
mapping:
name: $.name
age: $.age
birthdate: $.birthdate
gender: $.gender
city: $.city
cat content-pipe.csv | aux4 adapter map --configFile config-csv.yaml --config pipe
Handle CSV files that don't have header row by explicitly defining column names.
config:
no-header:
format: csv
columns: name,age,birthdate,gender,city
mapping:
name: $.name
age: $.age
birthdate: $.birthdate
gender: $.gender
city: $.city
cat content-no-columns.csv | aux4 adapter map --configFile config-csv.yaml --config no-header
Transform flat CSV data into hierarchical JSON structure with nested objects.
config:
nested:
format: csv
mapping:
name: $.name
age: $.age
birthdate: $.birthdate
gender: $.gender
place:
type: object
mapping:
city: $.city
cat content.csv | aux4 adapter map --configFile config-csv.yaml --config nested
Extract and map fields from a basic JSON object to output JSON with same structure.
config:
simple:
format: json
mapping:
name: $.name
age: $.age
birthdate: $.birthdate
gender: $.gender
city: $.city
cat json-simple.json | aux4 adapter map --configFile config-json.yaml --config simple
Process JSON arrays by applying the same mapping to each array element.
config:
array:
format: json
mapping:
name: $.name
age: $.age
birthdate: $.birthdate
gender: $.gender
city: $.city
cat json-array.json | aux4 adapter map --configFile config-json.yaml --config array
Extract specific fields from deeply nested JSON structures using array indexing.
config:
nested-simple:
format: json
mapping:
firstName: $.users[0].profile.name
firstAge: $.users[0].profile.age
firstCity: $.users[0].details.location.city
secondName: $.users[1].profile.name
secondAge: $.users[1].profile.age
secondCity: $.users[1].details.location.city
cat json-nested.json | aux4 adapter map --configFile config-json.yaml --config nested-simple
Access specific array elements using JSONPath array notation to flatten complex data.
config:
single-array-extraction:
format: json
mapping:
personId: $.person.id
firstName: $.person.profile.firstName
lastName: $.person.profile.lastName
homeCity: $.person.addresses[0].city
homeState: $.person.addresses[0].state
phoneNumber: $.person.phoneNumbers[0].number
company: $.person.employment[0].company
position: $.person.employment[0].position
cat json-single-array.json | aux4 adapter map --configFile config-json.yaml --config single-array-extraction
Build hierarchical output structure by creating nested objects from flat input data.
config:
nested-objects:
format: json
mapping:
employee:
type: object
mapping:
id: $.data.employees[0].id
name: $.data.employees[0].personal.firstName
department: $.data.employees[0].work.department
metadata:
type: object
mapping:
version: $.metadata.version
timestamp: $.metadata.timestamp
cat json-complex.json | aux4 adapter map --configFile config-json.yaml --config nested-objects
Parse basic XML elements and convert them to JSON key-value pairs.
config:
simple:
format: xml
mapping:
name: $.person.name
age: $.person.age
birthdate: $.person.birthdate
gender: $.person.gender
city: $.person.city
cat xml-simple.xml | aux4 adapter map --configFile config-xml.yaml --config simple
Extract both XML element content and attributes using special _attr notation.
config:
book-simple:
format: xml
mapping:
book1Id: $.library.book[0]._attr.id
book1Title: $.library.book[0].title
book1Author: $.library.book[0].author.name
book1Price: $.library.book[0].price
book2Id: $.library.book[1]._attr.id
book2Title: $.library.book[1].title
book2Author: $.library.book[1].author.name
cat xml-attributes.xml | aux4 adapter map --configFile config-xml.yaml --config book-simple
Process multiple XML elements as arrays using array indexing to access individual items.
config:
people-simple:
format: xml
mapping:
person1Id: $.people.person[0]._attr.id
person1Name: $.people.person[0].name
person1Age: $.people.person[0].age
person2Id: $.people.person[1]._attr.id
person2Name: $.people.person[1].name
person2Age: $.people.person[1].age
cat xml-people.xml | aux4 adapter map --configFile config-xml.yaml --config people-simple
Convert text values to lowercase using the built-in lowercase transformer.
config:
lowercase-test:
format: json
mapping:
name:
path: $.name
transformer: lowercase
city:
path: $.city
transformer: lowercase
cat transformer-uppercase-data.json | aux4 adapter map --configFile config-transformers.yaml --config lowercase-test
Convert text values to uppercase using the built-in uppercase transformer.
config:
uppercase-test:
format: json
mapping:
name:
path: $.name
transformer: uppercase
city:
path: $.city
transformer: uppercase
cat transformer-lowercase-data.json | aux4 adapter map --configFile config-transformers.yaml --config uppercase-test
Remove leading and trailing whitespace from text values using the trim transformer.
config:
trim-test:
format: json
mapping:
name:
path: $.name
transformer: trim
city:
path: $.city
transformer: trim
cat transformer-trim-data.json | aux4 adapter map --configFile config-transformers.yaml --config trim-test
Chain multiple transformers by separating them with pipe (|) to apply sequentially.
config:
multiple-trim-lowercase:
format: json
mapping:
name:
path: $.name
transformer: trim|lowercase
city:
path: $.city
transformer: trim|lowercase
cat transformer-multiple-trim-upper-data.json | aux4 adapter map --configFile config-transformers.yaml --config multiple-trim-lowercase
Apply trim first then uppercase transformation in sequence using pipe notation.
config:
multiple-trim-uppercase:
format: json
mapping:
name:
path: $.name
transformer: trim|uppercase
city:
path: $.city
transformer: trim|uppercase
cat transformer-trim-data.json | aux4 adapter map --configFile config-transformers.yaml --config multiple-trim-uppercase
Each entry in a mapping block can be written either as a shorthand string (just a JSONPath) or as an object that unlocks transformers, defaults, type conversion, templates, nested mappings and expressions.
mapping:
name: $.name
The object form supports the following keys:
| Key | Description | | ------------- | -------------------------------------------------------------------------------------------- | | path | JSONPath to read the value from (e.g. $.profile.name). | | type | Coerce/structure the value: number, boolean, array, object (see below). | | default | Value used when the resolved value is missing, null, or empty. | | transformer | Name of a transformer (or pipe-chained transformers) to apply to the value. | | text | A template string with $.path placeholders interpolated from the source object. | | expr | A built-in expression or JSONata expression evaluated against the source object (see below). | | mapping | A nested mapping, used together with type: object or type: array. |
config:
object-form:
format: json
mapping:
id:
path: $.id
type: number
status:
path: $.status
default: active
For input { "id": "42" } this produces { "id": 42, "status": "active" }.
text:)Use text: to build a value from one or more source fields. JSONPath placeholders written as $.path are replaced with the matching value from the source object; missing values become empty strings and the result is trimmed.
config:
text-template:
format: json
mapping:
fullName:
text: "$.firstName $.lastName"
For input { "firstName": "John", "lastName": "Doe" } this produces { "fullName": "John Doe" }.
type: object)Combine type: object with mapping: to build a nested structure from the same source object.
config:
nested:
format: json
mapping:
place:
type: object
mapping:
city: $.address.city
state: $.address.state
Use expr: to compute a value. The adapter tries a set of built-in expressions first and, if none match, evaluates the string as a JSONata expression against the source object.
| Expression | Returns | | ---------- | ------------------------------------------------------------------------------------------------------------------------------ | | uuid() | A version 7 UUID — time-ordered, so UUIDs generated later sort after earlier ones (great for sortable identifiers). | | now() | The current local timestamp as an ISO-8601 string with the machine's UTC offset, e.g. 2026-06-23T19:42:24-05:00. | | utc() | The current timestamp in UTC as an ISO-8601 string in Z form, e.g. 2026-06-24T00:42:24Z. | | time() | The current Unix timestamp in seconds since the epoch (a number), e.g. 1782261744. |
config:
ids-and-dates:
format: json
mapping:
id:
expr: uuid()
createdAtLocal:
expr: now()
createdAtUtc:
expr: utc()
createdEpoch:
expr: time()
name: $.name
echo '{"name":"John"}' | aux4 adapter map --config ids-and-dates
{
"id": "019ef71a-33c0-74c9-bd6b-488c4da098fb",
"createdAtLocal": "2026-06-23T19:42:24-05:00",
"createdAtUtc": "2026-06-24T00:42:24Z",
"createdEpoch": 1782261744,
"name": "John"
}
Any expression that is not a built-in is evaluated as JSONata, which lets you compute fields, concatenate strings, filter arrays, and more. Field names in the expression refer to keys of the source object.
config:
computed:
format: json
mapping:
fullName:
expr: "firstName & ' ' & lastName"
echo '{"firstName":"John","lastName":"Doe"}' | aux4 adapter map --config computed
{
"fullName": "John Doe"
}
In addition to the built-in transformers (default, lowercase, uppercase, trim), you can register named transformers in a transformers: block and reference them by name in your mapping. Custom transformers are built from these registrable types:
| Type | Configuration | Behavior | | --------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- | | date | pattern (input format, default YYYY-MM-DD'T'HH:mm:ss), format (output format, default YYYY-MM-DD HH:mm:ss Z) | Reformats a date string from pattern to format (via moment). | | replace | replace (value→value map), defaultValue (optional) | Replaces the value using the map; falls back to defaultValue. | | remove | list (array of substrings) | Removes every occurrence of each listed substring from the value. |
The built-in default transformer returns the value unchanged.
config:
custom-transformers:
format: json
transformers:
BIRTHDATE:
type: date
pattern: YYYY-MM-DD
format: MM/DD/YYYY
GENDER:
type: replace
replace:
M: MALE
F: FEMALE
defaultValue: UNKNOWN
PHONE:
type: remove
list:
- "+"
- "-"
mapping:
birthdate:
path: $.birthdate
transformer: BIRTHDATE
gender:
path: $.gender
transformer: GENDER
phone:
path: $.phone
transformer: PHONE
echo '{"birthdate":"2020-03-15","gender":"M","phone":"+1-555-123-4567"}' | aux4 adapter map --config custom-transformers
{
"birthdate": "03/15/2020",
"gender": "MALE",
"phone": "15551234567"
}
Transform complex JSON data into structured nested objects with grouped related fields.
config:
json-nested-simple:
format: json
mapping:
metadata:
type: object
mapping:
version: $.metadata.version
totalUsers: $.metadata.totalUsers
lastUpdated: $.metadata.lastUpdated
firstUser:
type: object
mapping:
id: $.users[0].id
firstName: $.users[0].profile.firstName
lastName: $.users[0].profile.lastName
email: $.users[0].profile.email
company: $.users[0].employment.company
cat complex-data.json | aux4 adapter map --configFile config-complex-simple.yaml --config json-nested-simple
Convert flat CSV rows into rich hierarchical structures with multiple nested object levels.
config:
csv-simple-complex:
format: csv
mapping:
person:
type: object
mapping:
id:
path: $.id
type: number
firstName: $.firstName
lastName: $.lastName
email: $.email
age:
path: $.age
type: number
contact:
type: object
mapping:
mobilePhone: $.mobilePhone
homeAddress:
type: object
mapping:
street: $.homeStreet
city: $.homeCity
state: $.homeState
employment:
type: object
mapping:
company: $.company
position: $.position
salary:
path: $.salary
type: number
cat complex-csv.csv | aux4 adapter map --configFile config-complex-simple.yaml --config csv-simple-complex
By default, the adapter outputs data as a JSON array. Use the --stream parameter to output each item as individual JSON objects (one per line).
Sample CSV input (content.csv):
name,age,birthdate,gender,city
John,,1992-04-10,M,New York
Jane,29,1994-02-10,F,
Dane,42,1936-03-11,,Boston
Standard output (JSON array):
cat content.csv | aux4 adapter map --config simple
Output:
[
{ "name": "John", "birthdate": "1992-04-10", "gender": "M", "city": "New York" },
{ "name": "Jane", "age": "29", "birthdate": "1994-02-10", "gender": "F" },
{ "name": "Dane", "age": "42", "birthdate": "1936-03-11", "city": "Boston" }
]
Streaming output (individual JSON objects):
cat content.csv | aux4 adapter map --config simple --stream
Output:
{"name":"John","birthdate":"1992-04-10","gender":"M","city":"New York"}
{"name":"Jane","age":"29","birthdate":"1994-02-10","gender":"F"}
{"name":"Dane","age":"42","birthdate":"1936-03-11","city":"Boston"}
Pass additional options to the CSV parser to control parsing behavior. Options can be provided as command-line JSON or directly in the configuration file.
Skip lines from the beginning using configuration:
Set up your configuration file to skip the first data row and process from the second row onwards:
config:
simple:
format: csv
options:
from: 2 # Skip first data row (John)
mapping:
name: $.name
age: $.age
birthdate: $.birthdate
gender: $.gender
city: $.city
Command:
cat content.csv | aux4 adapter map --config simple
Output:
[
{ "name": "Jane", "age": "29", "birthdate": "1994-02-10", "gender": "F" },
{ "name": "Dane", "age": "42", "birthdate": "1936-03-11", "city": "Boston" }
]
Apache-2.0