# CDA Export Tutorial - Generating Narrative text

When generating a CDA Document using the CDA Exchange+ module a narrative is generated to populate the `<text>` element of each section.

This narrative can be edited to display the information necessary from the various resources it consists of.

This tutorial aims to help you familiarise yourself with the various ways narrative generation occurs in the CDA Exchange+ Module and how it can be customized to suit your needs. A global overview of all the features can also be found [here](/content/docs/cda_exchange_plus/narrative_generation.html).

## Default behaviour

By default, if the `Composition.section.text` has been populated (be it manually or via generation) it will use its contents to populate the `<text>` element for the corresponding CDA section. Generally, this generated narrative will appear as a simple tabular summary of the most relevant fields of the entries.

**Overriding the default narrative templates**
If the simple tabular summary is not sufficient, custom templates can be uploaded to use instead; these will override the default narrative templates using the Narrative Generator module. The following setup should be followed:
**Configure a Narrative Generator Module**
**Properties file:**

```txt
module.narrative_generator.type=NARRATIVE_GENERATOR
module.narrative_generator.config.manifest_file={path_to_cda-narratives.properties}
```

Copy

**Yaml file**:

```yaml
{module_id}:
	name: Narrative Generator
	enabled: true
	type: NARRATIVE_GENERATOR
	config:
		manifest_file: {path_to_cda-narratives.properties}
```

Copy

`Path_to_cda-narratives.properties` is the location of the cda-narratives.properties file, this can be on the `classpath:` but can also be found via a local file path using `file:/path/to/file.txt`. How this file is set up can be found later in the tutorial.

Generally speaking it’s good practice to put this file in the `config_seeding` folder in the `classes/` folder, Ie. `classpath:config_seeding/cda-narrative.properties`

Once this file has been loaded, the `CDA Exchange+ Module` needs to be updated with a Dependency to the `Narrative Generator` module.
**cda-narrative.properties**
The cda-narrative.properties file specifies where the narrative generator module can find the templates for each section. Every section will require the following format:

```txt
{resource}.resourceType = Bundle
{resource}.tag = {resource_tag}
{resource}.narrative = {path-to-resource-html}
```

Copy

