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.
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.
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)
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
)
},
)
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.