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 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
Page standards status: Trial-use |
Contents:
Maintaining questionnaires can take a considerable amount of effort, particularly if they include logic to support population or extraction. At the same time, it is common for questionnaires to share content - the same questions or even the same sections might appear in multiple forms. Some organizations, particularly those with a research focus may have extensive libraries of questions intended to help drive re-use and consistency. This allows those organizations to increase consistency in how data is collected, which in turn increases the comparability of data captured, even when captured using different instruments. It also increases the quality of the data collected by encouraging the re-use of questions that have been vetted for readability, neutral phrasing and other quality considerations.
Achieving re-use with questionnaires is primarily focused on the benefit of authors. The use of modularization techniques is often transparent to the end users who must complete the questionnaires, unless they find themselves filling out many distinct forms and happen to notice the consistency of language and sections between those forms. In other words, questionnaire re-use is part of the authoring and publishing process, but generally not the form filling process.
This portion of the SDC specification describes three mechanisms for enabling re-use:
item
in a Questionnaire to reference a specific item
in another Questionnaire using the format Questionnaire URL#linkId
. This enables reuse of a specific item and its descendants
(if any) without the limitations of StructureDefinition
-based referencing. This is the recommended method going forward.
When using the data element-based approach, every single 'item' in the questionnaire must be specified, including all 'display' items, groups, etc. Re-use is limited to question text, value set, data type and other information that can be determined from the referenced definition element. When using the sub-questionnaire approach, multiple items can be defined along with display text, enableWhen logic and other questionnaire characteristics. The first approach is best suited for "data-element"- based questionnaires and the latter for defining collections of questions. (While defining separate modules for every single question is possible, it would be quite a bit of overhead).
These reuse mechanisms are not mutually exclusive. It is possible to create forms that mix all three techniques—for example, using subQuestionnaire for group-level reuse, as well as definitions that point to both StructureDefinition#elementId and Questionnaire#linkId for individual items.
Profile: | Modular Questionnaire profile |
---|---|
Relevant Extensions: | |
Example Questionnaires: | See below |
Regardless of mechanism, there are two phases. First, the questionnaire is authored in its modular form, maximizing re-use and minimizing authoring effort. Then, there is then a need to take the re-useably authored form (or collection of forms) and generate a fully 'assembled' form that contains all of the details needed for a Form Filler to properly render and capture answers for the form. While this assembly process can be undertaken by the Form Filler, it is more typically managed by the form designer as part of the publication process.
The following diagram shows the results of the assembly process with a set of questionnaires that combine both approaches:
The first questionnaire (Q1) contains two items, each with a sub-module extension pointing to other questionnaires - Q2 and Q3. Those two sub-questionnaires in term make use of the 'definition' element to refer to data elements from a single StructureDefinition. (In practice, the elements could as easily have been pointed to from a variety of StructureDefinitions.) The assemble operation then produces a new instance of Q1 that combines all of the items referenced from the two sub-modules and brings in the question text and other metadata from the referenced element definitions.
The assembly process can be done internally or by invoking the $assemble operation. Questionnaires might use any combination of defining content traditionally (i.e. all item details defined inline), referencing sub-questionnaires, and/or referencing external data elements. There is also no theoretical limit to the amount of nesting that can happen with sub-questionnaires, though practically more than 2-3 levels of nesting are very unlikely.
When working with modular questionnaires, the 'assembly' step should be performed prior to any population steps.
It is helpful to know when a Questionnaire is going to require assembly or not. It is also helpful to know whether a particular questionnaire can be used
as a 'root' form for entry, can be used as a sub-module or either. A system can search through for items that declare the
subQuestionnaire
extension, though doing so isn't terribly efficient. However,
for Data Element-based Questionnaires, there is no mechanism to tell with certainty that assembly is required - the 'definition' element may be included in
questions for a variety of reasons and some degree of metadata may be maintained in the 'master' Questionnaire for readability. Therefore, this specification
defines a assemble-expectation
extension that allows flagging whether a particular Questionnaire requires
assembly, whether it is safe to use as a subQuestionnaire and/or whether it can be used as a 'root' Questionnaire.
code | $assemble before use? | Can be subQuestionnaire? | Can be root questionnaire? |
---|---|---|---|
assemble-root-or-child | Yes | Yes | Yes |
assemble-root | Yes | No | Yes |
assemble-child | Yes | Yes | No |
independent-root-or-child | No | Yes | Yes |
independent-child | No | Yes | No |
There is no code for a questionnaire that's intended for use as a stand-alone form, doesn't require assembly and isn't intended for use as a child form, because that's the default.
In addition to these codes, the code system has a few additional abstract codes that are only available to aid in searching:
assembly
encompasses all codes that mean assembly is required and independent
encompasses all codes that don't require assembly
(though it won't include Questionnaires where the extension isn't present at all). E.g. to find all Questionnaires that don't require assembly, you would search
Questionnaire?assemble-expectation:below=independent
as well as Questionnaire?assemble-expectation:missing=true
. Alternatively, if 'missing'
and 'below' aren't supported, you could simply use Questionnaire?assemble-expectation:not=assemble-root-or-child,assemble-root,assemble-child
.
root
encompasses all codes that mean the form can be the 'root' for data entry. To find all Questionnaires that can be the root for data capture, you
would search Questionnaire?assemble-expectation:below=root
as well as Questionnaire?assemble-expectation:missing=true
. Alternatively, if 'missing'
and 'below' aren't supported, you could simply use Questionnaire?assemble-expectation:not=assemble-child,independent-child
.
child
encompasses all codes that mean the form can be used as a sub-module. To find all Questionnaires that can be safely used as sub-modules, you
would search Questionnaire?assemble-expectation=assemble-root-or-child,assemble-child,indelpendent-root-or-child,independent-child
.
The notion of a modular Questionnaire is that a 'display' item in a parent questionnaire can include an extension pointing to a specific Questionnaire whose items should be embedded in the resulting assembled Questionnaire in place of the 'display' item. The details of how this works are as follows:
subQuestionnaire
extension will contain the canonical reference to the
Questionnaire whose content should be substituted for the display itemSHOULD
be version-specific to ensure that the author of the parent questionnaire has full control over what content
they are importing. If the subQuestionnaire is not version-specific, then the same version of the parent Questionnaire could include varying
items as the subQuestionnaires evolve and this is considered an error. I.e. if canonical references are not version-specific, the content of the
referenced Questionnaires cannot change in a way that results in differences in allowed QuestionnaireResponses.SHOULD
say something that is meaningful in situations where it is not replaced. For example: "Sub-questionnaire
[some URL] not available. Unable to display all questions."subQuestionnaire
extension will be removed entirely.
I.e. that linkId and the associated text will not appear in the assembled Questionnaire. Instead, all of the 'root' items of the referenced
Questionnaire - including their descendant elements and items will appear in the same position as the replaced 'display' item was.assemble-expectation
on the resulting Questionnaire should be adjusted to
change the 'assemble' part of the code to 'independent', with the exception that if the code was 'assemble-root', then the extension should be removed entirely.
E.g. assemble-root-or-child
would change to independent-root-or-child
.subQuestionnaire
extension, those display
elements are also replaced by the referenced Questionnaire, repeating the process until no further subQuestionnaire extensions are found.MAY
declare a special variable
with the name linkIdPrefix
. If
there is a linkIdPrefix in context at the time a subQuestionnaire is substituted, that linkIdPrefix SHALL be pre-pended to the linkId
and
enableWhen.question
elements of all items in that Questionnaire. See the examples to see how this works in practice.
If linkIdPrefix is not used, care should be taken to ensure that linkIds are appropriately coordinated to avoid overlap across all referenced
Questionnaires%root.descendants().select(item.where(linkId='1.1'))
would need to change to %root.descendants().select(item.where(linkId=%linkIdPrefix + '1.1'))
This will need to happen in all extensions with a type of expression.assembleContext
extension on the root of the
Questionnaire. As well, if a Questionnaire is referenced by a subQuestionnaire
extension, it is an error if the listed variables are not available
in the context of the referencing element.assembleContext
extension on a Questionnaire indicates that it can ONLY be used as a part of a modular Questionnaire.
If stored, an assembled Questionnaire SHALL
have the same URL and Version as the base Questionnaire. Note that this means that it's possible
for a server to have multiple Questionnaire instances that share the same URL and Version. Clients SHOULD
populate
the knowledge-capability
and SHALL
populate it if they know that both unassembled and assembled versions will be hosted on the same server. This extension allows differentiating
between assembled (executable) from non-assembled (computable) instances. As part of the assembly process, the assembly engine SHOULD
add assembledFrom
extensions
pointing to the specific versions of all descendant Questionnaires that were used as part of the assembly process. The root questionnaire
doesn't need to be listed as its URL and version will be the same as the assembled Questionnaire.
In situations where there can be more than one assembled version of
the same questionnaire version hosted on the same server, the assembly process SHALL
also populate
package-source
(and the package information that can
be gleaned from it) to help differentiate between multiple assembled instances of a Questionnaire. This will typically only happen where the
Questionnaire component hierarchy isn't all version-specific.
⚠️ Warning: This implementation guide previously supported referencing items from
StructureDefinition
resources usingQuestionnaire.item.definition
. While still technically supported, this approach is limited:
- It does not map well to all
Questionnaire.item
features (e.g.,display
,text
,answerOption
).- It is not widely supported by Questionnaire authoring tools.
Future versions of this guide may remove support for the StructureDefinition-based approach. It is recommended to transition to the Questionnaire Library Referencing wherever feasible.
Data Element-based Questionnaires rely on the fact that Questionnaire 'item' elements largely correspond to the information found in the ElementDefinitions that are part of StructureDefinitions. These might be FHIR resources or data types, FHIR profiles, or logical models that represent any type of data at all. Full details on the mappings between Questionnaire.item and StructureDefinition.snapshot.element as well as general guidance on how definitions are to be mapped, including mapping to version-specific artifacts, mapping to slices, etc. are found in the FHIR core specification here.
The process for 'assembling' a Questionnaire that leverages Data Element-based mappings is as follows:
item.definition
element is present, try to resolve the referenced
element.
item.definition
. This process recurses. The linkId
of the generated items should be a concatenation of the linkId of the group and the path of the element.
If assembling a 'group' item from a definition, the following rules apply:
linkId
of the child questions are taken as the relative paths from the id
of the elements in the definition.
For example, if a group with linkId
3.2 has a definition that points to Patient.contact
, the child questions would have linkId
values of
3.2.name
, 3.2.address
, 3.2.address.line
, etc.
maxOccurs
of 0 or elements with fixed values or patterns will not be included as items.
id
, extension
, and modifierExtension
elements are not generated as child questions, though slices of them will be.
extension
and modifierExtension
, additional items will be added to support "other" values.
For example, if a definition pointed to USCore Organization.identifier
, there would be groups for the NPI, CLIA, and NIAC identifiers, but there would also be a group for "other identifiers" to handle identifiers not covered by one of the slices.
(linkId
s would be something like 4.5.identifier:NAIC.value
, 4.5.identifier:NIAC.period.start
for the slices, and 4.5.identifier.value
for the "other" items.)
NOTE: While generating complex structures of groups and questions from a FHIR resource profile is possible, in most situations, pointing to logical models specifically designed to be "Questionnaire-friendly" will produce better results.
If a system wants to create a library of 'questions' that can be drawn on by Questionnaires, this can be accomplished by:
The approach taken will depend on whether metadata such as status, publisher, etc. needs to be tracked on a per element basis or can be tracked at a higher level of granularity. Note that even when creating a separate data model for each item, some items may be 'complex', representing a 'group' with multiple child questions, and thus there will still be multiple elements in the StructureDefinition.
The only thing this implementation guide adds to the capabilities described in the base specification is the formal definition of the $assemble operation, including expectations of behavior for situations when the properties for an item in the base Questionnaire differ from those in the referenced definition.
This section introduces a preferred method for managing reusable items—such as questions, groups, and displays—by referencing them from other Questionnaires during the form assembly process. Instead of duplicating content, implementers can now reference a specific item from another Questionnaire using the format:
[Questionnaire URL]#[linkId]
This mechanism allows reuse of complete item definitions, including display text, data types, extensions, and constraints.
While this implementation guide previously supported referencing item definitions from StructureDefinition using item.definition
, that approach is limited and may not represent all Questionnaire.item
capabilities. This newer method offers a more robust and authoring-friendly alternative.
Note: If the referenced item has child items, they will also be included during assembly.
Example: To reference an item with linkId = "patient-name"
from a Questionnaire located at http://example.org/Questionnaire/QuestionLibrary
, the reference would be:
http://example.org/Questionnaire/QuestionLibrary#patient-name
To indicate that a Questionnaire serves as a reusable library of items, it should follow the Questionnaire Modular Library profile, which requires the inclusion of a usageContext
with the code workflow
and a value indicating Question Library.
This usageContext helps tools and systems distinguish libraries from standard data entry forms. It is recommended to follow the pattern defined in the sdc-usagecontext-questionnaire-library profile.
This specification includes a simple set of examples that highlight the functionality of the two different modular questionnaire mechanisms. They also serve as test cases for systems that might want to check their support for the $assemble operation (or equivalent internal functionality). The files are as follows:
This is the Questionnaire that uses a mix of direct element definitions (via definition
) and modular structure (via subQuestionnaire
). It includes a launch context and a variable for linkIdPrefix
to support nested item prefixing during assembly. The subQuestionnaire
extension references a submodule Questionnaire that will be inserted during the $assemble operation.
This is a reusable sub-questionnaire module that defines a structure for capturing a name. It includes three items: title, first name, and last name.
The example demonstrates the use of definition
to pull structure from a data library and initialExpression
to prepopulate
values from context. This module is designed to be referenced from a parent Questionnaire using subQuestionnaire
.
This module represents a patient's contact information and includes its own subQuestionnaire
reference to the modular-name
module. It demonstrates nesting of sub-questionnaires.