Normalize vendor fields with a closed pipe DSL on fieldMappings.attributes. One value in, one value out. Use split then index when you need one array element — not a hardcoded character offset.
Attribute shape, identity, and dimensions stay on Configure business vocabulary. This page is the expression catalog the CIP map step runs.
Prerequisites
- Datasource JSON with
fieldMappings.attributesand matchingmetadataSchema.properties - Configure data flow — list/get operations use a
mapstep - Login and
aifabrix datasource validaterights for the Connected System
Where it lives
| Layer | Location |
|---|---|
| Read expression | <datasourceKey>.json → fieldMappings.attributes.<name>.expression |
| CIP map | execution.cip.operations.*.steps → map.useFieldMappings (default true) or map.inline |
| Display label | Root labelKey (joins present fields with a space) |
Short-form sugar is a string equal to a {{...}} expression; the compiler expands it to { "expression": "..." }.
How to set
- Start from a root —
{{raw.<path>}}, or one hop{{fk.<name>.metadata.<field>}}/{{dimension.<key>}}. - Pipe functions with
|. The left side is the pipeline value; extra arguments go in parentheses. - Pick an array element with
indexaftersplit(0-based; negative counts from the end). Strings staysubstring—indexdoes not treat a string as characters.
{
"fieldMappings": {
"attributes": {
"status": {
"expression": "{{raw.fields.state}} | toLower | trim"
},
"folderLabel": {
"expression": "{{raw.driveItem.parentReference.path}} | coalesce(raw.parentReference.path) | split('root:/') | index(1)",
"description": "Library-relative folder after the document-root marker"
}
}
}
}
- If the field is on
labelKey, add it tometadataSchema.propertieswithindex: true. - Validate (see below). Function chains are non-invertible: they default to
direction: "read"unless you setwritePath.
Unknown names such as nth fail compile (unknown_function). Missing, non-array, empty, or out-of-range index returns null (same fail-soft as the rest of the DSL).
Defaults and examples
Closed allow-list (11 functions). join and split default delimiter is , (comma), not empty string or whitespace.
| Function | Arguments | Effect |
|---|---|---|
toLower / toUpper / trim / normalizeWhitespace |
(value) | Case and whitespace |
substring |
(value, start [, end]) | Slice a string; negative start from the end |
replace |
(value, search, replacement) | Replace all occurrences |
default |
(value, defaultValue) | Fallback when null/empty |
coalesce |
(value, ...) | First non-null/non-empty |
join |
(value [, delimiter]) | Array → string; default "," |
split |
(value [, delimiter]) | String → array; default "," |
index |
(value, n) | Array element; 0-based n; negative from the end |
Example: path /drives/<id>/root:/Deals/Roche with split('root:/') | index(1) yields Deals/Roche. Pair labelKey: ["folderLabel", "name"] for a space-joined operator label. There is no concat in this catalog — a dashed separator is a later mapping, not CIP pythonInline for a one-element pick.
Validate
aifabrix datasource validate <datasourceKey>
aifabrix validate <systemKey>
Expect compile errors for unknown functions or wrong argument counts. After publish, list records and confirm display uses labelKey fields.
Common mistakes
| Mistake | Fix |
|---|---|
"source": "$.id" JSONPath |
Use "expression": "{{raw.id}}" |
substring(N) for a variable-length drive id |
split('root:/') \| index(1) |
index on a string |
Use substring; index is arrays only |
Inventing nth, at, concat, or regex |
Stay on the closed list; unknown names fail compile |
Assuming split defaults to whitespace |
Default delimiter is "," |
Putting pythonInline on a one-element pick |
Use index in the map DSL |
Limits
The allow-list is closed: no JMESPath inside fieldMappings, no format helpers, and no growing the registry per vendor. CIP pythonInline remains last resort for transforms the pipe cannot express. labelKey still joins with a space.