FreeMarker Document Templates for TrueContext Data
Apache FreeMarker™ is a free template engine owned by the Apache Software Foundation. We’ve incorporated FreeMarker into some of our TrueContext features so that you can dynamically generate text from a submitted record. For example, you can generate a text file or HTTP Request Body. You can also use FreeMarker to create custom layouts for PDF, Word, and HTML documents.
This topic describes how to reference TrueContext data in a FreeMarker template.
Tip:This topic is designed for TrueContext users who have basic scripting and programming skills.
Contents
Available on the Advanced and Enterprise tiers:
What you need to know to use FreeMarker with TrueContext
When you need the full power of a programming language to build templates with sophisticated loop and conditional structures, the Apache FreeMarker Template Language (FTL) can achieve results that other template types can’t. Here’s what you should know before you get started.
Basic scripting and programming concepts
Understanding basic programming concepts—such as variables, if-else conditions, loops, and data structures—will help you understand the FreeMarker Template Language (FTL).
If you want to generate custom PDF, Word, or HTML output, you should know HTML and CSS syntax and coding conventions.
You can find basic programming reference guides and tutorials online.
How to use FreeMarker
The FreeMarker Template Language (FTL) includes a set of data-handling functions known as built-ins and directives. Directives are FTL commands that tell the template engine how to reference and format data. Directives can loop through sequences of data, conditionally show or hide content, and handle errors, for example.
FTL has a specific syntax for the expressions in a template. To learn more about FTL:
- Refer to the Apache FreeMarker Manual.
- Visit the TrueContext Community to post your questions.
The TrueContext data model
To give customers access to the full details of a submitted form, TrueContext creates JSON and XML representations of the data record. TrueContext provides the data structure as a JSON-formatted “tree”. When you build a FreeMarker template, you base the template on the TrueContext data structure.
Although the JSON tree structure is consistent across forms, the actual JSON or XML for a record depends on the form design and the submitted data.
Tip:The data model might include properties for features that aren’t available on your form or tier. Check your template to make sure that you only reference properties that are available and set up on your form.
How to handle incomplete data sets
Some data might not be available for all records, resulting in null or empty values when:
- Optional questions aren’t answered.
- Dispatched records don’t have all values prefilled.
- TrueContext Teamwork TrueContext Teamwork is an Enterprise tier feature that enables mobile users to transfer incomplete forms for other users to complete as part of a multi-user workflow. This can be useful for jobs that require someone else's expertise or that span multiple shifts. records are transferred as “Incomplete”.
Because the tree “nodes” of the data model depend on the design of each form, undefined nodes might result when you:
- Use the same custom layout document with multiple forms.
- Set up Question filtering to hide questions, pages, or sections, or set questions to Hidden on reports. Hiding parts of a form removes the corresponding nodes from the data structure.
Info:If you want your document to handle records that might have null or empty values, set up your template accordingly. The section Handle optional or incomplete data describes how to check for null or empty values and for missing nodes.
The data set that you want to include in your output document
The template engine generates textual output based on templates and input data. For example, you can dynamically generate text for a:
- PDF file, based on HTML and CSS, presented as a detailed report of work performed. You need to know which details from submitted records you want to include in the report.
- JSON, XML, or CSV message that contains data from submitted records to send to a customer or partner integration point. You need to know which data points (answers) to get and the format that’s required for the integration point.
Syntax quick reference
Record metadata
To reference metadata, use the dataRecord
node in your expressions.
Syntax | Example |
---|---|
${dataRecord.key}
|
Returns the unique record number that’s assigned by the TrueContext system. |
Note:For |
Returns the username and numeric identifier, but not the display name. |
Answer values
The TrueContext data model provides a top-level answers
node to simplify how you reference data in a Regular or Side-by-Side section. The answers
node flattens the form structure and uses the question unique IDs (labels) as keys in the key:value pairs. The keys are based on the questions and are specific to each form.
The answers
node syntax is the easiest way to reference data in a Regular or Side-by-Side section.
${dataRecord.pages.pageID.sections.sectionID.answers.uniqueID.question}
Info:If you want to reference answers in a Repeatable Section A Repeatable Section is a subform that contains a set of related questions. The data captured is “repeating”, because the field user can complete the same subform more than once, which creates multiple entries., you must specify the full path to the answer values. The section Answers in a Repeatable Section describes how to use the FreeMarker built-in #list
directive to loop over the values.
Answers with a single value
Syntax | Example |
---|---|
Note:Because our data model uses arrays for all answer values, you must include the array index in brackets ( |
Returns the value of the
|
Answers with multiple values
Some question types—such as Multiselect or attachment-based questions—can have multiple values. Use the #list
directive to get all of the values.
Syntax | Example |
---|---|
<#list answers.uniqueID as variable> ${variable} </#list> |
<#list answers.MultipleAnswers as values> ${values} </#list> Returns a list of submitted values. |
Answers with multiple properties
Some question types have multiple properties, such as Geo Location.
Syntax | Examples |
---|---|
|
Returns the submitted address.
Returns the latitude in decimal degrees. |
Images and other binary content
You can reference the following properties for Image, Sketch Pad, and Signature attachments.
identifier
—The unique attachment identifier in the TrueContext system.filename
—The filename and extension assigned by the TrueContext system.contentType
—The file type, such as image/jpeg or application/pdf.bytes
—The actual content of the attachment, Base64-encoded. In a PDF, Word, or HTML custom layout, displays the image.
Syntax | Examples |
---|---|
${answers.uniqueID[n].property}
|
Returns: d9257339-aa49-4267-98a9-17cc7aaf56ee |
Returns: UploadImage_1.jpg |
|
Returns: image/jpeg |
|
Returns the Base64-encoded content: iVBORw0KGgoAAAANSUhEUgAAAh4AAAIQCAYAAADOyWc…
In a PDF, Word, or HTML custom layout, displays the image.
|
We ignore references to the bytes
property for Audio Recording, Document Editor, and File Upload answers.
Tip:If you want to reference or display uploaded images, set up your form with Image, Sketch Pad, or Signature questions.
Answers in a Repeatable Section
The TrueContext data model treats each “row” in a Repeatable Section as a subform. Each subform has its own pages
, sections
, and answers
nodes.
To reference answers in a Repeatable Section:
- Use the FreeMarker built-in #list directive to loop over the repeatable section.
- Set up expressions to “walk the tree” of the data model hierarchy. The path depends on the node format option that you choose.
Tip:We recommend that you select All Labels as Node Names when you set up your document. This makes it easier and more precise to “walk the tree” of our data model. The following examples are based on this setting.
Syntax | <#list dataRecord.pages.pageID.sections.sectionID.rows as row> <#list row.pages.RowPageID.sections.RowSectionID.answers.uniqueID.values as value> ${value} </#list> </#list> |
Example | <#list dataRecord.pages.NewPage.sections.IncidentCauses.rows as row> <#list row.pages.IncidentCauses.sections.IncidentCauses1.answers.Cause.values as selection> <#list row.pages.IncidentCauses.sections.IncidentCauses1.answers.Details.values as detail> ${selection} - ${detail} </#list> </#list> </#list> Returns, for example: Equipment failure - Belt |
Date, Time, and Date/Time answers
Basic Date/Time syntax
The syntax you use to reference data in a Date/Time Selector or Date/Time Stamp field depends on the data type, as described in the following table.
Info:The examples show the output in the default ISO Date and Time formats. You can change the format using either FreeMarker or DREL Data Reference Expression Language (DREL) is used to get form data and metadata and add it to a string, such as dates, usernames, or answers to questions in forms..
Data type Data types describe the format in which a user answers a question. For example, a user might enter a name (Text) in one question, and a dollar amount (Currency) in another. A data type also supports validation (making sure that mobile users enter a valid email address format, for example). | Syntax | Example |
---|---|---|
Date |
|
Returns, for example: 2024-05-27 |
Time |
|
Returns, for example: 14:00:00+01:00 The default time format uses the 24-hour clock, and |
|
Returns, for example: Europe/London The default format is as per the list of tz database time zones. |
|
|
Returns, for example: 2024-06-04T23:07:00+02:00 This is the |
|
Date/Time |
|
Returns, for example: 2024-05-27T13:15:05+01:00 |
|
Returns, for example: Europe/London The default format is as per the list of tz database time zones. |
|
|
Returns, for example: 2024-06-04T23:07:00+02:00 This is the |
Info:The system returns the date and time in ISO format. The section Date/Time formats describes how you can change the default format.
Date/Time formats
Dates, times, and date/times default to the following formats:
- Date—yyyy-MM-dd
- Time—HH:mm:ssXXX
- Date/Time—yyyy-MM-dd'T'HH:mm:ssXXX
You can change date and time formats using either FreeMarker built-ins or DREL expressions.
Note:If, by mistake, you use a date format for a Time data type or a time format for a Date data type, the system returns a default value. Check that your output Document values are as expected.
FreeMarker
TrueContext returns dates and times as strings. You use the date
, time
, or datetime
built-ins to parse the strings into a date, time, or datetime object. The .xs
format specifier converts the value into the XML Schema date/time format (ISO 8601).
To get the format that you want, use the string
built-in to format the date, time, or datetime object.
Example | Result |
---|---|
${answers.dateTimeIncident[0].provided.time?datetime.xs?string("MM-dd-yyyy hh:mm a z")} |
06-04-2024 02:07 PM PDT |
${answers.DateOnlySelector[0]?date.xs?string("MM-dd-yyyy")} |
06-04-2024 |
${answers.TimeOnlySelect[0].provided.time?time.xs?string("hh:mm a")} |
02:07 PM PDT |
The time zone resolves to the Document Time Zone Source when you use FreeMarker built-ins to format a date, time, or datetime value. In the previous examples, the time zone is displayed as PDT, which is the time zone set for the team (America/Vancouver).
You can set different time zones within your template using the #setting directive, for example:
<#setting time_zone="America/New_York">
This setting only affects dates, times, and datetimes that you format using FreeMarker built-ins. Each time zone setting applies to the data that follows until you reset the time zone with another #setting
directive.
DREL
You can use the DREL method to change the format of a date, time, or datetime.
Info:The topic DREL Complete Reference List contains detailed information about DREL expressions.
Example | Result |
---|---|
<#-- For the data record (not specific answers) --> ${drel("%t[MM-dd-yyyy hh:mm a z]")} <#-- For a specific answer --> ${drel("%a[dateTimeIncident][MM-dd-yyyy hh:mm a zzzz]")} |
06-04-2024 10:09 PM BST 06-04-2024 10:07 PM British Summer Time |
Time zone overrides
FreeMarker time zone setting
You can set different time zones within your template using the #setting directive, for example:
<#setting time_zone="America/New_York">
This setting only affects dates, times, and datetimes that you format using FreeMarker built-ins. Each time zone setting applies to the data that follows until you reset the time zone with another #setting
directive.
Example | Result |
---|---|
<#setting time_zone="America/New_York"> ${answers.dateTimeIncident[0].provided.time?datetime.xs?string("MM-dd-yyyy hh:mm a z")} |
06-04-2024 05:07 PM EDT |
DREL time zone settings
You can use the DREL method to set the time zone to a specific value or to one of the following values:
- DataRecordTZ: Time zone on the user’s device.
- TeamTZ: Time zone configured at the team level.
- Region/City: A specific time zone. You can use any of the names in the list of tz database time zones.
Example | Result |
---|---|
${drel("%a[dateTimeIncident][MM-dd-yyyy hh:mm a z][America/Toronto]")}
|
06-04-2024 05:07 PM EDT |
${drel("%a[dateTimeIncident][MM-dd-yyyy hh:mm a z][TeamTZ]")}
|
06-04-2024 02:07 PM PDT |
Shifted time
The shifted
time depends on the Document Time Zone Source, as described in the following table. The examples show the UTC offset for each time zone.
Note:The device time zone refers to the device setting, not the user profile locale settings in the TrueContext Mobile App account details.
If the Document Time Zone Source is set to… | Then the shifted time is in the… |
Examples |
---|---|---|
Form Submission | Device time zone, which is the provided time. In this case, the provided time and the shifted time are the same. |
Date Time of Incident - provided time: 2024-06-04T22:07:00+01:00 Date Time of Incident - shifted: 2024-06-04T22:07:00+01:00 |
Team Preference Setting |
Team time zone |
Date Time of Incident - provided time: 2024-06-04T22:07:00+01:00 Date Time of Incident - shifted: 2024-06-04T14:07:00-07:00 |
Custom | The custom time zone that you specify |
Date Time of Incident - provided time: 2024-06-04T22:07:00+01:00 Date Time of Incident - shifted: 2024-06-04T23:07:00+02:00 |
Pages and sections
You can use the FreeMarker built-in #if directive to conditionally skip a section of the template. This provides a way to show or hide content, for example.
To reference specific pages and sections, set up expressions to “walk the tree” of the data model hierarchy. The path depends on the node format option that you choose.
Tip:We recommend that you select All Labels as Node Names when you set up your document. This makes it easier and more precise to “walk the tree” of our data model. The following examples are based on this setting.
Syntax | Example |
---|---|
<#if answers.uniqueID?has_content> ${dataRecord.pages.pageID.sections.sectionID.property} <#list dataRecord.pages.pageID.sections.sectionID.rows as row> <#list row.pages.RowPageID.sections.RowSectionID.answers.uniqueID.values as value> ${value} </#list> </#list> </#if> |
<#if answers.KnownCause?has_content> ${dataRecord.pages.NewPage.sections.IncidentCauses.name} <#list dataRecord.pages.NewPage.sections.IncidentCauses.rows as row> <#list row.pages.IncidentCauses.sections.IncidentCauses1.answers.Cause.values as selection> <#list row.pages.IncidentCauses.sections.IncidentCauses1.answers.Details.values as detail> ${selection} - ${detail} </#list> </#list> </#list> </#if> Returns…
|
drel( ) method
Data Reference Expression Language (DREL) is a TrueContext proprietary language used to reference data from a submitted record.
You can use the drel()
method to get data and metadata from a submitted record.
Syntax | Example |
---|---|
|
Returns: Display value: Good This example returns the display value instead of the server value for this options-based question. Tip:You can include static text in your DREL expressions. This example includes the static text |
Info:The topic DREL Complete Reference List describes all the available DREL references and properties.
Handle optional or incomplete data
Some data might not be available for all records, resulting in null or empty values when:
- Optional questions aren’t answered.
- Dispatched records don’t have all values prefilled.
- TrueContext Teamwork records are transferred as “Incomplete”.
Because the tree “nodes” of the data model depend on the design of each form, undefined nodes might result when you:
- Use the same custom layout document with multiple forms.
- Set up Question filtering to hide questions, pages, or sections, or set questions to Hidden on reports. Hiding parts of a form removes the corresponding nodes from the data structure.
Note:If the template expects a value that’s not in the data, document generation might fail. If you want your document to handle records that might have null or empty values, set up your template accordingly.
You can handle null or empty answers in one of two ways:
- Use the
!
null operator to check if the answer is null or empty.If the answer is null or empty, the document displays the characters inside the quotation marks. To display nothing, don’t specify any text:
${(answers.uniqueID[n])!""}
If the answer has a value, the document displays the value.
- Use the #if directive when you need to do more complex checks. For example, you might need to handle multiple conditions or include additional actions based on whether the value exists.
The following table provides some example syntax you can use to handle null or empty data.
Syntax | Example |
---|---|
|
Returns, if answered: Lestrade Returns, if null or empty: Not answered |
<#if answers.uniqueID?has_content> Text: ${answers.uniqueID[0]}. <#else> Text </#if> |
<#if answers.Inspector?has_content && answers.SeniorTechnician?has_content> The names of the inspectors are ${answers.Inspector[0]} and ${answers.SeniorTechnician[0]}. <#elseif answers.Inspector?size == 0 && answers.SeniorTechnician?has_content> The name of the senior technician is ${answers.SeniorTechnician[0]}. <#elseif answers.Inspector?has_content && answers.SeniorTechnician?size == 0> The name of the inspector is ${answers.Inspector[0]}. <#else> No inspector information available. </#if> Returns…
|
<#if answers.uniqueID??> <#if answers.uniqueID?has_content> ${answers.uniqueID[0]} <#else> Answer not provided </#if> <#else> Referenced answer is not part of this record </#if> |
<#if answers.Inspector??> <#if answers.Inspector?has_content> ${answers.Inspector[0]} <#else> Answer not provided </#if> <#else> The answer to "Inspector" is not part of this record. </#if> You can use the same document for more than one form. Remember that the structure of the data model will be the same across forms, but the specific nodes might be different. This example shows how to check for undefined nodes and for null or empty values. Tip:This example also checks for missing answer nodes that result from question filtering or questions set to Hidden on reports. Returns…
|
Note:TrueContext does not support the FreeMarker attempt/recover
directive.
Escape special characters
Special characters or line breaks in the data could result in a document that’s not valid for your cloud system or endpoint. Follow the instructions in the topic Escape Special Characters and Line Breaks for Template-driven Text Documents.
Unsupported functions
For security reasons, the system prevents the use of the include
and import
functions in a TrueContext FreeMarker template. If the system detects those functions, it removes them from the template.
Components of the TrueContext data model
Record metadata
The dataRecord
(root) node contains all of the data and metadata from the submitted record. The dataRecord
node properties include the unique identifier, name, and dates submitted and processed, for example. Child nodes contain geo stamp (geotag) and device details.
Form and FormSpace information
The form
child node has properties that can help you identify the Form Definition A Form Definition is a template for an actual form or record that field users interact with. Using the Form Builder, you define the structure, layout, fields and data types, and logic of a form. A Form Definition also specifies resources available to users on their devices, such as Images and Documents, and mappings for data brought in from external sources. and version, as well as the FormSpace FormSpaces are where forms are stored and organized in the TrueContext Web Portal. A TrueContext Team may have multiple FormSpaces, depending on their needs. Admins can set FormSpace permissions to control which users have access to the forms in that FormSpace. it’s in.
User information
The user
child node properties tell you who submitted, transferred, or edited the record.
The “answers” node
The JSON tree structure follows the structure of the Form Definition. There are nodes for pages, sections, and answers (fields).
The TrueContext data model provides a top-level answers
node to simplify how you reference data in a Regular or Side-by-Side section. The answers
node flattens the form structure and uses the field unique IDs (labels) as keys in the key:value pairs. The keys are based on the questions set up in the Form Definition and are specific to each form.
Note:The system strips out spaces from the unique IDs and truncates them if they’re longer than 19 characters. Use the keys exactly as shown in the data model, not as shown in the Form Builder.
The answers.uniqueID
syntax is the easiest way to reference data in a Regular or Side-by-Side section.
${dataRecord.pages.pageID.sections.sectionID.answers.uniqueID.question}
Sections
Different types of sections have different JSON representations, as shown in the following table.
Section type | JSON identifier | Node structure |
---|---|---|
Regular | Flow | "sections": [ { "type": "Flow", "label": "QuestionsPush", "name": "Questions to push from", "answers": [ |
Side-by-Side | QuestionTextColumn | "sections": [ { "type": "QuestionTextColumn", "label": "Job Information", "name": "Job Information", "answers": [ |
Repeatable (or “Repeating”) | Repeat | "sections": [ { "type": "Repeat", "label": "Subform", "name": "Subform", "rows": [ { "pages": [ { "label": "Subform", "name": "Subform", "sections": [ { "type": "Flow", "label": "Subform 1", "name": "Subform", "answers": [ |
Node format options
When you set up your FreeMarker output document, you can choose how the nodes in the JSON tree are named and structured. This helps you align the data model with the requirements of your ecosystem.
Choose one of the following options:
-
Standard—This option provides the form elements in an array that you can loop over. Use this option when you want to apply generic logic to all elements of your form.
-
All Labels as Node Names—Uses the page, section, and answer unique IDs (labels) instead of the generic names.
Tip:This option gives you precise labels you can use to reference specific nodes in the submitted record. Use this option when you want to place specific answers in specific places in your template output. The examples in this topic all use this setting.
-
Flat Answer List—Changes the hierarchical tree structure into a flat data structure (list). Use this option when you want to loop over answers and don’t need to reference the full form structure (pages, sections, or Repeatable Sections).
Build an FTL template
High-level process
Stage | Description |
---|---|
Get the TrueContext data model |
This gives you the structure that you need to build your template. You can change the naming of tree nodes as needed. There are two ways that you can get the data model for a FreeMarker text document:
For a FreeMarker PDF, Word, or HTML custom layout, the Custom Document Editor, Reference Data tab displays the JSON data model. Tip:The structure of a JSON record can vary widely, even for a single form. The data submitted by field users depends on Conditional Logic, optional questions, and Answer Exceptions An Answer Exception is a form feature that displays color-coded feedback when a mobile user selects or enters an answer. Answer Exceptions typically show an inspection status (pass/fail) or prompt the user for additional information. Color-coding notifies the user of the Exception's severity., for example. To avoid errors, build a template that can handle the variability of submitted records. |
Choose a document type and set up the basics |
FreeMarker templates work with the following document types:
Document basics include the:
|
Configure the Document and add the FreeMarker template |
|
Test your Document |
There are a few different ways you can test your document:
Info:To save time when testing a document with actual data, dispatch the record using the TrueContext REST API. Set up a Request Body and reuse it for testing. The API documentation provides instructions and examples of how to set up an API dispatch. |
Steps to build an FTL template for a FreeMarker text document
-
Open a text editor to start building your FreeMarker template.
-
In TrueContext, go to Forms & Integrations > Documents > Create Document. In the Template-driven Text Documents section, select FreeMarker.
-
On the Document Basics tab, enter the Name and Filename.
-
On the Configuration tab, enter the document details.
- FreeMarker templates work with the default settings for Data Node Format and Content Type. You don’t need to change these.
-
Data Node Format
A FreeMarker template is based on the “tree” structure of our JSON Form Definitions. The Data Node Format setting changes the structure and naming of the page, section, and answer nodes.
Choose one of the following options:
-
Standard—This option provides the form elements in an array that you can loop over. Use this option when you want to apply generic logic to all elements of your form.
-
All Labels as Node Names—Uses the page, section, and answer unique IDs (labels) instead of the generic names.
Tip:This option gives you precise labels you can use to reference specific nodes in the submitted record. Use this option when you want to place specific answers in specific places in your template output. The examples in this topic all use this setting.
-
Flat Answer List—Changes the hierarchical tree structure into a flat data structure (list). Use this option when you want to loop over answers and don’t need to reference the full form structure (pages, sections, or Repeatable Sections).
-
-
File Extension
Enter the extension for the output file you want to create. For example, enter
txt
orjson
. Make sure the extension works with your endpoint or integration system. -
Content Type
This specifies the kind of data contained in the output file. This helps to ensure that the correct application or method is used to view or process the data.
-
FreeMarker Template
View Template Input to download a JSON file that shows the data model for a specific Form Definition. You can view the input when you create or edit a Document, or after you save it. In your text editor, use this data model as a reference to build your FTL code.
Tip:You can start with a very simple template and build on it later. For example, start with a single expression, such as:${dataRecord.identifier}
Save the file as
.ftl
.
-
Select Choose File, and then select your FTL file.
-
(Optional) Preview the output. Are the results as expected?
- If yes, go to step 7.
- If no, you can fix the FTL file now or after you save the Document.
-
Select Create to save the FreeMarker Document.
Get the TrueContext data model
-
Go to the FreeMarker Document, and then select View Template Input. You can view the input when you create or edit the Document, or after you save it.
-
Select a Target Form. This should be the form that you want to link to the FreeMarker document.
-
Select Show Template Input.
Result: The system generates and downloads a JSON file that contains sample data. Use this view of the tree structure to set up your FreeMarker template.
Info:For examples of how to reference the data in your template, refer to the Syntax quick reference.
Tip:The data model might include properties for features that aren’t available on your form or tier. Check your template to make sure that you only reference properties that are available and set up on your form.
The following example also shows how to reference answers that have additional properties:
Note:Test your template thoroughly with actual data from submitted forms.For security reasons, the system prevents the use of the
include
andimport
functions in a TrueContext FreeMarker template. If the system detects those functions, it removes them from the template.
Basic example of template and output
If the FreeMarker template contains this content:
Username: ${dataRecord.user.username!""} ID: ${dataRecord.user.identifier!""} Data record A Data Record is a dispatched or submitted form, or a form saved as a draft on the user's device. Each data record has an associated reference number - a dataRecordID on the server and a clientDataRecordID on the device. ID: ${dataRecord.identifier!""} First: ${answers.firstName[0]!""} Middle: ${answers.middleName[0]!""} Last: ${answers.lastName[0]!""} Date Time of Incident - provided time: ${answers.dateTimeIncident[0].provided.time!""} Date Time of Incident - provided zone: ${answers.dateTimeIncident[0].provided.zone!""} Location of Incident - ${answers.locationOfIncident[0].address!""} Location of Incident - latitude - ${answers.locationOfIncident[0].coordinates.latitude!""} Location of Incident - longitude - ${answers.locationOfIncident[0].coordinates.longitude!""}
The output file looks like this:
Username: holmes ID: 123456789 Data record ID: 18000000000 First: John Middle: Alex Last: Smith Date Time of Incident - provided time: 2024-04-24T17:18:00-04:00 Date Time of Incident - provided zone: America/Toronto Location of Incident - 1234 Mystreet, Ottawa, ON A2B 3C4, Canada Location of Incident - latitude 45.3474 Location of Incident - longitude -75.9189