The `resource_tag` corresponds with the code value of the section as defined by the  [CDA Specification](https://build.fhir.org/ig/HL7/CDA-ccda-2.2/StructureDefinition-2.16.840.1.113883.10.20.22.2.17.html) . Generally speaking there should be a specific LOINC code associated with the section.

The `resource.html` will be a thymeleaf template that indicates what needs to be generated. This will be discussed in the next section.

It is recommended to put the `resource.html` files in the same `config_seeding/` folder as the `cda-narratives.properties` file. Ie. `classpath:config_seeding/resource.html`

**resource.html**
The html for each FHIR resource is written in Thymeleaf and uses FhirPath to select which part of the resource needs to be displayed.
**Thymeleaf Example - Encounter**
Below is an example of a Thymeleaf template for Encounter resources. It will display the resources via a table with the following fields: title, status, class, type, priority, period, location and participant.

1. Each narrative gets a Bundle as input

2. Using `<th:block th:each=”entry : ${resource.entry}” th:object=”${entry.getResource()}”>` will unpack each resource from the Bundle Entries

the resource can be retrieved from the entry and `<th:block th:if="*{getResourceType().name() == 'Encounter'}">` is used to validate that this template only triggers on Encounter resources.

```html
<th:block th:each="entry : ${resource.entry}" th:object="${entry.getResource()}">
   <th:block th:if="*{getResourceType().name() == 'Encounter'}">
```

Copy

Once the Encounter resource has been established, FhirPath queries can be leveraged to traverse the resource and resolve references. For example:

```html
<td th:text="*{getDiagnosis().isEmpty() != true ? #fhirpath.evaluate(#object, 'diagnosis.condition.resolve().code.coding[0].display')[0] : 'No Diagnosis'}">Title</td>
```

Copy

The above snippet will populate the <td> element with the Diagnosis, it will first check if the diagnosis field is not empty (`getDiagnosis().isEmpty())`, after that, it uses FhirPath to find the `condition,`resolves the Reference to a Condition/Procedure and retrieve the first occurring `coding.display`, if the diagnosis is empty `No Diagnosis` is displayed.

For more information on how to use Fhirpath:  [here](https://www.hl7.org/fhirpath/)

The full Encounter resource Thymeleaf below can serve as a starting point when creating your own templates

## Sample of Encounter resource Thymeleaf:

```html
<div xmlns:th="http://www.thymeleaf.org">
   <h5>Encounters</h5>

<table>
      <thead>
      <tr>
         <th>Title</th>
         <th>Status</th>
         <th>Class</th>
         <th>Type</th>
         <th>Priority</th>
         <th>Period</th>
         <th>Location</th>
         <th>Participant</th>
      </tr>
      </thead>
      <tbody>
      <th:block th:each="entry : ${resource.entry}" th:object="${entry.getResource()}">
         <th:block th:if="*{getResourceType().name() == 'Encounter'}">
            <tr>
               <td th:text="*{getDiagnosis().isEmpty() != true ? #fhirpath.evaluate(#object, 'diagnosis.condition.resolve().code.coding[0].display')[0] : 'No Diagnosis'}">Title</td>
               <td th:text="*{getStatus() ? getStatus().getDisplay() : ''}">Status</td>
               <td th:text="*{getClass() ? getClass().get(0).getDisplay() : ''}">Class</td>
               <td th:text="*{getType() ? getType().get(0).getDisplay() : ''}">Type</td>
               <th:block th:if="*{hasPriority()}">
                  <td th:text="*{getPriority() ? getPriority().get(0).getDisplay() : ''}">Priority</td>
               </th:block>
               <th:block th:unless="*{hasPriority()}">
                  <td></td>
               </th:block>
               <th:block th:if="*{hasPeriod()}">
                  <td th:text="*{#strings.concatReplaceNulls('', getPeriod().getStartElement().getValueAsString(), ' - ', getPeriod().getEndElement().getValueAsString())}">Period</td>
               </th:block>
               <th:block th:unless="*{hasPeriod()}">
                  <td></td>
               </th:block>
               <th:block th:if="*{hasLocation()}">
                  <th:block th:with="location = ${#fhirpath.evaluateFirst(#object, 'location[0].location.resolve()')}">
                     <th:block th:if="${location != null}">
                        <td th:text="~{location ? getName() : ''}">Location</td>
                     </th:block>
                     <th:block th:unless="${location != null}">
                        <td></td>
                     </th:block>
                  </th:block>
               </th:block>
               <th:block th:unless="*{hasLocation()}">
                  <td></td>
               </th:block>
               <th:block th:if="*{hasParticipant()}" th:fragment="renderParticipantRef(encounter)">
                  <td th:text="${#fhirpath.evaluate(#object, 'participant[0].individual.reference.resolve().name[0].family')[0]} + ', ' + ${#fhirpath.evaluate(#object, 'participant[0].individual.reference.resolve().name[0].given[0]')[0]}" >Participant</td>
               </th:block>
               <th:block th:unless="*{hasParticipant()}">
                  <td></td>
               </th:block>
            </tr>
         </th:block>
      </th:block>
      </tbody>
   </table>
</div>
```

Copy

[CDA Export Tutorial](/content/docs/guide_tutorials/tutorial_cda_export.html)

CDA Export - Custom Narrative Generation Tutorial

Tutorials

[Introduction](/content/docs/guide_tutorials/tutorial_intro.html)
[Integration Testing Tutorial](/content/docs/guide_tutorials/tutorial_integration_test.html)
[Custom Operations Tutorial](/content/docs/guide_tutorials/tutorial_custom_operations.html)
[HL7 v2.x Ingestion Tutorial](/content/docs/guide_tutorials/tutorial_processing_hl7_v2x_feeds.html)
[Federated OAuth2/OIDC Tutorial](/content/docs/guide_tutorials/tutorial_federated_oauth2.html)
[MDM Tutorial](/content/docs/guide_tutorials/tutorial_mdm.html)
[MDM UI Tutorial](/content/docs/guide_tutorials/tutorial_mdm_ui.html)
[MDM First Golden Resource Tutorial](/content/docs/guide_tutorials/first_golden_resource.html)
[MDM Advanced Rule Authoring Tutorial](/content/docs/guide_tutorials/advanced_rule_authoring.html)
[MDM Web UI Admin Setup Tutorial](/content/docs/guide_tutorials/mdm_web_ui_admin_setup.html)
[CDA Import Tutorial](/content/docs/guide_tutorials/tutorial_cda_import.html)
[CDA Export Tutorial](/content/docs/guide_tutorials/tutorial_cda_export.html)
[CDA Export - Custom Narrative Generation Tutorial](/content/docs/guide_tutorials/tutorial_cda_export_narrative_generation.html)
[CDA Import JSON example](/content/docs/guide_tutorials/tutorial_cda_import_json.html)
[CDA Export Template JSON example](/content/docs/guide_tutorials/tutorial_cda_export_json.html)
[Consent Tutorial](/content/docs/guide_tutorials/tutorial_consent.html)
[CMS-0057-F IG Setup Tutorial](/content/docs/guide_tutorials/tutorial_terminology_cms57f.html)

[CDA Import JSON example](/content/docs/guide_tutorials/tutorial_cda_import_json.html)
