Structured Data Capture
4.0.0-ballot - STU 4 ballot International flag

Structured Data Capture, published by HL7 International / FHIR Infrastructure. This guide is not an authorized publication; it is the continuous build for version 4.0.0-ballot built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/HL7/sdc/ and changes regularly. See the Directory of published versions

Form Population

Page standards status: Trial-use

One of the objectives of the SDC implementation guide is to reduce data entry into forms when the relevant data already exists in discrete form within the clinical or administrative system completing the form. This saves the user time and increases accuracy. If a Questionnaire is created with knowledge of where the data for different questions within the form is expected to come from, the Form Filler or Form Manager system can query for the relevant information and automatically fill in some of the answers. FHIR's REST interface provides a standard way to query this data, regardless of the type of client.

This 'population' process can happen in one of two ways:

  • The SDC Form Filler can invoke one of the $populate operations on a SDC Form Manager to create an initial QuestionnaireResponse before exposing the form to the user. This approach is known as 'pre-population' and is used by 'simple' Form Fillers that don't have the capacity to execute the logic needed to populate the form themselves. This approach is more limited because the population process can't take into account any user-provided information, nor can it provide guidance to the user. Either the population process can fill in an answer or it can't.
  • Alternatively, the SDC Form Filler can "interactively" handle the population process internally without invoking an operation. This is called "continuous population". In this case, there is no need to try to populate answers for all questions at once and answers to previous questions can be used as part of the logic used to populate subsequent ones. As well, the population process can provide guidance rather than always providing outright answers.

Population operations

There are 3 distinct $populate operations. They all perform the same population process, but the response they pass back (and the ramifications for what a Form Filler or other invoking system will need to do after) will be different.

  • $populate will pass back the results of the operation in a QuestionnaireResponse, meaning that the continued filling of the form will require a Form Filler to handle the rendering.
  • $populate-html returns the results back as a Binary containing an HTML form where populated values are reflected in initial default elements. Subsequent review and rendering are handled in an HTML rendering environment within the Form Filler. The results of completing the form are submitted as application/x-www-form-urlencoded or multipart/form-data rather than as a QuestionnaireResponse.
  • $populate-link returns a hyperlink to a website that has the form already pre-populated. Managing the HTML is handled external to the Form Filler. Like the $populate-html approach, results are returned as web form content rather than QuestionnaireResponse

The latter two modes are intended for form fillers that might not have the capability to support the complexity of the form and offloads the work of figuring out how to render the form in addition to the work of populating it.

If using a populate operation, the operation will typically only be invoked once. However, there are two circumstances where it might be invoked more than once:

  1. If the user has saved a QuestionnaireResponse "in progress" and comes back to it later, it is possible they might choose to re-run the populate process, for example to load information they know has been entered or imported into the EHR since the last time the $populate process was run.
  2. If the user is creating a net new QuestionnaireResponse by copying a previous QuestionnaireResponse, the user might also want to re-run the population process to take advantage of new data that wasn't available in the original form.

Both of these situations involve starting from an existing QuestionnaireResponse, which means that "re-populating" a form is something that will only be a consideration if using $populate, not $populate-html or $populate-link.

