Skip to main content

Selecting data with JSONPath

SHIPM8 templates use JSONPath Plus syntax to navigate data. You can test expressions at jsonpath.com.

A sample data structure

The examples on this page use the following port-call JSON:

{
"Data": [
{
"Ct_portcallfile": {
"eta": "2025-07-22T00:00:00",
"port name": "Amsterdam",
"__AdditionalData": {
"ship": {
"name": "Ocean Star"
},
"customer": {
"name": "Blue Tide Shipping",
"member": true,
"company": ""
},
"cargoRegistration": [
{
"cargo": "Crude Oil",
"quantity": 52000,
"blNumber": "BL-2025-001"
}
]
}
}
}
]
}

Picking out values

Use a dot-separated path inside {{ }} to reach any field:

What to extractExpressionResult
ETA{{ Data.[0].Ct_portcallfile.eta }}2025-07-22T00:00:00
Port name{{ Data.[0].Ct_portcallfile.['port name'] }}Amsterdam
Ship name{{ Data.[0].Ct_portcallfile.__AdditionalData.ship.name }}Ocean Star
Customer name{{ Data.[0].Ct_portcallfile.__AdditionalData.customer.name }}Blue Tide Shipping
Member flag{{ Data.[0].Ct_portcallfile.__AdditionalData.customer.member }}True
Company (empty){{ Data.[0].Ct_portcallfile.__AdditionalData.customer.company }}(blank)
Cargo type{{ Data.[0].Ct_portcallfile.__AdditionalData.cargoRegistration.[0].cargo }}Crude Oil
Cargo quantity{{ Data.[0].Ct_portcallfile.__AdditionalData.cargoRegistration.[0].quantity }}52000
BL number{{ Data.[0].Ct_portcallfile.__AdditionalData.cargoRegistration.[0].blNumber }}BL-2025-001

Data types

JSONPath can reach any standard JSON data type. Targeting an object or array directly returns an internal object — always drill down to a scalar field for readable output.

TypeExampleResult
String{{ Data.[0].Ct_portcallfile.__AdditionalData.ship.name }}Ocean Star
Number{{ Data.[0].Ct_portcallfile.__AdditionalData.cargoRegistration.[0].quantity }}52000
Boolean{{ Data.[0].Ct_portcallfile.__AdditionalData.customer.member }}True or False
Null / empty{{ Data.[0].Ct_portcallfile.__AdditionalData.customer.company }}(blank)
Object{{ Data.[0].Ct_portcallfile }}System.Dynamic.ExpandoObject — use a specific field instead
Array item (object){{ Data.[0].Ct_portcallfile.__AdditionalData.cargoRegistration.[0] }}System.Dynamic.ExpandoObject — use .cargo, .quantity, etc.

Arrays and indexes

Array indexes go in square brackets with a leading dot: .[0], .[1], etc.

✅ Correct:

{{ Data.[0].Ct_portcallfile.__AdditionalData.cargoRegistration.[0].cargo }}

❌ Incorrect:

{{ Data[0].Ct_portcallfile.__AdditionalData.cargoRegistration[0].cargo }}   ← won't work

Looping through a list

When a field holds multiple items (e.g. several cargo registrations), loop with {{#each}} instead of hardcoding an index:

{{#each Data.[0].Ct_portcallfile.__AdditionalData.cargoRegistration}}
Cargo: {{ this.cargo }}, Quantity: {{ this.quantity }}, BL: {{ this.blNumber }}
{{/each}}

Inside the loop, this refers to the current item. Do not use a .[0] index inside an #each — the loop already iterates every item automatically.


Field names with spaces or special characters

If a field name contains spaces, wrap it in square brackets with single quotes:

✅ Correct:

{{ Data.[0].Ct_portcallfile.['port name'] }}

❌ Incorrect:

{{ Data.[0].Ct_portcallfile.port name }}   ← won't work

The same bracket notation is required for field names containing dashes, dots, or that start with a digit:

✅ Correct:

{{ Data.[0].Ct_portcallfile.['arrival-eta'] }}
{{ Data.[0].Ct_portcallfile.['123status'] }}

Showing a boolean as Yes / No

Booleans render as True / False by default. Use ifEquals to show friendlier text:

{{#ifEquals Data.[0].Ct_portcallfile.__AdditionalData.customer.member true}}
Yes
{{else}}
No
{{/ifEquals}}

Rules to remember

RuleDetail
Array index syntaxAlways .[0], never [0]
Spaces in field namesUse ['field name'] bracket notation
Special chars / leading digitSame bracket notation: ['arrival-eta'], ['123id']
One expression per {{ }}You cannot combine two paths in one expression
No leading $The root context is implied; $.Data.[0]... is not needed
Case-sensitiveeta and ETA are different fields
Missing fieldsReturn a blank value — no error