Skip to main content

Transform Component

The Transform component manipulates JSON data using JSONata — a query and transformation language for JSON. Use it to extract specific fields, reshape structures, filter by value, merge datasets, or compute totals before passing data to downstream components.


Using the Transform component​

  1. Add the Transform component after the step whose output you want to reshape, for example an M3 API, REST API or Code step.
  2. Load test data into Input, either from an earlier run or by pasting it in. See Testing with real data.
  3. Write a JSONata expression in JSONata Expression. Output shows the result as you type.
  4. Click Save. Only the expression is saved; the test input isn't.
  5. When the workflow runs, the step's output is passed to the next component. Check it in Execution Logs after a test run.

The Transform editor​

The editor has three panels:

PanelWhat it's for
InputTest data for the expression. It stands in for the data the step receives when the workflow runs.
JSONata ExpressionThe expression that is saved with the step.
OutputThe result of running the expression on Input. It updates as you type.

Drag the dividers between the panels to resize them. The sizes are remembered in your browser.

Layout​

Use the layout buttons at the top right, next to Learn JSONata syntax, to choose how the panels are arranged:

  • Three columns: Input, JSONata Expression and Output side by side.
  • Expression above output: Input on the left, with JSONata Expression above Output on the right. This gives long expressions and wide outputs more room. Both the vertical and the horizontal divider can be dragged.

Your choice is remembered in your browser, along with the panel sizes of each layout.

Input​

Input starts with a small sample, { "body": { "hello": "world" } }. You can edit it or paste in your own JSON. Invalid JSON is underlined, and Output shows the parse error instead of a result.

To test against real data, load an earlier run of the workflow:

  • Leave Workflow execution id empty and click Load (or press Enter) to load the latest run.
  • Or enter the ID of a specific run, with or without the WFEXEC- prefix, and click Load. You can find run IDs in Execution Logs.

The input, and any run you loaded, is kept when you close and reopen the step or move between steps in the workflow editor, and every Transform step in the workflow shows the same input. It is reset when you open another workflow.

JSONata Expression​

