{"content":"# aux4/adapter\n\nA flexible data transformation CLI tool that maps and transforms data between JSON, CSV, and XML formats using JSONPath expressions and configurable transformers.\n\n## Installation\n\n``bash\naux4 aux4 pkger install aux4/adapter\n`\n\n## CSV Processing\n\n### Simple CSV with headers\n\nParse a standard CSV file with column headers and map each column to JSON fields.\n\n`yaml\nconfig:\n simple:\n format: csv\n mapping:\n name: $.name\n age: $.age\n birthdate: $.birthdate\n gender: $.gender\n city: $.city\n`\n\n`bash\ncat content.csv | aux4 adapter map --configFile config-csv.yaml --config simple\n`\n\n### Pipe-separated values\n\nProcess CSV files that use pipe (|) as delimiter instead of commas.\n\n`yaml\nconfig:\n pipe:\n format: csv\n delimiter: \"|\"\n mapping:\n name: $.name\n age: $.age\n birthdate: $.birthdate\n gender: $.gender\n city: $.city\n`\n\n`bash\ncat content-pipe.csv | aux4 adapter map --configFile config-csv.yaml --config pipe\n`\n\n### CSV without headers\n\nHandle CSV files that don't have header row by explicitly defining column names.\n\n`yaml\nconfig:\n no-header:\n format: csv\n columns: name,age,birthdate,gender,city\n mapping:\n name: $.name\n age: $.age\n birthdate: $.birthdate\n gender: $.gender\n city: $.city\n`\n\n`bash\ncat content-no-columns.csv | aux4 adapter map --configFile config-csv.yaml --config no-header\n`\n\n### CSV to nested objects\n\nTransform flat CSV data into hierarchical JSON structure with nested objects.\n\n`yaml\nconfig:\n nested:\n format: csv\n mapping:\n name: $.name\n age: $.age\n birthdate: $.birthdate\n gender: $.gender\n place:\n type: object\n mapping:\n city: $.city\n`\n\n`bash\ncat content.csv | aux4 adapter map --configFile config-csv.yaml --config nested\n`\n\n## JSON Processing\n\n### Simple object mapping\n\nExtract and map fields from a basic JSON object to output JSON with same structure.\n\n`yaml\nconfig:\n simple:\n format: json\n mapping:\n name: $.name\n age: $.age\n birthdate: $.birthdate\n gender: $.gender\n city: $.city\n`\n\n`bash\ncat json-simple.json | aux4 adapter map --configFile config-json.yaml --config simple\n`\n\n### Array processing\n\nProcess JSON arrays by applying the same mapping to each array element.\n\n`yaml\nconfig:\n array:\n format: json\n mapping:\n name: $.name\n age: $.age\n birthdate: $.birthdate\n gender: $.gender\n city: $.city\n`\n\n`bash\ncat json-array.json | aux4 adapter map --configFile config-json.yaml --config array\n`\n\n### Nested object extraction\n\nExtract specific fields from deeply nested JSON structures using array indexing.\n\n`yaml\nconfig:\n nested-simple:\n format: json\n mapping:\n firstName: $.users[0].profile.name\n firstAge: $.users[0].profile.age\n firstCity: $.users[0].details.location.city\n secondName: $.users[1].profile.name\n secondAge: $.users[1].profile.age\n secondCity: $.users[1].details.location.city\n`\n\n`bash\ncat json-nested.json | aux4 adapter map --configFile config-json.yaml --config nested-simple\n`\n\n### Array indexing\n\nAccess specific array elements using JSONPath array notation to flatten complex data.\n\n`yaml\nconfig:\n single-array-extraction:\n format: json\n mapping:\n personId: $.person.id\n firstName: $.person.profile.firstName\n lastName: $.person.profile.lastName\n homeCity: $.person.addresses[0].city\n homeState: $.person.addresses[0].state\n phoneNumber: $.person.phoneNumbers[0].number\n company: $.person.employment[0].company\n position: $.person.employment[0].position\n`\n\n`bash\ncat json-single-array.json | aux4 adapter map --configFile config-json.yaml --config single-array-extraction\n`\n\n### Creating nested objects\n\nBuild hierarchical output structure by creating nested objects from flat input data.\n\n`yaml\nconfig:\n nested-objects:\n format: json\n mapping:\n employee:\n type: object\n mapping:\n id: $.data.employees[0].id\n name: $.data.employees[0].personal.firstName\n department: $.data.employees[0].work.department\n metadata:\n type: object\n mapping:\n version: $.metadata.version\n timestamp: $.metadata.timestamp\n`\n\n`bash\ncat json-complex.json | aux4 adapter map --configFile config-json.yaml --config nested-objects\n`\n\n## XML Processing\n\n### Simple XML document\n\nParse basic XML elements and convert them to JSON key-value pairs.\n\n`yaml\nconfig:\n simple:\n format: xml\n mapping:\n name: $.person.name\n age: $.person.age\n birthdate: $.person.birthdate\n gender: $.person.gender\n city: $.person.city\n`\n\n`bash\ncat xml-simple.xml | aux4 adapter map --configFile config-xml.yaml --config simple\n`\n\n### XML attributes extraction\n\nExtract both XML element content and attributes using special _attr notation.\n\n`yaml\nconfig:\n book-simple:\n format: xml\n mapping:\n book1Id: $.library.book[0]._attr.id\n book1Title: $.library.book[0].title\n book1Author: $.library.book[0].author.name\n book1Price: $.library.book[0].price\n book2Id: $.library.book[1]._attr.id\n book2Title: $.library.book[1].title\n book2Author: $.library.book[1].author.name\n`\n\n`bash\ncat xml-attributes.xml | aux4 adapter map --configFile config-xml.yaml --config book-simple\n`\n\n### XML array processing\n\nProcess multiple XML elements as arrays using array indexing to access individual items.\n\n`yaml\nconfig:\n people-simple:\n format: xml\n mapping:\n person1Id: $.people.person[0]._attr.id\n person1Name: $.people.person[0].name\n person1Age: $.people.person[0].age\n person2Id: $.people.person[1]._attr.id\n person2Name: $.people.person[1].name\n person2Age: $.people.person[1].age\n`\n\n`bash\ncat xml-people.xml | aux4 adapter map --configFile config-xml.yaml --config people-simple\n`\n\n## Data Transformers\n\n### Lowercase transformation\n\nConvert text values to lowercase using the built-in lowercase transformer.\n\n`yaml\nconfig:\n lowercase-test:\n format: json\n mapping:\n name:\n path: $.name\n transformer: lowercase\n city:\n path: $.city\n transformer: lowercase\n`\n\n`bash\ncat transformer-uppercase-data.json | aux4 adapter map --configFile config-transformers.yaml --config lowercase-test\n`\n\n### Uppercase transformation\n\nConvert text values to uppercase using the built-in uppercase transformer.\n\n`yaml\nconfig:\n uppercase-test:\n format: json\n mapping:\n name:\n path: $.name\n transformer: uppercase\n city:\n path: $.city\n transformer: uppercase\n`\n\n`bash\ncat transformer-lowercase-data.json | aux4 adapter map --configFile config-transformers.yaml --config uppercase-test\n`\n\n### Trim whitespace\n\nRemove leading and trailing whitespace from text values using the trim transformer.\n\n`yaml\nconfig:\n trim-test:\n format: json\n mapping:\n name:\n path: $.name\n transformer: trim\n city:\n path: $.city\n transformer: trim\n`\n\n`bash\ncat transformer-trim-data.json | aux4 adapter map --configFile config-transformers.yaml --config trim-test\n`\n\n### Multiple transformers (trim + lowercase)\n\nChain multiple transformers by separating them with pipe (|) to apply sequentially.\n\n`yaml\nconfig:\n multiple-trim-lowercase:\n format: json\n mapping:\n name:\n path: $.name\n transformer: trim|lowercase\n city:\n path: $.city\n transformer: trim|lowercase\n`\n\n`bash\ncat transformer-multiple-trim-upper-data.json | aux4 adapter map --configFile config-transformers.yaml --config multiple-trim-lowercase\n`\n\n### Multiple transformers (trim + uppercase)\n\nApply trim first then uppercase transformation in sequence using pipe notation.\n\n`yaml\nconfig:\n multiple-trim-uppercase:\n format: json\n mapping:\n name:\n path: $.name\n transformer: trim|uppercase\n city:\n path: $.city\n transformer: trim|uppercase\n`\n\n`bash\ncat transformer-trim-data.json | aux4 adapter map --configFile config-transformers.yaml --config multiple-trim-uppercase\n`\n\n## Field Mapping Forms\n\nEach 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.\n\n### Shorthand (JSONPath string)\n\n`yaml\nmapping:\n name: $.name\n`\n\n### Object form\n\nThe object form supports the following keys:\n\n| Key | Description |\n| ------------- | -------------------------------------------------------------------------------------------- |\n| path | JSONPath to read the value from (e.g. $.profile.name). |\n| type | Coerce/structure the value: number, boolean, array, object (see below). |\n| default | Value used when the resolved value is missing, null, or empty. |\n| transformer | Name of a transformer (or pipe-chained transformers) to apply to the value. |\n| text | A template string with $.path placeholders interpolated from the source object. |\n| expr | A built-in expression or JSONata expression evaluated against the source object (see below). |\n| mapping | A nested mapping, used together with type: object or type: array. |\n\n`yaml\nconfig:\n object-form:\n format: json\n mapping:\n id:\n path: $.id\n type: number\n status:\n path: $.status\n default: active\n`\n\nFor input { \"id\": \"42\" } this produces { \"id\": 42, \"status\": \"active\" }.\n\n### Text templates (text:)\n\nUse 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.\n\n`yaml\nconfig:\n text-template:\n format: json\n mapping:\n fullName:\n text: \"$.firstName $.lastName\"\n`\n\nFor input { \"firstName\": \"John\", \"lastName\": \"Doe\" } this produces { \"fullName\": \"John Doe\" }.\n\n### Nested objects (type: object)\n\nCombine type: object with mapping: to build a nested structure from the same source object.\n\n`yaml\nconfig:\n nested:\n format: json\n mapping:\n place:\n type: object\n mapping:\n city: $.address.city\n state: $.address.state\n`\n\n## Expression Mappings\n\nUse 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](https://jsonata.org) expression against the source object.\n\n### Built-in expressions\n\n| Expression | Returns |\n| ---------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| uuid() | A **version 7 UUID** — time-ordered, so UUIDs generated later sort after earlier ones (great for sortable identifiers). |\n| 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. |\n| utc() | The current timestamp in UTC as an ISO-8601 string in Z form, e.g. 2026-06-24T00:42:24Z. |\n| time() | The current Unix timestamp in seconds since the epoch (a number), e.g. 1782261744. |\n\n`yaml\nconfig:\n ids-and-dates:\n format: json\n mapping:\n id:\n expr: uuid()\n createdAtLocal:\n expr: now()\n createdAtUtc:\n expr: utc()\n createdEpoch:\n expr: time()\n name: $.name\n`\n\n`bash\necho '{\"name\":\"John\"}' | aux4 adapter map --config ids-and-dates\n`\n\n`json\n{\n \"id\": \"019ef71a-33c0-74c9-bd6b-488c4da098fb\",\n \"createdAtLocal\": \"2026-06-23T19:42:24-05:00\",\n \"createdAtUtc\": \"2026-06-24T00:42:24Z\",\n \"createdEpoch\": 1782261744,\n \"name\": \"John\"\n}\n`\n\n### JSONata expressions\n\nAny 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.\n\n`yaml\nconfig:\n computed:\n format: json\n mapping:\n fullName:\n expr: \"firstName & ' ' & lastName\"\n`\n\n`bash\necho '{\"firstName\":\"John\",\"lastName\":\"Doe\"}' | aux4 adapter map --config computed\n`\n\n`json\n{\n \"fullName\": \"John Doe\"\n}\n`\n\n## Custom Transformers\n\nIn 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:\n\n| Type | Configuration | Behavior |\n| --------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |\n| 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). |\n| replace | replace (value→value map), defaultValue (optional) | Replaces the value using the map; falls back to defaultValue. |\n| remove | list (array of substrings) | Removes every occurrence of each listed substring from the value. |\n\nThe built-in default transformer returns the value unchanged.\n\n`yaml\nconfig:\n custom-transformers:\n format: json\n transformers:\n BIRTHDATE:\n type: date\n pattern: YYYY-MM-DD\n format: MM/DD/YYYY\n GENDER:\n type: replace\n replace:\n M: MALE\n F: FEMALE\n defaultValue: UNKNOWN\n PHONE:\n type: remove\n list:\n - \"+\"\n - \"-\"\n mapping:\n birthdate:\n path: $.birthdate\n transformer: BIRTHDATE\n gender:\n path: $.gender\n transformer: GENDER\n phone:\n path: $.phone\n transformer: PHONE\n`\n\n`bash\necho '{\"birthdate\":\"2020-03-15\",\"gender\":\"M\",\"phone\":\"+1-555-123-4567\"}' | aux4 adapter map --config custom-transformers\n`\n\n`json\n{\n \"birthdate\": \"03/15/2020\",\n \"gender\": \"MALE\",\n \"phone\": \"15551234567\"\n}\n`\n\n## Complex Mappings\n\n### JSON to nested objects\n\nTransform complex JSON data into structured nested objects with grouped related fields.\n\n`yaml\nconfig:\n json-nested-simple:\n format: json\n mapping:\n metadata:\n type: object\n mapping:\n version: $.metadata.version\n totalUsers: $.metadata.totalUsers\n lastUpdated: $.metadata.lastUpdated\n firstUser:\n type: object\n mapping:\n id: $.users[0].id\n firstName: $.users[0].profile.firstName\n lastName: $.users[0].profile.lastName\n email: $.users[0].profile.email\n company: $.users[0].employment.company\n`\n\n`bash\ncat complex-data.json | aux4 adapter map --configFile config-complex-simple.yaml --config json-nested-simple\n`\n\n### CSV to complex objects\n\nConvert flat CSV rows into rich hierarchical structures with multiple nested object levels.\n\n`yaml\nconfig:\n csv-simple-complex:\n format: csv\n mapping:\n person:\n type: object\n mapping:\n id:\n path: $.id\n type: number\n firstName: $.firstName\n lastName: $.lastName\n email: $.email\n age:\n path: $.age\n type: number\n contact:\n type: object\n mapping:\n mobilePhone: $.mobilePhone\n homeAddress:\n type: object\n mapping:\n street: $.homeStreet\n city: $.homeCity\n state: $.homeState\n employment:\n type: object\n mapping:\n company: $.company\n position: $.position\n salary:\n path: $.salary\n type: number\n`\n\n`bash\ncat complex-csv.csv | aux4 adapter map --configFile config-complex-simple.yaml --config csv-simple-complex\n`\n\n## Command Line Options\n\n### Streaming Output (--stream)\n\nBy default, the adapter outputs data as a JSON array. Use the --stream parameter to output each item as individual JSON objects (one per line).\n\n**Sample CSV input (content.csv):**\n\n`csv\nname,age,birthdate,gender,city\nJohn,,1992-04-10,M,New York\nJane,29,1994-02-10,F,\nDane,42,1936-03-11,,Boston\n`\n\n**Standard output (JSON array):**\n\n`bash\ncat content.csv | aux4 adapter map --config simple\n`\n\n**Output:**\n\n`json\n[\n { \"name\": \"John\", \"birthdate\": \"1992-04-10\", \"gender\": \"M\", \"city\": \"New York\" },\n { \"name\": \"Jane\", \"age\": \"29\", \"birthdate\": \"1994-02-10\", \"gender\": \"F\" },\n { \"name\": \"Dane\", \"age\": \"42\", \"birthdate\": \"1936-03-11\", \"city\": \"Boston\" }\n]\n`\n\n**Streaming output (individual JSON objects):**\n\n`bash\ncat content.csv | aux4 adapter map --config simple --stream\n`\n\n**Output:**\n\n`json\n{\"name\":\"John\",\"birthdate\":\"1992-04-10\",\"gender\":\"M\",\"city\":\"New York\"}\n{\"name\":\"Jane\",\"age\":\"29\",\"birthdate\":\"1994-02-10\",\"gender\":\"F\"}\n{\"name\":\"Dane\",\"age\":\"42\",\"birthdate\":\"1936-03-11\",\"city\":\"Boston\"}\n`\n\n### CSV Parser Options (--options)\n\nPass additional options to the CSV parser to control parsing behavior. Options can be provided as command-line JSON or directly in the configuration file.\n\n**Skip lines from the beginning using configuration:**\n\nSet up your configuration file to skip the first data row and process from the second row onwards:\n\n`yaml\nconfig:\n simple:\n format: csv\n options:\n from: 2 # Skip first data row (John)\n mapping:\n name: $.name\n age: $.age\n birthdate: $.birthdate\n gender: $.gender\n city: $.city\n`\n\n**Command:**\n\n`bash\ncat content.csv | aux4 adapter map --config simple\n`\n\n**Output:**\n\n`json\n[\n { \"name\": \"Jane\", \"age\": \"29\", \"birthdate\": \"1994-02-10\", \"gender\": \"F\" },\n { \"name\": \"Dane\", \"age\": \"42\", \"birthdate\": \"1936-03-11\", \"city\": \"Boston\" }\n]\n``\n\n## See Also\n\n- aux4/config for more information on configuration files.\n- aux4/validator for validating data against schemas.\n\n## License\n\nApache-2.0\n"}