android-fhir

Use ResourceMapper

Mapping FHIR Questionnaire Responses to other FHIR resources (and back) allows the structured data capture process to be more tightly integrated with clinical workflows.

For example, if your application has a questionnaire for new patient registration, your ultimate goal may be to create a FHIR Patient resource based on the answers provided to use in your application. Or, if your application has a questionnaire for entering test results, you could create a FHIR Observation resource. The process of mapping a FHIR QuestionnaireResponse to one or more other FHIR resources is called extraction.

On the other hand, you may want to reduce data entry by loading values from existing FHIR resources into your questionnaire. For example, if a questionnaire asks for a patient’s name and age, you can pre-populate that information from an existing FHIR Patient resource. The process of mapping one or more FHIR resources to a FHIR QuestionnaireResponse is called population.

This section shows how to use the ResourceMapper class from the Structured Data Capture Library to perform extraction and population.

Extract FHIR resources from a questionnaire response

The Structured Data Capture Library supports two mechanisms for data extraction: Definition-based extraction and StuctureMap-based extraction.

Both methods of extraction require a HAPI FHIR Questionnaire that includes data extraction FHIR extensions, plus a corresponding QuestionnaireResponse containing the answers to extract. You can use HAPI FHIR’s JsonParser.parseResource() from FhirContext.newJsonParser() to deserialize your JSON content to a questionnaire:

val jsonParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser()

// From a JSON string
val myQuestionnaire =
    jsonParser.parseResource(questionnaireJsonString) as Questionnaire

// From a URI for a JSON file
val myQuestionnaire =
    jsonParser.parseResource(contentResolver.openInputStream(questionnaireUri)) as Questionnaire

The QuestionnaireResponse you use with data extraction is likely from calling QuestionnaireFragment.getQuestionnaireResponse() after your user fills out a questionnaire:

val myQuestionnaireResponse = fragment.getQuestionnaireResponse()

Learn more about QuestionnaireFragment and how to collect responses from a questionnaire.

Next, call ResourceMapper.extract() to extract the FHIR resources. It returns a HAPI FHIR Bundle containing one or more FHIR resources as specified by the data extraction FHIR extensions in the questionnaire. Note that ResourceMapper.extract() is a suspend function, so the following examples must be called from an appropriate coroutine, such as ViewModelScope if you are using a ViewModel in your app.

Definition-based extraction

For Definition-based extraction, all the metadata required to perform data extraction are within the questionnaire, so no additional information is necessary. Simply pass the Questionnaire and QuestionnaireResponse to ResourceMapper.extract():

val bundle = ResourceMapper.extract(questionnaire, questionnaireResponse)

StructureMap-based extraction

In addition to the Questionnaire and QuestionnaireResponse, StructureMap-based Extraction also requires a StructureMapExtractionContext to retrieve a StructureMap. To create a StructureMapExtractionContext, pass your application’s context and provide a structureMapProvider lambda function which returns the StructureMap.

The function includes a String parameter which contains the canonical URL for the Structure Map referenced in the Target structure map extension of the questionnaire, and a HAPI FHIR IWorkerContext which may be used with other HAPI FHIR classes, like StructureMapUtilities.

A StructureMap may be written in the FHIR Mapping Language or as a StructureMap FHIR resource.

For example, if your StructureMap is hard-coded and written in the FHIR Mapping Language:

val mappingStr = "map ..."
val bundle = ResourceMapper.extract(
    myQuestionnaire,
    myQuestionnaireResponse,
    StructureMapExtractionContext(context = applicationContext) { _, worker ->
        StructureMapUtilities(worker).parse(mapping, "")
    },
)

As another example, this code uses a StructureMap resource as JSON based on its URL:

val bundle = ResourceMapper.extract(
    myQuestionnaire,
    myQuestionnaireResponse,
    StructureMapExtractionContext(context = applicationContext) { targetStructureMapUrl, _ ->
        val structureMapJson = getJsonFromUrl(targetStructureMapUrl)
        jsonParser.parseResource(mappingJson) as StructureMap
        )
    },
)

Populate a questionnaire response based on other FHIR resources

The Structured Data Capture Library supports expression-based population. If a questionnaire implements the SDC Questionnaire Populate - Expression profile, then you can use ResourceMapper.populate() to generate a questionnaire response based on the values in other FHIR resources:

val questionnaireResponse = ResourceMapper.populate(questionnaire, resource1, resource2, ...)

In this example, resource1, resource2, ... are FHIR resources represented by instances of HAPI FHIR Structures. To understand which resources you should include, look at the expression-based population extensions used in the questionnaire, most often the Initial Expression extension.

ResourceMapper.populate() returns a QuestionnaireResponse which can be used to pre-fill a questionnaire with existing answers.