Kodjin Data Mapper
Data Mapper is a part of Kodjin interoperability suite. It is a service that implements data conversion from proprietary and legacy formats to FHIR format. Currently, it supports four types of conversions: JSON to FHIR, HL7v2 to FHIR, C-CDA to FHIR and FHIR STU3 to R4.
This operation requires the following SMART on FHIR scopes:
- system|user|patient/kodjin/DataMapperTemplate.read
- system|user|patient/kodjin/DataMapperTemplate.write
You can read more about smart-on-FHIR scopes on SMART on FHIR Authorization page
Endpoints
-
POST
[fhir_base]/$convert-data
-
GET, POST, PUT, DELETE
[fhir_base]/templates/[template_name]
Query parameters
Query parameter | Type | Status | Description |
---|---|---|---|
template | string | implemented | The id of the template used for conversion |
data | json object | implemented | The actual data to be converted |
Overview
- Kodjin data mapper is implemented using Liquid template engine.
- there're CRUD operations on templates and the ability to store the templates in GitHub repo similarly to the FHIR conformance resources.
The example of the template
{
"resourceType": "Patient",
"id": "{{ PatientId | to_json_string | generate_uuid }}",
"identifier": [
{
"use": "usual",
"type": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "MR"
}
]
},
"system": "urn:oid:2.16.840.1.113883.19.5",
"value": "{{ MRN }}"
}
],
"active": true,
"name": [
{
"family": "{{ LastName }}",
"given": [
"{{ FirstName }}"
]
}
],
"gender": {% if Gender == 'M' -%}
"male",
{% elsif Gender == 'F' -%}
"female",
{% elsif Gender == 'U' -%}
"unknown",
{% elsif code -%}
"other",
{% else %}
"",
{% endif -%}
"birthDate": "{{ DOB | add_hyphens_date }}",
"managingOrganization": {
"reference": "Organization/2.16.840.1.113883.19.5",
"display": "Good Health Clinic"
}
}
Filters
By default, Liquid provides a set of standard filters to assist template creation. Besides these filters, Kodjin data mapper also provides some other filters that are useful in conversion, which are listed below.
Hl7v2 specific filters
Filter | Description | Syntax |
---|---|---|
get_first_segments | Returns first instance of the segments | {% assign result = hl7v2Data \| get_first_segments: 'segment1\|segment2\|...' -%} |
get_segment_lists | Extracts HL7 v2 segments | {% assign result = hl7v2Data \| get_segment_lists: 'segment1\|segment2\|...' -%} |
get_related_segment_list | Given a segment and related segment name, returns the collection of related named segments | {% assign result = hl7v2Data \| get_related_segment_list: parentSegment, 'childSegmentName' -%} |
get_parent_segment | Given a child segment name and overall message index, returns the first matched parent segment | {% assign result = hl7v2Data \| get_parent_segment: 'childSegmentName', 3, 'parentSegmentName' -%} |
has_segments | Checks if HL7 v2 message has segments | {% assign result = hl7v2Data \| has_segments: 'segment1\|segment2\|...' -%} |
split_data_by_segments | Given an HL7 v2 message and segment name(s) as the separator(s), returns the message list split by separator(s). Note: Each segment separator will be retained as the first segment of each message in the list, while the segments before the first separator (which may be empty) will be retained as the first message in the list without any separator. |
{% assign result = hl7v2Data \| split_data_by_segments: 'segment1\|segment2\|...' -%} |
C-CDA specific filters
Filter | Description | Syntax |
---|---|---|
get_first_ccda_sections | Returns first instance (non-alphanumeric chars replace by '_' in name) of the sections | {% assign firstSections = msg \| get_first_ccda_sections: 'Problems' -%} |
get_ccda_section_lists | Returns instance list (non-alphanumeric chars replace by '_' in name) for the given sections | {% assign sections = msg \| get_ccda_section_lists: 'Problems' -%} |
get_first_ccda_sections_by_template_id | Returns first instance (non-alphanumeric chars replace by '_' in name) of the sections by template id | {% assign firstSections = msg \| get_first_ccda_sections_by_template_id: '2.16.840.1.113883.10.20.22.2.5.1' -%} |
String Filters
Filter | Description | Syntax |
---|---|---|
char_at | Returns char at position index | {{ 'foo' \| char_at: 0 }} #=> 'f' |
contains | Returns true if a string includes another string | {{ 'foo' \| contains: 'fo' }} #=> true |
escape_special_chars | Returns string with special chars escaped | {{ '\E' \| escape_special_chars }} #=> '\\E' |
unescape_special_chars | Returns string after removing escaping of special char | {{ '\\E' \| unescape_special_chars }} #=> '\E' |
match | Returns an array containing matches with a regular expression | {% assign m = code \| match: '[0123456789.]+' -%} |
to_json_string | Converts to JSON string | {% assign msgJsonString = msg \| to_json_string -%} |
to_double | Converts string to double | {{ "100.01" \| to_double }} |
base64_encode | Returns base64 encoded string | {{ decodedData \| base64_encode }} |
base64_decode | Returns base64 decoded string | {{ encodedData \| base64_decode }} |
sha1_hash | Returns SHA1 hash (in hex) of given string | {{ inputData \| sha1_hash }} |
gzip | Returns compressed string | {{ uncompressedData \| gzip }} |
gunzip_base64_string | Returns decompressed string | {{ compressedData \| gunzip_base64_string }} |
Math filters
Filter | Description | Syntax |
---|---|---|
is_nan | Checks if the object is not a number | {{ true \| is_nan }} #=> true |
abs | Returns the absolute value of a number | {{ -2019.6 \| abs }} #=> 2019.6 |
pow | Returns the base to the exponent power, that is, base^exponent | {{ 3 \| pow: 3 }} #=> 27 |
random | Returns a non-negative random integer that is less than the specified maximum. | {{ 100 \| random }} #=> 52 |
sign | Returns either a positive or negative +/- 1, indicating the sign of a number passed into the argument. If the number passed into is 0, it will return a 0. Note that if the number is positive, an explicit (+) will not be returned | {{ -5 \| sign }} #=> -1 |
truncate_number | Returns the integer part of a number by removing any fractional digits | {{ -34.53 \| truncate_number }} #=> -34 |
divide | Divides first number by the second number and return a double | {{ 5 \| divide: 2 }} #=> 2.5 |
DateTime filters
Filter | Description | Syntax |
---|---|---|
add_hyphens_date | Adds hyphens to a date or a partial date that does not have hyphens to make it into a valid FHIR format. The input date format is YYYY, YYYYMM, or YYYYMMDD. The output format is a valid FHIR date or a partial date format: YYYY, YYYY-MM, or YYYY-MM-DD. | {{ PID.7.Value \| add_hyphens_date }} |
format_as_date_time | Converts valid HL7v2 and C-CDA datetime to a valid FHIR datetime format. The input datetime format is datetime or partial datetime without hyphens: YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ]. For example, the input 20040629175400000 will have the output 2004-06-29T17:54:00.000Z. Provides parameters to handle different time zones: preserve, utc, local. The default method is preserve. | {{ PID.29.Value \| format_as_date_time: 'utc' }} |
now | Provides the current time in a specific format. The default format is yyyy-MM-ddTHH:mm:ss.FFFZ. | {{ '' \| now: 'dddd, dd MMMM yyyy HH:mm:ss' }} |
add_seconds | Adds double seconds on a valid FHIR datetime (e.g.2021-01-01T00:00:00Z). Provides parameters to handle different time zones: preserve, utc, local. The default method is preserve. | {{ "2021-01-01T00:00:00Z" \| add_seconds:100.1, 'utc' }} |
Collection filters
Filter | Description | Syntax |
---|---|---|
to_array | Returns an array created (if needed) from given object | {% assign authors = msg.ClinicalDocument.author \| to_array -%} |
concat | Returns the concatenation of provided arrays | {% assign ethnicCodes = ethnicCodes1 \| concat: ethnicCodes2 -%} |
batch_render | Render every entry in a collection with a snippet and a variable name set in snippet | {{ firstSections.2_16_840_1_113883_10_20_22_2_5_1.entry \| to_array \| batch_render: 'Entry/Problem/entry', 'entry' }} |
Miscellaneous filters
Filter | Description | Syntax |
---|---|---|
get_property | Returns a specific property of a coding with mapping file CodeSystem.json | {{ PID.8.Value \| get_property: 'CodeSystem/Gender', 'code' }} |
generate_uuid | Generates an ID based on an input string | {% assign patientId = firstSegments.PID.3.1.Value \| generate_uuid -%} |
generate_id_input | Generates an input string for generate_uuid with 1) the resource type, 2) whether a base ID is required, 3) the base ID (optional) | {{ identifiers \| generate_id_input: 'Observation', false, baseId \| generate_uuid }} |
concept_map_translate | translates the code from source to target using $translate operation on ConceptMap | {{ Code \| concept_map_translate: id: 'icd10-to-icd9, system: 'http://hl7.org/fhir/sid/icd-10-cm', target_system: 'http://terminology.hl7.org/CodeSystem/icd9' }} |
Tags
By default, Liquid provides a set of standard tags to assist in template creation. Besides these tags, FHIR Converter also provides some other tags useful in conversion, which are listed below. If these tags do not meet your needs, you can write your own tags.
Tag | Description | Syntax |
---|---|---|
evaluate | Evaluates an ID with an ID generation template and input data | {% evaluate patientId using 'Utils/GenerateId' obj:msg.ClinicalDocument.recordTarget.patientRole -%} |
mergeDiff | Merge diff JSON on input JSON data. The input data and difference in content should be a valid JSON format. | {% mergeDiff msg -%} <diff json> {% endmergeDiff -%} |
Data mapper API
Create a new template
To upload a new template for Kodjin data mapper through the API, use a POST request to the endpoint:
Where:
fhir_base
- the base url of Kodjin FHIR Servertemplate_name
- a name for identifying the templatetemplate_type
- a type of the template. Possible values include:json
,html
,common
(starting from Kodjin FHIR Server version 4.6.0)templates
- is a configurable path in Kodjin data mapper configuration (template
used by default Kodjin configuration)
The request body should contain the template code.
Starting from Kodjin FHIR Server version 4.6.0, there have been changes to the creation of new templates through the Kodjin data mapper API
How to create a new template
curl --location 'https://demo.kodjin.com/templates/ADT_X10?type=html' \
--header 'content-type: application/json' \
--data '<html>
<head>
<title>
This is a demo HTML TEMPLATE
</title>
</head>
<body>
<div>Patient ID {{ msg.PatientId }}</div>
<h1>Patient Name</h1>
<div> Family: {{ msg.LastName }} </div>
<div> Name: {{ msg.FirstName }} </div>
<h1>Gender</h1>
<div> {{msg.Gender}} </div>
<div>
<h1>Telecom</h1>
{% for p in msg["Phone Number"] -%} {
"system": "phone",
"value": "{{ p }}"
}
{% endfor -%}
</div>
</body>
</html>'
Post-processing for json template types
Templates with a json type will undergo post-processing, while html or other types will not. See details about post-processing in the section below.
Try Kodjin data mapper with our Kodjin FHIR Server Postman Collection
Update a template
To update an existing template for Kodjin data mapper through the API, use a PUT request to the endpoint:
Where:
fhir_base
- the base url of Kodjin FHIR Servertemplate_name
- a name for identifying the templatetemplate_type
- a type of the template. Possible values include:json
,html
,common
(starting from Kodjin FHIR Server version 4.6.0)
The request body should contains an updated template.
Get a template by id
To retrieve a template, send a GET request with the template name that was used to create the template.
How to get a template through API:
Delete a template
To delete a template send a DELETE request with the template name that was used to create the template.
How to delete a template through API:
JSON post processing
When a json-type template is rendered or inbound data is transformed using a json-type template, Kodjin data mapper will apply post-processing to the rendered object. This includes:
- Removing trailing commas
- Removing empty objects
- Removing empty lines
- Removing repeated objects with the same attributes.