The expression editor helps you write JSONata:

  • Syntax highlighting in a monospace font, with the same colours as the JSONata exerciser. Regular expressions (/…/) are highlighted too.
  • Autocomplete: type $ (or press Ctrl+Space) for a list of functions, grouped by category, including the Vince-specific functions. Choosing a function adds the brackets for you. The list also offers $context paths, including $context.runtime.connections.<alias> and $context.runtime.variables.<name> for the connections and variables set up in the workflow's environments.
  • Brackets and quotes close automatically, and the matching bracket is highlighted.
  • Indentation: pressing Enter after {, ( or [ indents the next line, and typing the closing bracket lines it up again.
  • Folding: click the arrow next to a line number to collapse a { }, [ ] or ( ) block.
  • Copy to clipboard: the button above the editor copies the whole expression.
ShortcutAction
Ctrl+FSearch in the editor (click into the editor first)
Shift+Alt+AComment out the selection as a /* */ block, or remove the comment
Tab / Shift+TabIndent / outdent the selected lines
Ctrl+Z / Ctrl+Shift+ZUndo / redo

On a Mac, use Cmd instead of Ctrl.

Output​

Output runs the expression on Input every time either of them changes:

  • If the expression works, the result is shown as formatted JSON.
  • If it fails, the JSONata error message is shown in red. This is the easiest place to find out why an expression fails, because a failing Transform doesn't report an error when the workflow runs (see Gotchas).
  • If Input or the expression is empty, Output asks for both.

Testing with real data​

Three things differ between the editor and a real run.

$ is the whole run, not the previous step. After Load, Input holds the complete record of the run: its status, the trigger input, and the output of every step. When the workflow runs, $ is only the previous step's output. So an expression like $.body.records that works at run time finds nothing in the editor, and the other way round.

Recommended: refer to steps by ID

Write $context.data.all.<step ID> instead of $, even for the previous step, for example $context.data.all.rest_api_1.body.records. It gives the same result in the editor and at run time, and it keeps working when steps are added or moved. See the $context Reference and the JSONata Masterclass.

If an expression does use $, replace Input with just the previous step's output to test it. You can copy that from Execution Logs.

$context is simulated. The editor builds a $context so that expressions using it can be tested:

PathIn the editor
$context.data.allThe output of every step of the loaded run, by step ID
$context.data.triggerThe header and body the loaded run was started with. executionParams and executionKeys aren't available.
$context.userYou, the user signed in to the editor, not the user who ran the workflow
$context.runtimeThe connections and variables of the workflow's default environment
$context.tenant, $context.envThe real values
$context.workflowExecutionNot available

Large data isn't loaded. When a step's output is too large to keep with the run, Vince Platform stores it separately. A real run reads it from there, but Load doesn't: that data is missing from Input and from $context.data.all in the editor. To test with it, copy the step's output from Execution Logs and paste it into Input.

Getting help​

Learn JSONata syntax opens the JSONata documentation. The JSONata exerciser is useful for trying out standard JSONata, but it doesn't know $context or the Vince-specific functions, so test those in the Transform editor.

Stuck on an expression? Ask Frøy

Click Ask Frøy in the header while a Transform step is open. It sees your expression, any error and the step's input, so it can explain an error or write or fix the expression. A suggested expression is placed in the editor: check Output and test it before you click Save. See Ask Frøy.


Common JSONata expressions​

OperationExample
Extract fields$context.data.all.m3_api_1.body.results.records.{"Name": ITNO, "Price": SAPR}
Filter by condition$context.data.all.rest_api_1.body.items[price > 20]
Sum a field$sum($context.data.all.rest_api_1.body.items.price)
Flatten nested lists into one list$context.data.all.rest_api_1.body.orders.lines[]

Each example names the step it reads from, such as rest_api_1, as recommended in Testing with real data. See How step IDs are formed.


Vince-specific functions​

On top of the standard JSONata functions, the Transform component has a few functions of its own. Parameters marked optional can be left out.

FunctionReturnsWhat it does
$toXml(data, ignoreAttributes, attributeNamePrefix)TextConverts a JSON object to an XML string. ignoreAttributes (true/false) and attributeNamePrefix (text) are optional.
$fromXml(xml, ignoreAttributes, attributeNamePrefix)JSONConverts an XML string to JSON. ignoreAttributes and attributeNamePrefix are optional.
$tsToTimezone(timestamp, timeZone)TextFormats a timestamp in a given time zone, as an ISO-style date and time with the UTC offset. timeZone is an IANA time zone name such as Europe/Oslo; if left out, GMT is used.
$removeNullValues(input)Same as inputRemoves every null value, at any depth. Empty lists ([]) and empty objects ({}) are kept.
$uuid()TextGenerates a random UUID, for example as a unique reference for a request.
$sheetToJson(rows, headerRowIndex)ListTurns spreadsheet rows (a list of row objects) into a list of objects whose keys come from the header row. headerRowIndex is optional and defaults to 0, the first row. Returns [] if the input isn't valid.
$chunk(list, size)List of listsSplits a list into batches of size items. The last batch holds whatever is left over.

$toXml and $fromXml also work on the current value when you leave out the first argument, so $context.data.all.rest_api_1.body ~> $toXml() is the same as $toXml($context.data.all.rest_api_1.body).

Some examples:

/* Show a UTC timestamp in Norwegian local time */
$tsToTimezone("2026-10-02T09:30:00Z", "Europe/Oslo")

/* Send lines to an API that accepts at most 100 per request */
{ "batches": $chunk($context.data.all.rest_api_1.body.lines, 100) }

/* Drop null fields before sending a request body */
$removeNullValues({ "item": "BOLT-M8", "note": null, "lines": [] })
/* → { "item": "BOLT-M8", "lines": [] } */

Two things to keep in mind:

  • $chunk of an empty list returns [[]]: one empty batch, not an empty list. If a REST API step runs For each over the batches, it would make one request with an empty batch. Guard it with a Skip if expression such as $count(body.lines) = 0.
  • These functions only exist in Vince. The JSONata exerciser doesn't know them and reports them as undefined. Test the rest of the expression there, and these functions in the Transform editor or a workflow test run.

When you want the XML conversion as a visible step of its own, see the Converter component and Receive, Transform and Send XML.


Gotchas​

Errors in the expression don't fail the step​

If the expression can't be evaluated, the Transform doesn't fail. It passes its input on to the next step unchanged, as if the Transform weren't there. This happens for:

  • a syntax error, such as a missing bracket or a typo in a function name,
  • an error while the expression runs, such as $number("") on an empty value, or
  • a deliberate $error() or $assert() call.

Only an empty expression, or a problem loading the input data, makes the step itself fail.

No error message is logged. In Execution Logs, the Transform's output is simply identical to its input, and that is the only sign that the expression failed. So if a Transform seems to "do nothing", open the run and compare the Transform's input and output. If they match, copy the input into Input in the Transform editor: Output then shows the actual error.

This also means a Transform can't stop a workflow on purpose. To report a problem, return it as data, for example a "status": "FAILED" field that later steps can check. See REST API in Practice for the pattern.


Transform versus Code​

Use Transform for working with data: extracting fields, filtering, restructuring lists, calculating totals, and conditional logic (JSONata has condition ? a : b). Use Code when you need something JSONata can't do, such as a protocol the other components don't support, or logic that is much clearer in JavaScript.


Further reading​

  • JSONata Masterclass — structure larger Transform expressions so they stay readable and correct
  • Code — custom JavaScript for logic that JSONata cannot express
  • M3 API — commonly used upstream of Transform to reshape M3 output
  • Execution Logs — inspect the transform output from a test run
  • $context Reference — read the trigger input, earlier steps, the user and environment values in an expression