If choosing to re-populate a form, there are several considerations to keep in mind:

  • Re-population SHOULD only be done at user request because it may bring back data that had previously been removed or add additional selections to 'repeat' questions that the user had previously reviewed.
  • Users SHOULD be warned about both of these effects (return of previously removed data and addition of additional answers to questions whose answers had previously been reviewed).
  • Re-population SHOULD NOT revert elements that had been changed without user request. (If a user wants data to be fully reverted, they can always start the form from scratch).
  • If data is changed or reverted as part of a re-population process, these changes should be highlighted to the user.
  • Re-population can also be run in a mode where the Form Filler runs $populate on a blank form and then displays net new or changed answers alongside the original answers and provides the user with the option of propagating some or all of the answers across from the newly populated form into the 'current' form.
  • This same approach can also be used where the user starts with a newly populated form and then is given the option of propagating answers across from a previously completed QuestionnaireResponse.
  • Some sophisticated systems might have algorithms that determine whether reverting or supplementing data is appropriate based on what data is newer, where it came from, or other considerations. However, there is no standard algorithm for doing this and requirements might vary by Questionnaire and by item.
  • A single Questionnaire can sometimes include data from multiple subjects. The population process needs to be aware of what the subject for a given section of the Questionnaire is and take that into account when retrieving data to populate the record. (E.g. don't populate an answer asking for a mother's blood type with the child's blood type.) In SDC, the fact that a particular 'group' in a Questionnaire has a distinct subject is communicated using the isSubject extension. An equivalent extension flags the element within the QuestionnaireResponse.

Population modes

There are four different modes of "population" possible:

  • Full population: The questionnaire can identify the specific data element (or set of data elements) that should be used to populate the form. No user intervention is required other than to review the content. E.g. capturing the patient's gender, birth date, most recent weight measurement, etc. In some cases, this might involve performing a calculation based on data retrieved. For example, determining the patient's BMI by querying the most recent weight and height observations. This is the only type of population the $populate operation can perform (and then, only if the logic is based entirely on context or on answers to prior questions that were able to be populated automatically).
  • Choice selection: The questionnaire can identify the candidate answers, but the user must choose which of those should be included in the form response. For example, a question might say "List any relevant concomitant medical conditions". The notion of "relevant" will typically require human decision-making. However, the system rendering the questionnaire can easily bring up a list of concomitant medical conditions and allow the user to select which ones are "relevant" and include those in the answer. Choice selection can only occur during interactive population.
  • Answer context: The specific answer to the question will not exist as data in the client system, but might be able to be determined by the user based on data that is available in the clinical system. For example, the question "Has the patient ever exhibited a similar reaction in the past?" with a yes/no/unknown answer choice is not a data element that will exist in the clinical system. However, it is possible to provide the clinician with a list of AdverseEvent, Observation and Condition instances that might be relevant they can scan in choosing how to answer the question. Providing answer contexts can likewise only done interactively, not with the $populate operation.
  • No population: There is no way to query information relevant to the answer - the user will have to fill out that portion of the form unassisted.

"Choice selection" and "answer context" options will generally only be exposed when the user is interacting with the associated question (typically when a user clicks on an icon indicating they want to see the context or EHR choices).

Caveats and considerations with form population

  • For form population to work, the designer of the Questionnaire must do a fair bit of work defining the queries and the filters needed to select what elements to use in populating specific questions. While there are standard expectations for querying demographics like gender, birth date or even most recent weight (due to the HL7-mandated vital signs profiles), there is little international guidance on what codes or conventions to use when representing other data such as medications, procedures, lab results, etc. For form population to work with such data, the Questionnaire will have to be designed presuming the use of particular profiles and conventions - for example, national implementation guides such as US Core or Australian Base. The more sophisticated a Questionnaire's population rules, the more dependent it will be on systems exposing their data in accordance with specified profiles. Note: The mechanisms to do this in a more automated way are under consideration for the next release.
  • Even if data exists and is exposed in accordance with agreed profiles, that does not necessarily mean that the source system will have the necessary query capabilities to find and appropriately filter the data. While some degree of filtering is possible using FHIRPath or CQL, loading thousands or tens of thousands of records for local filtering by the client is likely to pose a challenge from the perspective of performance, memory usage, access control logging, etc. National and other implementation guides that set minimum expectations on search for capabilities on clinical and administrative systems can be helpful here as well.
  • Any queries performed to populate the form will need to be subject to appropriate access controls. Users SHALL NOT be able to see information populated into a form that they would not be able to see when navigating the source system directly (I.e. it is a mandatory requirement that the population process not populate information in the form if the user completing the questionnaire would not have permission to see that data if they queried it directly). In some cases, this means that an answer in a form might not be populated even though the data exists - because the user does not have authority to see that data.
  • Defining the rules for populating a questionnaire is essentially a mapping process. The author is mapping between the data element defined by a particular question or group item and a corresponding element in a FHIR resource or profile.

    Mapping can be dangerous because it can lead to the sharing of incorrect data or, occasionally, the failure to share correct data. For this reason, it is essential that human users be given the opportunity to review questionnaire responses that have been populated by automated means.

    Even with this precaution, care should be taken when performing data mappings, including:

    • Be aware that the risk of incorrect mapping occurring can be significantly higher when mapping complex questionnaires and/or complex data structures and especially high when mapping both.
    • The degree of risk is implementation dependent (type of data, type of questionnaire, type of source, mapping mechanism, type of user, etc.)
    • Both mappings and the implementation of those mappings should be carefully verified and, in some situations, should be subject to certification or external verification
    • Mapping from profiles not specifically defined for use in the context of a particular questionnaire or set of questionnaires (i.e. with a defined context) magnifies the risk of erroneous population.
  • The 'enableWhen' elements in Questionnaire mean that some elements may not be relevant in all situations. When pre-populating a questionnaire, it makes sense to "fill in" as much data as possible, even if it may not always be needed. However, such data should not be shown to the user until the given item is "enabled". And once the questionnaire is completed, data for any non-enabled elements SHALL not be displayed to the user completing the form. If an answer disables a portion of the QuestionnaireResponse containing significant user-entered data, the entry system SHOULD warn users that that information will be removed on submission.
  • Sometimes the author interested in making a Questionnaire "populatable" does not have authority to make changes to the "official" Questionnaire. In other cases, there might be one official Questionnaire, but a need to populate it from resources that comply with different sets of profiles (e.g. that comply with requirements from different countries) - and thus a need for different metadata in the Questionnaire to support the population process. In this case, rather than invoking the population on the original Questionnaire, it can be done on a derived Questionnaire.
  • When performing population, the considerations around errors and lack of support for expressions may come into play. In addition, similar considerations can also be relevant in terms of what 'population' approach the Questionnaire supports, as opposed to what level of population capability the Form Filler has. The desired behavior of alerting the user that some elements might not have been populated and that other clients might provide more population support is the same whether the variation is "handles FHIRPath vs. CQL" or "uses Observation-based vs. expression-based".
  • When information from other sources has been used to help populate a QuestionnaireResponse, there may be a desire to capture what information sources were used, what software was used to perform the population process, etc. The way to represent this information in FHIR is using the Provenance resource. The various source records used in population would be represented using Provenance.entity.what where the Provenance.entity.role would be 'source'. Software information would be captured in Provenance.agent.
  • When using FHIRPath and CQL, the empty set can be taken to mean 'false'. However, items of type 'boolean' actually have three states - 'true', 'false' and 'not answered'. An empty set SHALL be treated as 'not answered' rather than being converted to a boolean value of 'false'.

Pre-population service

Populating a QuestionnaireResponse is a complex task. The system must be able to query resources, use FHIRPath or CQL to populate and potentially calculate relevant data elements, manage conditionality rules around enableWhen as part of the population process, etc. As a result, some client systems might prefer to offload the responsibility for handling pre-population of a form to a separate system. The FHIR specification defines a set of services that can be used to provide a variable degree of offloading - from just handling the population aspect through to handling the rendering of the form and interactive data capture completely through a separate site.

There are three operations:

Operation Description
populate This operation supports generating a QuestionnaireResponse instance based on a specified Questionnaire. If matching data is available for any of the questions and the server supports the pre-population capability, the answers for those questions will be populated in the returned QuestionnaireResponse instance.
populatehtml This operation produces an HTML web page as a Binary instance. The HTML page provides an interactive rendering of the form, using html-based controls to capture user inputs and scripting languages to support form validation and submission to the server that generated the form and/or the recipient(s) designated by the Questionnaire. If matching data is available for any of the questions and the server supports the pre-population capability, the form will initially render with the answers for those questions filled in.
NOTE: because the Binary will contain active content, client systems must ensure they trust the server performing the populatehtml operation.
populatelink This operation returns a URL leading to a web page with an interactive rendering of the form that allows a user navigating to the link with a browser to complete and submit a response to the questionnaire. The response will be transmitted to the server generating the link, hosting the form and/or as designated as part of the Questionnaire itself. If matching data is available for any of the questions and the server supports the pre-population capability, the form will initially render with the answers for those questions filled in.

In addition to these operations, another alternative is to use the Adaptive Form mechanism. It hides the design of the questionnaire entirely and, in principle, allows the service to determine the next question to automatically fill in (or perhaps even suppress asking questions) based on data the service can access about the patient.

For SDC purposes, server systems claiming to support CapabilityStatements that require support for the populate, populatehtml or populatelink operations (SDC Form Manager) SHALL, at minimum:

  • Handle the input parameters identifier, questionnaire, questionnaireRef, subject and content
  • Support passing at least* the Patient resource using the content parameter
  • Populate the returned QuestionnaireResponse instance or rendered form for all questions that have SDC extensions defining population expectations if appropriate data exists in the underlying data repository and/or in the content passed into the populate operation.

Similarly, client systems claiming to support the populate, populatehtml and/or populatelink operations (SDC Form Filler) SHALL, at a minimum:

  • Be capable of invoking the operation(s) on a selected questionnaire both directly (Questionnaire/[identifier]/$populate) as well as indirectly either by identifier or questionnaire
  • Support passing at least* the Patient resource using the content parameter
  • Be able to accept an incoming partially-populated QuestionnaireResponse and render it as if they had retrieved a saved partially-completed QuestionnaireResponse
  • It is the responsibility of the SDC Form Filler to ensure the form is valid after a human has reviewed and edited the form.

* Supporting additional resources relevant to the context of the form is also encouraged. Past versions of this specification mandated support for passing C-CDA resources as FHIR Binary instances and this is still permitted. However, this specification no longer provides recommendations for extracting data elements from C-CDA and we have not yet heard of any systems that do this successfully in a production environment.

Designing Questionnaires to support 'populate'

This specification defines three different mechanisms to embed information in Questionnaires to support population:

Systems are free to experiment with other population mechanisms but cannot expect support for those from other SDC-conformant systems.

Each mechanism has its own profile that includes the additional resource elements or extensions relevant for supporting a particular mechanism: SDC Questionnaire Populate - Observation, SDC Questionnaire Populate - Expression, and SDC Questionnaire Populate - Structure Map profiles. Each profile identifies specific 'must support' elements and extensions that systems that claim to support a specific SDC population mechanism SHALL be capable of populating data, as befits the CapabilityStatement(s) they claim conformance to. Each system should choose which approach(es) it wishes to use and support based on the elements specified in that profile.

Some of these mechanisms make use of FHIR-based queries, FHIRPath and/or CQL as well as extensions that include expressions in one of these languages. Implementers should read the Using Expressions page for background and guidance on these technologies and extensions.

These three mechanisms aren't necessarily mutually exclusive. It is possible to use StructureMap-based population to perform an initial set of 'complex' population and then have different elements within the Questionnaire that are set up to perform supplemental observation-based or expression-based population. Obviously, the same element should only be populated in one way. Also, combining methods adds complexity and may reduce the number of systems that are capable of appropriately handling the Questionnaire.

Observation-based Population

This is the simplest of the population mechanisms. It takes advantage of the fact that most question answers in the healthcare space typically correspond to the value element of an Observation. It also takes advantage of the Questionnaire.item.code element that identifies what a concept each question or group corresponds to. An example for SDC Questionnaire Populate - Observation profile can be found here.

To use this method:

  1. Include the item.code element on each question to be populated. Typically, this will be a LOINC code, but in some jurisdictions/environments, SNOMED CT or other codes may be relevant.
  2. Groups can also have an item.code present - this might represent the code of a panel or the Observation.code of an Observation with no value but with multiple Observation.component elements. Child question items can then assert the item.code of the "member-of" Observations or the Observation.component.code values.
  3. To signal that the item.code is actually intended for use in population (as opposed to just providing metadata about the Questionnaire item, the questionnaire-observationLinkPeriod extension must also be included). This extension indicates the period of time over which to search for matching observations. If there are no observations within that window, no population will occur. For observations where how recent they are does not matter (e.g. blood type), simply set the duration to a long period of time - e.g. 200 years. If a link period is defined at the Questionnaire root, on a group item, or on a question item with descendent questions, the period will apply to all eligible (those having item.code and being of type question) descendent questions unless overridden by a nearer link period declaration.

    Observation Link Period Hierarchical Diagram: This diagram illustrates the structure and flow of 'observationLinkPeriod' extension in a Questionnaire. It shows how the period applies from the Questionnaire root down to group items and question items, with cases of inheritance, overriding, and items without codes.

    It shows how the period applies from the Questionnaire root down to group items and question items, with cases of inheritance, overriding, and items without codes
    Diagram Details:
    • Questionnaire Root: Contains the initial observationLinkPeriod setting.
    • Group Items: Inherit the observationLinkPeriod from the root or override it if a new period is defined.
    • Question Items: Items with item.code inherit the nearest observationLinkPeriod from their ancestors, such as the root or a parent group, which allows them to participate in observation-based auto-population. If an observationLinkPeriod is defined directly on an item with item.code, this specific period overrides any inherited period. Items without item.code do not inherit any observationLinkPeriod and are excluded from the auto-population mechanism. However, if an item with no item.code has descendants that do have item.code, those descendants can still inherit the nearest applicable observationLinkPeriod from higher levels.
  4. Multiple item.code elements might be present. If so, each is considered an acceptable Observation.code for the desired population value.

For example:

    
  

When performing the population operation, the system would look for questions that have the questionnaire-observationLinkPeriod extension and would then perform a query on the Observation using the context of the QuestionnaireResponse's subject - typically a Patient. The query would retrieve the most recent observation for that subject whose code matched one of the Questionnaire.item's codes, that had a value and whose value was of the correct data type.

The 'logical' query performed for the above Questionnaire item being populated on August. 31 might look like this:

[base]?Observation?subject=[questionnaire response subject id]&code=http%3A//loinc.org|29463-7,http%3A//loinc.org|3141-9,http%3A//loinc.org|8341-0&status=final,amended,corrected&date=ge2018-06-02&_sort=-date&_count=1

In practice, the server might not support the _sort or _count parameters, so the filtering for "most recent" might need to be done locally - especially if there's a need to check for matching data type.

Considerations and rules when using this approach:

  • If the units of measure are constrained for the Questionnaire item, the system can choose to convert the data (if the units are coded and the conversion factor is known), grab the most recent Observation within the window where conversion is not necessary, or choose not to populate.
  • Question items being populated from Observations of type Quantity SHOULD also have a type of Quantity. However, they MAY have a type of integer or decimal provided that the questionnaire-unit extension is present to allow determination of what unit to match on/convert to.
  • Systems need to allow for the possibility that an Observation might not have a value (e.g. if dataAbsentReason is present).
  • Systems SHALL filter to only look at Observations with a status of 'final', 'amended', or 'corrected'.
  • Systems SHALL check for the presence of the Observation.focus element and exclude elements where the focus is not the patient (e.g. we do not want the heart rate of a fetus if trying to populate the heart rate of the mother.)
  • If a parent item (group or question) already has established the context of a specific Observation, when populating child items, matching observations SHALL be limited to components of the Observation bound to the parent item and other Observations reachable by a hasMember link from that observation.
  • Where an Observation is known to directly correlate to another resource element value (e.g. LOINC 21112-8 corresponds to Patient.birthDate), systems MAY take advantage of this knowledge to populate the answer of a question by retrieving data from resource elements other than Observation.value and Observation.component.value.
  • Most of the data elements used to populate a QuestionnaireResponse from Observations can also be used to generate/update Observations from a completed Questionnaire. See the Extraction page of this implementation guide for more information.
  • This Observation-based population mechanism can be used in parallel with the Expression-based mechanism described below - i.e. some elements might be populated from Observation.value elements based on the item.code while other questions in the same form might be populated based on queries, FHIRPaths and/or CQL specified in the form.
  • This mechanism only supports Full Population. It does not work for other modes.
  • This mechanism can only be used for non-repeating items.
  • This mechanism can be used either for a pre-population step - before the user fills in any data, or as a "continuous" population process, where data is only retrieved when a given element becomes "enabled".
  • Obviously, this mechanism only works for questionnaire items that correspond to Observation values.

Expression-based Population

This approach to population is more generic. It supports retrieving data from any queryable FHIR resources available on the source system. Those queries can be based on the context in which the QuestionnaireResponse is being generated and/or on the results of other queries. Furthermore, it permits FHIRPath and CQL operations to be done on the resulting data such as calculations, conditional determinations, etc. As such, it is significantly more powerful than the Observation-based method. However, it also requires skill in using FHIR queries, FHIRPath, and/or CQL so it requires more technical expertise than the Observation-based approach. An example for SDC Questionnaire Populate - Expression profile can be found here.

To use this method:

  1. Include the questionnaire-launchContext extension to identify any contextual information that needs to be passed into the population process. Typical contexts would be the Patient or Encounter resources in whose context the questionnaire is being completed, but other elements are also possible (e.g. an AdverseEvent if performing an adverse event report). These 'context' elements will be available as expression variables for use in subsequent steps.
  2. Use the variable extension to query for any additional data required, possibly based on context variables set in the previous step, and/or other variable extensions. (NOTE: Elements SHALL be evaluated in the following order: questionnaire-launchContext elements, then all Questionnaire-level variables in order of appearance in the Questionnaire.)
  3. If appropriate, use the questionnaire-itemPopulationContext on group items to establish the context for a group. When populating the questionnaire, this will do two things: it will create a group repetition for each row returned from the query; and it will set the specified variable name to that resource repetition for use in processing descendant items of the group.
  4. Use the variable extension on items as well to perform intermediary calculations or additional queries that are based on itemPopulationContext values.
  5. For Full Population, use the questionnaire-initialExpression to cause the initial answer for the question to be set to the specified expression. This should always be a FHIRPath or CQL expression that resolves to an item of the appropriate type unless the element has a type of Reference, in which case the expression can ALSO be a FHIR query - and the item will be populated with a reference to the resource. Another exception is for an element of type Attachment, the query can return a Binary or DocumentReference, with the former populating the Attachment.content and the latter populating content and/or url, depending on what is present in the DocumentReference. Note, this extension SHALL NOT appear on groups.
  6. For Choice Selection, use the sdc-questionnaire-candidateExpression to make available a list of possible answers for the user to choose from. As with initialExpression, this should always be a FHIRPath or CQL expression that resolves to an item of the appropriate type unless the element has a type of Reference, in which case the expression can be a FHIR query - and any selected item will be populated with a reference to that resource.
  7. For Answer Context, use the sdc-questionnaire-contextExpression to indicate the resources to make available for display to the user to aid in answering the question. The information SHOULD be made available through user action (clicking a button or link to launch a separate window/dialog) rather than being presented by default.

Examples of questionnaires using this approach include this, this, this and this.

Considerations and rules when using this approach:

  • FHIR queries found in any of the variables may contain embedded FHIRPath expressions (surrounded by double curly-braces).
  • If the result of evaluating the FHIRPath expressions is an invalid query, that is an error. Systems SHOULD log it and continue with population as if the query had returned no data.
  • An item is not allowed have both initial.value and initialExpression present since both generate values before the user has access to the form.
  • If the candidateExpression or contextExpression resolve to an empty set, do not display them.
  • Variables made available by launch context may be used by any expression within the Questionnaire, however they are most safely used within initialExpression. Because the launch context might vary each time the QuestionnaireResponse is opened or edited, by populating launchContext into the values of (possibly hidden) questions via initialExpression, the 'original' context in which the QuestionnaireResponse was created can be retained..
  • Unlike initialExpressions, candidateExpressions can appear on groups as well as questions. If they appear on a group item and the group item is allowed to repeat, then a separate group instance is created for each repetition the user selects from the candidates. The variable named in the candidateExpression extension is set to the value of the candidate for use in continuous population of descendant items. For example, a candidateExpression might resolve to a list of Conditions. After the user picks the relevant conditions, a separate group would be created for each and child items for the condition code, severity, onset date, etc. could automatically be populated using an initialExpression based on the variable name from the candidateExpression.
  • When an initialExpression, candidateExpression or contextExpression will return a resource, backbone element or complex data type, the questionnaire-choiceColumn extension can be used to control which data elements should be exposed to the user (and what labels and widths should be allocated to each element so exposed).
  • When an item has an associated candidateExpression or contextExpression, consider whether there should be a preceding 'display' item that provides instructions on how to filter from the available candidates or how to make use of the available context in answering the question.
  • Multiple expression extensions can be present at once. If so, precedence is as follows: initial.value or initialExpression is used if it resolves; if not then candidateExpression expression is used. A link to contextExpression can be present with either of the modes as it may help the user in verifying the content.
  • It is an error if the return type of an initialExpression, calculatedExpression or candidateExpression disagrees with the type of the item, with the following exceptions:
    • A Resource can map to a Reference item type (populating the reference property with the resource type and id, optionally populating the display)
    • A Quantity can map to an integer or decimal item type provided that the questionnaire-unit extension is present to allow determination of what unit to match on/convert to. However, if the Observation selected for population is a Quantity with a comparator (e.g., "greater than", "less than", etc.), then that Observation cannot be used for population as the semantics of the comparator would be lost.
    • A code can be mapped to a coding item type if the value can be uniquely resolved within its answer space, and will be converted to the coding in the QuestionnaireResponse item answer (populating the provided code, and appropriate system value)
    Systems that encounter non-matching expressions that resolve to an element that does not agree SHOULD log it but still populate other elements as best they can.
  • When defining queries in expressions, be sure to filter all relevant elements. For example, ensuring status excludes entered-in-error elements, practitioners are active, etc.
  • Take care to ensure that variable names as set by questionnaire-launchContext, variable and questionnaire-itemPopulationContext remain unique within the hierarchy of the questionnaire. It's technically ok to have sibling items define the same variable name - they will not collide. However, if doing so, make sure it's being used for the same purpose to avoid confusion.
  • If the same context are used for both questionnaire-itemPopulationContext and questionnaire-itemExtractionContext, then the value will be repeated for both extensions.
  • If the initialExpression evaluates to a collection size that exceeds the maximum cardinality requirements of the item, the system may either choose not to populate the item at all, or instead may treat the initialExpression as if it were a candidateExpression and give the user a chance to choose from amongst the results being returned.
  • If the initialExpression returns fewer occurrences than the questionnaire-minOccurs value (if specified), it SHALL populate what occurrences it can. The user can then add in additional repetitions as needed.
  • If an answer is dependent on other answers within the form, the calculation of the answer will typically be performed using a variable extension on the nearest common ancestor in which all relevant questions or variables are descendants. The question will then have an initialExpression extension that references that calculated value. The reason for this is that FHIRPath only has access to the current context node and its descendants, not siblings or ancestors. However, if it is known that there can only be one item with a particular linkId, then the value of that answer can be accessed directly by using %context.descendants().select(item).where(linkId='someLinkId').answer
  • It's possible that not all queries will resolve successfully - or that some context variables might not be populated. In this situation, the system performing the population SHOULD make best efforts and populate whatever elements it can that are not dependent on other answers within the form.
  • It's possible that the same data might be queried multiple times within different contexts when filling out the form. Systems are free to notice this and use the data already in memory rather than re-querying the data. Form designers can be proactive and use variables to minimize this too.
  • The expressions used to populate some elements might be dependent on the answers to other questions, not just on context elements or queried data. In this case, pre-populating systems will only be able to populate the answer if the questions depended on are able to be pre-populated. For continuous-populating systems, they can either populate the dependent answer when the depended-on answer is filled in or when the user gets to the dependent answer.
  • In some cases, a user might choose to change the answer to a question that was the source for pre-populating another question. In this case, the system MAY leave the dependent answer as-is. Alternatively, it MAY re-evaluate the population logic and, if the new answer would differ, prompt the user about whether they would like to change to the new calculated answer. (Note that this may trigger still further updates. Users should have a mechanism to cancel further prompts for updates if they feel bombarded.)
  • If a questionnaire is stored in partially-completed state and then is re-opened sometime later for editing, it's possible that originally populated values could be out-of-date. Systems MAY choose to leave already populated data elements as they are. Alternatively, systems MAY re-execute queries to determine whether the new populated value would differ from the current value and, if so, prompt the user as to whether the question should be updated to the 'new' auto-populated value. Systems SHALL NOT replace already filled in answers without user approval.
  • If the units of measure are constrained for the Questionnaire item, the system can choose to convert the data (if the units are coded and the conversion factor is known) or choose not to populate.
  • It is possible that answerExpression and initialExpression can both exist. InitialExpression runs on launch and answerExpression should run whenever the user interface needs to render the question, the user interacts with the question or during validation.
  • An answerExpression and calculatedExpression can both exist and are re-calculated when the source for their expressions change. If the calculatedExpression is not valid according to the results of the current answerExpression, the QuestionnaireResponse will fail validation and be unable to be marked as 'completed' until corrected.
  • The result of initialExpression, calculatedExpression and answerExpression must all align with the 'type' of the item they appear on - e.g. can't have an expression that returns a string if the type is Choice/Coding.

StructureMap-based Population

The StructureMap approach is the most sophisticated approach of the three - and the most powerful. It allows iteration of groups based on repeating elements within resources, supports concept translation using structure maps and provides access to transformation capabilities not available with the Expression-based approach. It also allows the conversion process between data and Questionnaire to be maintained independently and to draw on shared sources across Questionnaires. This can be an advantage in certain environments where the content of the questionnaire may need tight control, but the data environment can be more dynamic. This comes at the cost of requiring expertise in the FHIR mapping language, which is not (yet?) a common skill.

To use this method:

  1. As done for the Expression-based approach, include the questionnaire-launchContext extension to identify any contextual information that needs to be passed into the population process. Typical contexts would be the Patient or Encounter resources in whose context the questionnaire is being completed, but other elements are also possible (e.g. an AdverseEvent if performing an adverse event report). These 'context' elements will be available as expression variables for use in subsequent steps.
  2. Include the sdc-questionnaire-sourceQueries extension which SHALL point to a Batch consisting of one or more queries to execute. Prior to executing, FHIRPaths embedded in the queries (referring to elements from the questionnaire-launchContext variables) SHALL be resolved.
  3. Include the questionnaire-sourceStructureMap extension. This SHALL define a transform between the Bundle of Bundles that will result from executing the sourceQueries Batch and a QuestionnaireResponse that complies with the Questionnaire.

For example:

    
  

To populate the QuestionnaireResponse, evaluate the FHIRPaths in the sourceQueries batch, execute the sourceQueries batch and then execute the StructureMap on the resulting Bundle. The result of that will be the pre-populated QuestionnaireResponse. A sample questionnaire that shows this approach can be found here.

Considerations when using this approach:

  • This approach will only work for pre-population using the Full Population mode. It cannot support continuous population using calculatedExpression nor "choice selection" and "answer context" using the candidateExpression and contextExpression extensions.
  • This StructureMap-based population has the drawback that if the StructureMap execution fails, there will generally not be any QuestionnaireResponse as output. As a result, the StructureMap must be designed to be very robust in the face of missing or potentially 'bad' data.
  • The ability of StructureMaps to reference other StructureMaps allows for the possibility of re-use if certain sections of multiple questionnaires are consistent.