FHIR:Vissue-286 FHIR Profiling Guidelines R4: verschil tussen versies
(Clone of V1.0 production page for issue 286) |
(→Current implementation) |
||
(3 tussenliggende versies door dezelfde gebruiker niet weergegeven) | |||
Regel 100: | Regel 100: | ||
Any StructureDefinition that profiles a Resource does so because there is some kind of logical definition ''dictating'' how. Profiles SHALL have a traceable relationship with their functional counterpart(s). | Any StructureDefinition that profiles a Resource does so because there is some kind of logical definition ''dictating'' how. Profiles SHALL have a traceable relationship with their functional counterpart(s). | ||
− | The FHIR specification contains several solutions for this problem, [http://hl7.org/fhir/conceptmap.html ConceptMap] (>=STU1), [http://hl7-fhir.github.io/structuredefinition.html StructureMap] (>=STU3), [http://hl7.org/fhir/elementdefinition-definitions.html ElementDefinition.mapping]. Neither of these solutions are mature and cover our use case. | + | The FHIR specification contains several solutions for this problem, [http://hl7.org/fhir/conceptmap.html ConceptMap] (>=STU1), [http://hl7-fhir.github.io/structuredefinition.html StructureMap] (>=STU3), [http://hl7.org/fhir/elementdefinition-definitions.html {{fhir|ElementDefinition.mapping}}]. Neither of these solutions are mature and cover our use case. |
* ConceptMap: works best for value sets and codes. | * ConceptMap: works best for value sets and codes. | ||
* StructureMap: overcomplicated and unclear how to apply and whether or not this has a future. | * StructureMap: overcomplicated and unclear how to apply and whether or not this has a future. | ||
− | * ElementDefinition.mapping: is a free text mapping ''inside'' the profile. This means we cannot add mappings to profiles from third parties without updating their resource. | + | * {{fhir|ElementDefinition.mapping}}: is a free text mapping ''inside'' the profile. This means we cannot add mappings to profiles from third parties without updating their resource. |
===Current implementation=== | ===Current implementation=== | ||
− | We use the mapping elements in profiles to map functional | + | We use the {{fhir|StructureDefinition.mapping}} and {{fhir|ElementDefinition.mapping}} elements in profiles to map functional concepts to resource elements. The following rules apply: |
+ | * The mapping {{fhir|.mapping.uri}} SHALL resolve to a description of the functional model: | ||
+ | ** For zibs, this SHOULD be the English page on zibs.nl. | ||
+ | ** For functional models in ART-DECOR, this SHOULD be the link to the dataset on ART-DECOR v3 in the format of <q>[host]/ad/#/[prefix]/datasets/dataset/[dataset id]/[dataset effectiveDate]</q> | ||
+ | * The {{fhir|.mapping.identity}} should be a constructed in the following way: | ||
+ | ** For zibs, this SHOULD be the <q>zib-[English zib name, lowercased]-v[version]-[publication]EN</q> | ||
+ | ** For functional models in ART-DECOR, this SHOULD be, all in lowercase, <q>[project prefix][dataset name]-[dataset effectiveDate as 'yyyymmdd']</q>. The dataset name SHOULD be the English name if available, otherwise it SHOULD be the Dutch name. All spaces are replaced by dashes. If the project prefix and dataset name are similar, it's better to not repeat it and simply use 'dataset'. | ||
+ | * The {{fhir|.mapping.name}} should be constructed in the following way: | ||
+ | ** For zibs, this SHOULD be <q>zib [English zib name]-v[version]([publication]EN)</q> | ||
+ | ** For functional models in ART-DECOR, this SHOULD be <q>ART-DECOR Dataset [dataset name] [dataset effectiveDate]</q>. The dataset name SHOULD be the English name if available, otherwise it SHOULD be the Dutch name. If the dataset name contains the word 'dataset', it SHOULD not be repeated. | ||
+ | * Functional concepts are referenced based on their id in the functional model, which should be used to populate {{fhir|.mapping.map}}. | ||
+ | * The description of the functional concept is ''normally'' placed in {{fhir|.mapping.comment}}, unless other rules apply (see [[#References that are reversed in FHIR]]). | ||
+ | * When slicing, the mapping is made on the ''content'' of the slice, not the slice itself (see also [[#Placing-Info]]). | ||
− | + | So on the root of the StructureDefinition, the mapping for a zib should be defined as: | |
− | |||
− | |||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
<mapping> | <mapping> |
Huidige versie van 7 sep 2022 om 16:25
Dit is een tijdelijke pagina met wijzigingen voor issue 286. De gepubliceerde versie vind je hier. |
Inhoud
- 1 Introduction
- 2 Open vs. closed world modeling
- 3 Functional model as base
- 4 Versioning
- 5 Mapping semantic codes to profiles
- 6 Slicing
- 7 ValueSet binding
- 8 Extensions
- 9 Common patterns
- 10 Mandatory FHIR elements without a functional counterpart
- 11 References that are reversed in FHIR
- 12 Practical guidelines
- 13 Special cases
- 14 Data type mapping
1 Introduction
This page lays out the conventions for creating FHIR profiles and associated conformance resources within Nictiz. These guidelines are specifically aimed at FHIR R4; for the STU3 profiling work, a separate document exists.
This page is titled "profiling guidelines", but actually addresses all conformance resources (profiles, extensions, value sets, code systems, CapabilityStatements) and associated examples. We use these terms somewhat interchangeable throughout this document; 'profile' can usually be read as 'the whole set of conformance resources'.
1.1 Language
Unless stated otherwise, the FHIR conformance materials will be created in English in order to encourage adoption and re-use.
2 Open vs. closed world modeling
When profiling, an "open world" or a "closed world" model can be chosen. The former means that the profile only allows the elements to be used specified by the functional model, with all the restrictions from the functional model. The latter means that the profile can accommodate the elements specified by the functional model, but doesn't impose further restrictions.
We adopt the "open world" modeling approach to aid re-usability beyond the known use cases. When restrictions are deemed necessary for a specific use case, it will be added to the information standard specific profiles.
× | Open | Closed |
---|---|---|
Pros |
|
|
Cons |
|
|
2.1 General guidelines for open world modeling
We only profile elements, cardinalities and bindings that require profiling. We leave other elements, cardinalities and bindings as-is.
2.2 Cardinality
The functional description will specify the cardinality for each concept as a minimum required and maximum allowed number of times it may occur, which is the same mechanism as in FHIR. However, one needs to be careful as the cardinality can only be restricted in derived profiles, and never widened. Being too strict could thus hinder the re-use of these profiles. This is especially true for cardinalities in zibs, which should be interpreted as 'purely conceptual'; a use case might allow for data that conceptually always should be there to be absent in practice.
For zib profiles:
- A minimum of 0 or 1 will be profiled as 0.
- A maximum (1, n, *) will be profiled as-is.
For nl-core profiles:
- No further restrictions are added, as these profiles only cover the currently known use cases. Adding restrictions here would hinder as yet unknown of undefined use cases.
For information standard specific profiles:
- If the corresponding zib has a minimum of 1 and the use case doesn't contradict this, the minimum will be profiled here as 1.
- Cardinalities may be further restricted if the use case defines this.
2.3 Constraining references
Concepts in a functional description oftentimes refer to each other; e.g. most clinical concepts will refer to the concept of a Patient. In FHIR these connections are realized using the reference datatype, which allow to specify the target (base resource of profile) as well. For example, a profile representing the zib Problem could set the target of the .subject
element to the profile representing the zib Patient.
However, setting the target explicitly means a restriction of the allowed targets, which runs counter to the principles of open world modelling. On the other hand, specifying a dedicated profile provides useful guidance on how to handle this profile. To address both concerns, the target profile will be added next to the base resource.For example, the Condition resource allows Patient and Group as target in the .subject
element. When profiling the zib Problem, the profile representing the zib Patient will be added as a third option.
3 Functional model as base
Most, if not all, conformance resources are based on an underlying functional model. The functional model is the specification to which the conformance resources should adhere.
The basis for most other functional models is formed by the 'zibs' ('Zorginformatiebouwstenen'), in English also known as are Clinical Information Models (CIMs), Health and Care Information Models (HCIMs) or Clinical Building Blocks (CBB) -- we will use the Dutch term 'zib' for all profiling work as it has become a recognizable term over the past years. The zibs are defined by the program ‘Registratie aan de bron’ (Data capture at the point of care) and provide a foundation of use case neutral building blocks from which use cases can be built. The formal definition of the zibs can be found on the zibs wiki
Use cases or information standards use and refine those zibs that are relevant to the situation. The formal specification for these information standards can usually be found in Nictiz' instance of ART-DECOR.
3.1 Layering: zibs, nl-core profiles and information standard specific profiles
The profiles and other conformance resources align to this layering of information standards. We recognize three levels of profiles:
- zib profiles
- profiles that represent the zib as faithfully as possible
- nl-core profiles
- profiles derived from the zib profiles that that might be enriched by concepts from the different use cases that need the zib. See #The nl-core layer for more information.
- information standard specific profiles
- optional derived profiles from the nl-core profiles that further restrict or enhance these profiles for a specific use case.
3.2 The nl-core layer
The goal of the nl-core layer is to ensure that similar concepts defined at the use case level are implemented in a uniform way at the FHIR level. Whether the concept is used by a single or multiple use cases is irrelevant – adopting it at the intermediate nl-core level provides clear guidance to future use.
On the other hand, concepts defined at the intermediate level are only of value if they can be reused across situations. Therefore, it should be investigated how the concept can be created in a reusable way before it is implemented at the nl-core level. If there is a vanishingly small opportunity for reuse, then it is best to define it at the use case level to avoid clutter at the nl-core level. In practice, this means:
- Extensions from use cases should usually be generalized and added to the nl-core layer.
- Adding reference types to specific profiles (see #Constraining references) should usually be done at the nl-core layer.
- Cardinalities are usually determined by the zibs and further restricted by the use cases, so it makes little sense to implement them at the nl-core layer. These should normally be implemented at the use case layer. Also see #Cardinality.
- Mappings to the functional specifications for use cases (see #Associating the functional definition to StructureDefinitions) are by definition use case specific and should be added at the use case layer.
- Bindings to ValueSets (see #ValueSet binding) are usually use case specific, but might be added at the nl-core layer.
- SearchParameters should usually be generalized and added to the nl-core layer.
3.3 Associating the functional definition to StructureDefinitions
Any StructureDefinition that profiles a Resource does so because there is some kind of logical definition dictating how. Profiles SHALL have a traceable relationship with their functional counterpart(s).
The FHIR specification contains several solutions for this problem, ConceptMap (>=STU1), StructureMap (>=STU3), ElementDefinition.mapping
. Neither of these solutions are mature and cover our use case.
- ConceptMap: works best for value sets and codes.
- StructureMap: overcomplicated and unclear how to apply and whether or not this has a future.
ElementDefinition.mapping
: is a free text mapping inside the profile. This means we cannot add mappings to profiles from third parties without updating their resource.
3.3.1 Current implementation
We use the StructureDefinition.mapping
and ElementDefinition.mapping
elements in profiles to map functional concepts to resource elements. The following rules apply:
- The mapping
.mapping.uri
SHALL resolve to a description of the functional model:- For zibs, this SHOULD be the English page on zibs.nl.
- For functional models in ART-DECOR, this SHOULD be the link to the dataset on ART-DECOR v3 in the format of
[host]/ad/#/[prefix]/datasets/dataset/[dataset id]/[dataset effectiveDate]
- The
.mapping.identity
should be a constructed in the following way:- For zibs, this SHOULD be the
zib-[English zib name, lowercased]-v[version]-[publication]EN
- For functional models in ART-DECOR, this SHOULD be, all in lowercase,
[project prefix][dataset name]-[dataset effectiveDate as 'yyyymmdd']
. The dataset name SHOULD be the English name if available, otherwise it SHOULD be the Dutch name. All spaces are replaced by dashes. If the project prefix and dataset name are similar, it's better to not repeat it and simply use 'dataset'.
- For zibs, this SHOULD be the
- The
.mapping.name
should be constructed in the following way:- For zibs, this SHOULD be
zib [English zib name]-v[version]([publication]EN)
- For functional models in ART-DECOR, this SHOULD be
ART-DECOR Dataset [dataset name] [dataset effectiveDate]
. The dataset name SHOULD be the English name if available, otherwise it SHOULD be the Dutch name. If the dataset name contains the word 'dataset', it SHOULD not be repeated.
- For zibs, this SHOULD be
- Functional concepts are referenced based on their id in the functional model, which should be used to populate
.mapping.map
. - The description of the functional concept is normally placed in
.mapping.comment
, unless other rules apply (see #References that are reversed in FHIR). - When slicing, the mapping is made on the content of the slice, not the slice itself (see also #Placing-Info).
So on the root of the StructureDefinition, the mapping for a zib should be defined as:
<mapping>
<identity value="zib-medicationagreement-v1.2-2020EN" />
<uri value="https://zibs.nl/wiki/MedicationAgreement-v1.2(2020EN)" />
<name value="zib MedicationAgreement-v1.2(2020EN)" />
</mapping>
A specific element can then be mapped using:
<element id="MedicationRequest.extension:usageDuration">
<path value="MedicationRequest.extension" />
<mapping>
<identity value="zib-medicationagreement-v1.2-2020EN" />
<map value="NL-CM:9.6.19936" />
<comment value="PeriodOfUse" />
</mapping>
</element>
Note that implicitly mapped elements and reversed references use a slightly different comment
.
4 Versioning
Discussions regarding this topic are ongoing. This section might change in the future. |
In general terms, FHIR conformance resources could be affected at several different layers:
- The version of the package that the conformance resources reside in: versioned according to SemVer 2.0.
- The version of the conformance resource themselves (
StructureDefinition.version
): used to indicate the business version to the user, without strict specifications. - The FHIR version (
StructureDefinition.fhirVersion
): this document is specifically aimed at FHIR R4, meaning this element will be fixed on 4.x. - The version of the underlying data model.
Regarding point 1 and 2: Nictiz uses the package level as the main versioning mechanism. As a result, the conformance resources within the package are not individually versioned; they should be regarded as a consistent set. To identify the package version a conformance resource, its version number will be set to the package version.
Regarding point 4: the life cycle of the underlying data model is not reflected directly in the version number of the conformance resources, but a change in de the underlying data could result in a change in one or more of the conformance resources. In this case, the normal SemVer rules will determine what happens; if some of the conformance resources need to be changed in a backwards compatible way, a new patch release of the package should be made, if major functionality is added, a new minor version of the package should be released, etc. When a new version of the underlying data model reflects a fundamental change, the choice can be made to create a new package under a different name rather than a new version (eg. each zib releases will have their own package).
Version updates of conformance resources normally do not affect their canonical URI. Any resource that references another resource normally does so without a version indicator (uri|version
). Instead, this is handled at the package level; reference targets either reside within the same package or in a versioned package that has been added as a dependency.
5 Mapping semantic codes to profiles
Oftentimes a functional concept has an equivalent FHIR element, e.g. a 'comment' in the functional description maps in FHIR to the Resource.comment
element. When this is not the case, a code (usually SNOMED or LOINC) is needed to add the proper definition to the FHIR resource, usually using the Resource.code
element. For example, the root concept of an Observation is unknown unless it is defined by the .code
element, and when components are used in an Observation, each Observation.component
needs to be defined using an individual .code
element. These codes should be provided by the functional description (for zibs this is the DefinitionCode).
These codes are profiled as required elements using a ElementDefinition.pattern
on the element that should contain the code. This allows to add additional codings on the same element.
6 Slicing
Elements are sliced for two reasons:
- To specify different requirements for repetitions of an element.
- To allow other uses of a base element than what is required by the functional specification, e.g. the reuse of an
.identifier
next to the profiled.identifier
.
Slicing can often occur on different levels within an element, e.g. when the element is of type CodeableConcept, a slice can be made on the element itself or on the child element of type Coding (.element.coding
). In general, slicing will occur on the highest level possible, thus on the element itself in the example above. Note that this is only possible for repeating elements (max cardinality > 1). When an element of type CodeableConcept does not repeat, the Coding element can be sliced, but this is discouraged as this is often not what is meant; when .coding
repeats within a single element of type CodeableConcept, it must have the same semantic meaning although some granularity difference is accepted (eg. when communicating the same concept in different code systems).
In general, the slice discriminator is set to discriminator.type
= value and discriminator.path
to the path where the discriminator value is located (if it is the root element, it should be noted as $this
). The sliced element gets a pattern
or a required ValueSet binding on the location of the path. No further cardinality constrains are added in the sliced element that correspond with the pattern[x]
as they are made mandatory by the pattern.
These general slicing guidelines apply to the following situations. See this page for examples in XML:
- Mapping semantic codes to profiles requires the presence of the semantic code while leaving the option to use the element for other concepts, e.g the zib LaboratoryTestResultCode profile uses
Observation.category
for a sematic code that represents the zib and to map the zib concept ResultType. - Identifier systems are always defined on a sliced
.identifier
, even if there is only one defined.
Other forms of slicing that are common (Forge sets these slicing details by default):
- A concept is mapped to one or multiple types of a polymorphic element, e.g.
Observation.value[x]
. The mapping and functional description are placed on the slice with the matching data type(s). - Adding an extension slices the
.extension
element that is discriminated by the value onextension.url
.
6.1 Slice names
The slice name should describe the concept it represents. It should align with the name from the functional description where possible, but a more suitable name may be chosen if deemed more applicable:
- E.g. the zib concept 'PatientIdentificationNumber' defines a patient id for Dutch patients in the form of a bsn, hence the slice name 'bsn' for a slice on
Patient.identifier
is more informative than the zib concept name. - For CodeSpecification extension slices, a custom rule applies.
Slices follow the convention of FHIR elements in general, using a camelCased name starting with a lowercase letter. If the slice name represents or starts with an abbreviation, the entire abbreviation should be lowercased (e.g. 'bsn' instead of 'BSN').
7 ValueSet binding
7.1 Binding multiple ValueSets
The functional model might require multiple valuesets to be used for some data element, eg. when offering the choice between multiple code systems. However, FHIR allows to bind just one ValueSet to an element. There are two strategies to handle this situation:
- Create and bind a combined ValueSet that encompasses all the ValueSets defined in the functional model.
- Create slices for each ValueSet binding.
The use of combined ValueSets is the preferred approach. Although the use of slices would make the different concepts visible in the profiles, this strategy doesn’t allow for overlapping ValueSets (which often doesn’t make much sense semantically but happens for example when the different ValueSets include the same NullFlavor codes). It is also less straightforward for derived profiles to expand or restrict the base ValueSet when using slices. Using the first approach, a new ValueSet can be created and bound (if the binding strength permits it and it makes sense semantically).
However, option 2 should be used if there are different requirements for the ValueSet bindings.
Also see the examples.
7.2 Binding strength
The FHIR profiles should faithfully reproduce the binding strength from the functional description. It may not always be possible to adopt the binding strength verbatim. For example, when creating slices for ValueSets, the binding strength must be set to required in order to make the discriminator work, even though the binding strength in the functional description is extensible. However, by making the slicing open, conceptually the same result is achieved.
Also see the examples.
7.3 Handling conflicts with base bindings
FHIR base resource might specify a required binding for some of its elements, whereas the corresponding concept in the functional specification uses alternative or more specialized codes. To conform both to FHIR and to the functional description, a ConceptMap will be created to map the codes from the functional specification to the codes from the FHIR ValueSet. This ConceptMap will be linked to the existing ValueSet using the extension permitted-value-conceptmap extension.
If all mappings in the ConceptMap are equal or equivalent, no further action is needed.
7.3.1 Datatype code
When not all codes from the functional specification map cleanly to a required ValueSet from a FHIR base resource with datatype code:
- The ValueSet from the functional description will be bound with the binding strength of the functional concept using the CodeSpecification extension. The extension slice is named after the full English name of the value set according to the functional description, in camelCased notation.
- Mapping to the concepts of the functional description is applied both to the FHIR element and the extension.
- The ConceptMap will be added using the extension permitted-value-conceptmap extension on the FHIR ValueSet.
7.3.2 Datatype CodeableConcept
When not all codes from the functional specification map cleanly to a required ValueSet from a FHIR base resource with datatype CodeableConcept:
CodeableConcept.coding
will be sliced with a discriminator ofvalue
/$this
, based on a required binding on theCodeableConcept.coding
level.- A slice will be created that binds the ValueSet of the functional description:
- The slice is named after the full English name of the value set according to the functional description, in camelCased notation.
- The binding strength is set to required. This is needed in order to make a valid slice definition.
- The minimum cardinality of the slice is set to 1; if the concept is included, bot the FHIR and function model codes are required.
- The ConceptMap is documented using the permitted-value-conceptmap extension on the ValueSet bound in this slice.
binding.description
is set to:In addition to a coding from this ValueSet, the corresponding coding from the FHIR base ValueSet SHALL be communicated. The ConceptMap <[canonical of ConceptMap]> can be used to relate these two ValueSets.
- Mapping to the concepts of the functional description is applied only to the FHIR element, not to the slice.
8 Extensions
Sometimes a concept from the functional model cannot be implemented using the building blocks FHIR offers by default. In this case, an extension might be used to implement such concept. Keep in mind that extensions are often seen as a burden for implementers:
- If it possible to model the concept (cleanly) without an extension, this is usually the preferred way.
- If that's not possible, check if HL7 provides an extension to implements the concept.
- If that's not possible, try to create an extension in a reusable way (or reuse a previously defined extension).
- If that's not possible, create an extension specific for the profile.
Usually the mappings to the functional model, bindings to specific ValueSets and any functional descriptions will be added when the extension is used within a profile. When the extension pertains to a particular profile, this information SHALL be added to the StructureDefinition of the ValueSet.
9 Common patterns
Sometimes different profiles use a common pattern, for example when references to a particular zib requires special guidance. Special care should be taken to ensure that this pattern is implemented in a consistent way. There are several approaches for this:
- When all these profiles share a common base, a base profile can be defined that includes this pattern.
- When the pattern is part of an extension, then it is applied in a common way by definition.
- A datatype profile may be created that can be re-used across resource profiles (using
type.profile
). This datatype profile may include special guidance aimed at profilers. An example of this approach is described in #Referencing zib HealthProfessional.
10 Mandatory FHIR elements without a functional counterpart
On occasion, FHIR requires an element to be populated while the functional model doesn't specify it. For example, the Procedure resource has the required element Procedure.status
, but the zib Procedure, which is mapped to this FHIR resource, doesn't specify such a field.
In these circumstances, an effort should be made to map the zib concepts implicitly to these elements. For example, FHIR Procedure.status
can be inferred from the zib concept ProcedureEndDate; if it is in the past, then the status should be assumed to be completed. If it is not possible to make such an implicit mapping, the FHIR element is left as-is; the implementation guide should describe how the implementer should deal with it, probably using the data-absent-reason extension.
Implicit mappings are documented in the following way:
- The comment of the implicitly mapped element should provide guidance on how to map the functional concept.
- The
mapping
element is populated with the mapped concept, but the description is altered to:[concept name] (implicit, main mapping is on [element name])
. - Other metadata (
.definition
,.short
,.alias
) isn't populated according to the normal guidelines.
11 References that are reversed in FHIR
Functional building blocks often refer each other, but on occasion, the logical direction for the reference in FHIR is in the other direction. For example, zib TextResult defines a reference to zib Procedure, but the association between FHIR resources DiagnosticReport (for zib TextResult) and Procedure (for zib Procedure) is defined on Procedure.report
.
In these situations, the FHIR approach is followed rather than some custom extension or other mechanism. Although this approach cannot enforce the cardinality from the functional model, the use of the default implementation requires the least effort from implementers and gives the best results for interoperability.
These reversed mappings are profiled in the following way:
- In the profile that contains the reference:
- If the element that represents the association between the two resources is a repeating element, it is sliced with a discriminator of
profile
/resolve()
and a slice is added with the target(s) set to the target profile(s). Otherwise, the target profile is just added to the list of targets. - The
.mapping
element is populated with the mapped concept, but the description is altered to:Reversed reference for [functional building block name].[concept name]"
- The
.short
and slice name, if used, use the English name of the target rather than the concept name. - An
.alias
containing the Dutch name of the target is added. - The
.comment
contains an (additional) note in the following form:Please note that on a functional level, [functional building block A] references [functional building block B], but in FHIR this direction is reversed."
.definition
can be populated with the (modified) definition from the functional building block, but only if it provides useful information to the implementer.- The cardinality of the element is unaffected.
- If the element that represents the association between the two resources is a repeating element, it is sliced with a discriminator of
- In the target profile (where the reference would normally be made if the functional definition is followed):
- The
.comment
on the root contains an (additional) note in the following form:Please note that on a functional level, [functional building block A] references [functional building block B], but in FHIR this direction is reversed. Therefore, the concept [concept name ]([concept identifier]) is mapped on [path to reference] in profile [profile B] instead of in this profile.
- The
Example from profile zib-Procedure-event:
<element id="Procedure.report">
<path value="Procedure.report" />
<slicing>
<discriminator>
<type value="profile" />
<path value="resolve()" />
</discriminator>
<rules value="open" />
</slicing>
</element>
<element id="Procedure.report:textResult">
<path value="Procedure.report" />
<sliceName value="textResult" />
<short value="TextResult" />
<comment value="Please note that on a functional level, zib TextResult references zib Procedure, but in FHIR this direction is reversed." />
<alias value="TekstUitslag" />
<type>
<code value="Reference" />
<targetProfile value="http://nictiz.nl/fhir/StructureDefinition/zib-TextResult" />
</type>
<mapping>
<identity value="zib-textresult-v4.4-2020EN" />
<map value="NL-CM:13.2.5" />
<comment value="Reversed reference for zib TextResult.Procedure" />
</mapping>
</element>
And in zib-TextResult:
<element id="DiagnosticReport">
<path value="DiagnosticReport" />
...
<comment value="Please note that on a functional level, zib TextResult references zib Procedure, but in FHIR this direction is reversed. Therefore the concept Procedure (NL-CM:13.2.5) is mapped on `Procedure.report:textResult` in profile zib-Procedure-event instead of in this profile." />
...
12 Practical guidelines
12.1 Identity of artifacts
12.1.1 Canonical URL, id, name and title
Conformance resources can have multiple types of identifying information, which are related at some level:
.url
- The canonical URL, which is the external identifier for conformance resources. All conformance resources SHALL have a canonical URL. This URL is preferably resolvable but does not have to be processable. Canonical URL's are about the identity of artifacts, not necessarily about retrieval location. Canonical URLs aren't meant to be human recognizable.
.id
- This should align with the latter part of the canonical URL.
.name
- A recognizable name that is still computer processable.
.title
- A recognizable title purely for human consumption.
URIs for the latter (for artifacts living in ART-DECOR) are described in ART-DECOR FHIR_URIs.
12.1.1.1 Profiles, extensions and datatypes
- The
.id
will be constructed in the following way:- For profiles
- representing a functional building block:
- zib profiles:
zib-[English zib name]
- nl-core profiles:
nl-core-[English zib name]
- standard specific:
[project prefix]-[concept name]
- with optionally the following suffix:
- If the functional building block is spread out over multiple resources,
-[ResourceName]
is appended, e.g. zib-HealthProfessional-Practitioner and zib-HealthProfessional-PractitionerRole. This suffix may be absent from the "main" resource, if there's one. - If there are multiple implementations of the same building block for different uses, a use specific suffix is appended. A common pattern for this is when zibs are used both for registered and planned events, resulting in an event and request resource from the FHIR workflow perspective (e.g. zib Procedure which is mapped to both a Procedure and ServiceRequest resource). The following suffixes may be used:
- Past use:
-event
- Future use:
-request
- Past use:
- If the functional building block is spread out over multiple resources,
- zib profiles:
- directly representing a particular concept of a functional building block:
[profile id].[English concept name]
- representing a functional building block:
- For extensions:
- directly representing a specific concept in a single profile:
ext-[English root concept name].[English concept name]
- pertaining to multiple profiles, or not pertaining to specific profiles and generally applicable:
- if the use context is a single resource:
ext-[resource]-[purpose]
- otherwise:
ext-[purpose]
- if the use context is a single resource:
- directly representing a specific concept in a single profile:
- For datatype profiles:
- representing a functional building block: this is regarded a normal profile as described above
- representing a pattern:
pattern-[purpose]
- For profiles
- The canonical URL will then be created as:
http://nictiz.nl/fhir/StructureDefinition/[id]
- The name will be the
.id
capitalized, with hyphens removed. - The title will generally be the
.id
with hyphens replaced by spaces.
Where:
[project prefix]
is preferably the same as its matching ART-DECOR project prefix[purpose]
and[English concept name]
are generally a PascalCased name joining words together, with the first letter of every word capitalized.
12.1.1.2 ValueSets
- For value sets as specified on ART-DECOR, the id will be:
[value set OID]--[effective date as yyyymmddhhmmss]
- The canonical URL will then be created as:
http://decor.nictiz.nl/fhir/ValueSet/[id]
- Both the name and title will be the name of the value set (usually in Dutch).
12.1.1.3 CodeSystems
- For code systems as specified on ART-DECOR, the id will be:
- If a canonical URL is available, then the latter part of the canonical URL.
- Otherwise the code system OID.
- The canonical URL will then be created as:
- When a URI is explicitly stated, then this is used.
- If the code system can be resolved with a URI in the OID register, then this is used.
- Otherwise:
urn:oid:[code system OID]
- Both the name and title will be name of the code system (usually in Dutch). If the code system can be resolved in the OID register it will get that name as registered.
12.1.1.4 NamingSystems
NamingSystems are rarely needed. No strict guidance is given, but in general, the following conventions apply:
- The id will be
namingsystem-[identifier]
, where identifier is usually the latter part of the canonical URI this NamingSystem defines. However, a more informative identifier may be chosen if deemed more appropriate. - The name will be
[identifier]
capitalized and with dashes and such removed, unless a better scheme is deemed more appropriate. - NamingSystems don't have a title or canonical URI.
12.1.1.5 ConceptMaps
- The id will be constructed as:
[source ValueSet.name]-to-[target ValueSet.name]
- The canonical URL will then be:
http://nictiz.nl/fhir/ConceptMap/[id]
- The name will be constructed as:
[source ValueSet.name]_to_[target ValueSet.name]
- The title will be constructed as:
[source ValueSet.name] to [target ValueSet.name]
12.1.1.6 Examples and fixtures
Examples and fixtures (example instances used for test/qualification purposes) are not conformance resources and lack the .url
, .name
and .title
elements. However, to ensure consistency, the .id
is standardized in the following way:
- For fixtures:
[profile id]-[3 character project prefix]-[unique string]
, capped to 64 characters. The[project prefix]
is necessary to prevent the same id from being used by different projects in the same test environment. It is preferably the same as its matching ART-DECOR project prefix. - For examples:
[profile id]-{[3 character project prefix]-}[unique string]
, capped to 64 characters (the[3 character project prefix]
is not needed for examples, but may be included to facilitate re-use of tools for both fixtures and examples).
12.1.2 Folder structure and file name
- profiles
resources/[id].xml
- extensions
resources/[id].xml
- valuesets
resources/terminology/[Dutch name]-[id].xml
- conceptmaps
resources/terminology/conceptmap-[id].xml
- codesystems
resources/terminology/codesystem-[name].xml
- namingsystems
resources/terminology/[id].xml
- examples
examples/[profile id]-[serial number, two digits].xml
12.2 Metadata
12.2.1 StructureDefinitions
12.2.1.1 Metadata on the StructureDefinition root
- version: see #Versioning
- status: as applicable (normally draft or active)
- publisher:
Nictiz
- contact:
- name:
Nictiz
- telecom:
- system:
email
- value:
info@nictiz.nl
- use:
work
- system:
- name:
- description:
- For profiles:
- For zib profiles: the 'Concept' section from the zib. When the profile represents just a part of a zib and the 'Concept' section does not cover the actual use of the profile, a relevant excerpt or an adaptation should be used.
- For nl-core profiles: copy the description from the zib profile.
- For standard specific profiles: as applicable.
- For extensions:
- A description of what the extension is for.
- For profiles:
- purpose:
- For profiles:
- For zib profiles:
This [resource type] resource represents the Dutch [zib ('Zorginformatiebouwsteen', i.e. Health and Care Information Model) [English zib name] [version]([release])]([link to the English zib page on zibs.nl]).
N.B.: This template includes a markdown link: [text](url). A complete example would be:This Patient resource represents the Dutch [zib ('Zorginformatiebouwsteen', i.e. Health and Care Information Model) Patient v3.2 (2020)](https://zibs.nl/wiki/Patient-v3.2(2020EN)).
- For nl-core profiles:
A derived profile from [[id of zib profile]]([canonical of zib profile]) to provide a version better suited for implementation purposes. This profile augments the base profile with elements found in the various use cases that have adopted the zib.
- For standard specific profiles: a description with a reference to the base profile, with an explanation of why it has been added.
- For zib profiles:
- For extensions:
- For extension representing a specific concept:
This extension represents the [concept name] of [name of the building block]]
, followed by a link to the functional description. - For other extensions this will usually be absent.
- For extension representing a specific concept:
- Note: for extensions and datatype profiles, guidance for profilers may be placed here as well.
- For profiles:
- copyright:
Copyright and related rights waived via CC0, https://creativecommons.org/publicdomain/zero/1.0/. This does not apply to information from third parties, for example a medical terminology system. The implementer alone is responsible for identifying and obtaining any necessary licenses or authorizations to utilize third party IP in connection with the specification or otherwise.
- mapping: see #Associating_the_functional_definition_to_StructureDefinitions
- abstract: usually false, but may be set to true when this profile is to be used only as a base profile from which other profiles should be derived.
- comment: when special guidance on the use of this profile is needed, it will be placed here. For example: when this profile has a (non-trivial) relationship to other profiles, when a concept of the functional description is mapped over multiple elements, etc.
Note: this should be guidance aimed at implementers. When the guidance is aimed at profilers, for example in extensions or datatype profiles, it should be added toStructureDefinition.purpose
. - alias:
- for zib profiles: the zib concept name as dictated by #Associating the functional definition to StructureDefinitions.
- for nl-core profiles: the id of the profile (this is actually just a placeholder for when there is no actual difference with the base profile, as FHIR requires
StructureDefinition.differential
orStructureDefinition.snapshot
to be populated).
12.2.1.2 Metadata for elements
- For elements that map directly (not implicitly) to zib concepts:
- The English name from the zib concept is placed on
element.short
(in elements that refer to other zibs, the name is built up likeElementName::ReferenceZibName
, but we only use the part before the double colons). If there are multiple zib elements mapped to a single FHIR element, it will be formatted likeZibConcept1 / ZibConcept2
(unless the names are the same). - The zib concept description is placed on
element.definition
, unless it's the root concept of the zib (because this will always beRoot concept of the [...] information model ...
, which doesn't provide much information). If there are multiple zib elements mapped to a single FHIR element, the descriptions will be placed in a bullet list. - The Dutch zib concept names are placed on
element.alias
- The English name from the zib concept is placed on
- For elements that bind ValueSets:
- If there is a ConceptMap,
.binding.description
will be:Use ConceptMap [ConceptMap.name] to translate terminology from the functional model to profile terminology in ValueSet [ValueSet.name]
- If there is a ConceptMap,
- For elements that are (directly or indirectly) included in a custom constraint defined elsewhere:
- The keys of all related constraints are added to
.condition
(note: this is thus not necessary when the constraint is defined on the element itself). Because.condition
is added to notify the implementer that a constraint applies to the usage if this element, this rule applies to both the element directly mentioned in the constraint as well as its child element(s) that contain the mapping to the functional model.
- The keys of all related constraints are added to
12.2.2 ConceptMaps
12.2.2.1 Metadata on the ConceptMap root
- status: as applicable (normally draft or active)
- publisher:
Nictiz
- contact:
- name:
Nictiz
- telecom:
- system:
email
- value:
info@nictiz.nl
- use:
work
- system:
- name:
- description:
Maps [functional ValueSet] codes as found in [linked description to the functional model] to [FHIR ValueSet] codes as found in FHIR R4.
For zibs, the linked description will be
the Dutch [zib ('Zorginformatiebouwsteen', i.e. Health and Care Information Model) [English zib name] [version]([release])]([link to the English zib page on zibs.nl]).
- copyright:
Copyright and related rights waived via CC0, https://creativecommons.org/publicdomain/zero/1.0/. This does not apply to information from third parties, for example a medical terminology system. The implementer alone is responsible for identifying and obtaining any necessary licenses or authorizations to utilize third party IP in connection with the specification or otherwise.
- In addition, the [bidirectional extension (http://hl7.org/fhir/StructureDefinition/concept-bidirectional)](http://hl7.org/fhir/StructureDefinition/concept-bidirectional) is added with a value to indicate whether this ConceptMap can be used in both ways.
12.3 Miscellaneous
- As a rule of thumb, info is placed 'as close as possible' to the elements that actually represent the data. For example: when slicing, the texts are placed on the slice content, not the slice itself. Similarly, in concept containers like
Observation.component
, this info is placed on the .valueXXX elements. This is also true for the zib mappings. - Slices get a lowerCamelCased name based on the functional concept name.
- New elements defined through extensions get a lowerCamelCased name based on the functional concept name.
- The key for invariants should be:
- for zibs:
zib-[English zib name]-[number]
, eg. zib-Alert-1. - for nl-core:
nl-core-[English zib name]-[number]
. - for use case specific profiles:
[dataset id]-[number]
, where [dataset id] is preferably the same as its matching ART-DECOR project prefix.
- for zibs:
- Inline examples in profiles are added (only) when the usage of an element in the profile is not trivial.
13 Special cases
13.1 Special use of FHIR resources
13.1.1 Measurement qualifiers in Observation.component
Functional models for measurements will usually be mapped onto the FHIR Observation resource. The type of measurement is conveyed using Observation.code
and the result of the measurement is conveyed using Observation.value[x]
, or Observation.component.value[x]
if the measurement consists of multiple components.
However, sometimes the functional model requires that the type of measurement needs to be further specified using a qualifier. For this purpose, the Observation.method
and Observaton.bodySite
elements can be used. If it is not possible to map these concepts to these elements or to a core extension of Observation, they may be mapped to Observation.component
, according to a remark in the specification ("or may provide qualifying information to Observation.code
") and a discussion on Zulip, which concludes that the use of Observatoin.component
for qualifiers is appropriate and preferred above (custom) extensions.
13.1.2 HL7 Vital Signs
The FHIR R4 specification for the Observation resource defines a profile for vital signs measurements. Furthermore, it states that:
If implementations use this Resource when expressing the profile-specific concepts as structured data, they SHALL conform to the following profiles
This means that the following zib profiles would need to be based on the HL7 Vital Signs profile:
- BloodPressure
- BodyHeight
- BodyWeight
- BodyTemperature
- HeadCircumference
- HeartRate
- O2Saturation
The FHIR spec defines derived profiles for each of these vital signs, plus an IG with further recommandations.
However, the HL7 Vital Signs profile imposes two issues that make it impossible to implement zib profiles for the relevant vital signs measurements directly onto it:
- The required terminology binding on
Observation.component
to the Vital Signs Units dataset makes it impossible to use.component
's for representing anything else than a Quantity (like a CodeableConcept or a boolean), which is required by some of these zibs. - The
mustSupport
= true flag found on numerous elements isn't further specified in the HL7 Vital Signs IG, as is required by FHIR.
To circumvent this problem, it has been chosen not to directly base the zib profiles onto the HL7 Vital Signs profiles, but instead create profiles that aim to be (as) functional equivalent (as possible). This means that constraints, terminology bindings, etc. are adopted (except for the terminology binding mentioned above) and that the zib profiles are not in conflict with the equivalent HL7 profiles, except for the requirement that Observation.hasMember
and Observation.derivedFrom
should have a HL7 Vital Signs target -- this requirement cannot be satisfied when cloning a profile. Where possible, the current profiling guidelines are followed rather than the approach by HL7 (e.g. where the HL7 profiles use slices with a fixed code and system to enforce the inclusion of a coding, the zib profiles use a pattern).
On occasion, the zib takes another approach to communicate a certain concept than HL7 Vital Signs. For example, zib BodyHeight specifies a ValueSet for the body position during measurement (lying or standing), while the HL7 Vital Signs suggests to include an additional Observation.code.coding
for "body height measurement while lying down" (only). When the zib approach is not incompatible with the HL7 approach, the zib approach will be followed and the difference will be documented in the .comment
of the relevant element.
To enforce a consistent approach for creating the vital signs zib profiles, a pattern profile has been created. Please note that this should not be interpreted as an equivalent to the base HL7 Vital Signs profile; the zib profiles deliberately skip the common base profile and are directly matched directly to their equivalent HL7 profiles like BloodPressure, BodyHeight, etc. This base profile is not needed for the current use case and omitting it prevents a layer of complexity; for example, the HL7 Vital Signs base profile binds certain ValueSets which are then restricted again in the derived profiles.
13.2 Zib 2020 specific considerations
13.2.1 Implicit subject reference
Starting from release 2020, zibs oftentimes do not explicitly define their subject, i.e. who or what the information is about. However, the general guideline for zibs is that they capture healthcare information about a patient. So implicitly there is a subject, and this subject is usually a patient -- although in some cases it might be inferred that the subject is something or someone else, or can be more than just a patient.
The following guidelines apply for profiling a zib without an explicit subject:
- In the zib profiles, the subject will not be modeled explicitly.
- In the nl-core profiles, the subject will be modeled as a reference to the relevant nl-core profile.
The reason for this is that even though the subject is assumed, when it is not explicitly defined, no formal mapping can be made to a profile. On the other hand, it can be assumed that the subject will be modeled explicitly once the zib is used in a use case scenario,
13.2.2 Referencing zib HealthProfessional
Zib HealthProfessional is mapped onto two profiles: one on FHIR resource PractitionerRole (zib-HealthProfessional-PractitionerRole) and one on FHIR resource Practitioner (zib-HealthProfessional-Practitioner). The PractitionerRole resource covers the recording of the location and types of services that HealthProfessionals are able to provide for a HealthcareProvider, whereas the Practitioner resource captures the personal information, including the identifiers of the health professional.
In FHIR, it is usually possible to define a reference to either resource. However, the reference to this zib from other zibs will be modelled in the following way:
- Only zib-HealthProfessional-PractitionerRole is added to the list of target resources.
- As described in #Constraining references, no restrictions on the base Practitioner or PractitionerRole are made.
This approach has been adopted for two reasons. First, the relation between these two resources points from PractitionerRole to Practitioner; having a PractitionerRole instance, the Practitioner instance can be resolved, but not the other way around. Second, information about a health professional will rarely be communicated without the details captured using PractitionerRole.
This mechanism guides implementers to the use of the zib-HealthProfessional-PractitionerRole profile as the main entry point for zib HealthProfessional. Meanwhile, when there is a need to communicate the zib-HealthProfessional-Practitioner profile instead, this is still possible as the base resource Practitioner is still available.
To ensure consistent documentation of this mechanism, the profile http://nictiz.nl/fhir/StructureDefinition/pattern-HealthProfessionalReference has been created.
13.2.3 References to zib MedicalDevice
There are quite a few zibs that reference zib MedicalDevice. In FHIR, this association is implemented using a reversed reference from the DeviceUseStatement resource representing zib MedicalDevice (zib-MedicalDevice). However, because of the high number of references, the guidelines described in #References_that_are_reversed_in_FHIR would result in a chaotic collection of slices defined in the zib-MedicalDevice profile. Therefore, a slightly adapted approach has been chosen for this profile:
- There's a single slice defined for all the zib MedicalDevice references:
DeviceUseStatement.reasonReference:zibMedicalDeviceReference
. - The
.short
of this slice is fixed onzib MedicalDevice reference
instead of a concatenation of all the target profiles. - Similarly, the
.definition
and.comment
carry a general explanation about the use of this slice. - For each zib referring zib MedicalDevice:
- The profile is added to this list of target profiles (needs to be overwritten with the nl-core version in the nl-core layer).
- The mapping is added (with the "Reversed reference" line as specified in #References_that_are_reversed_in_FHIR).
- The Dutch name is added as
.alias
(as specified in #References_that_are_reversed_in_FHIR).
Profiles that derive from zib-MedicalDevice in the context of a particular zib (like zib HearingFunction and zib VisualFunction) cannot re-use this slice for their own reference (the target profile is not derived from one of the profiles listed in the resource). Therefore, they should set the cardinality of this general slice to 0..0 and define their own reference slice.
14 Data type mapping
In most cases, the mapping between ART-DECOR, zib and FHIR datatypes is straightforward, though there are a number of cases which are not as clear-cut. The table below shows how datatypes from the functional models should be mapped to FHIR.
ART-DECOR | zib | FHIR | Remarks |
---|---|---|---|
count | INT | Count or integer | Count in FHIR is derived from Quantity. This is appropriate for observations, such as a count of red blood cells in a specimen. Count in FHIR is a Quantity with system set to http://unitsofmeasure.org and code set to 1 (for units). If this is not appropriate, use integer.
|
boolean | BL | boolean | |
blob | ED | base64Binary or Attachment | |
code | CD | CodeableConcept or coding or code | In general, CodeableConcept will be the right choice. See Using Codes in Resources for details. |
complex | ANY | BackboneElement | complex is data which is not further defined in DECOR, and thus cannot be translated. |
currency | - | Money | Does not have a zib counterpart currently. Theoretically this could be MO |
date | - | date | Does not have a zib counterpart currently. Closest counterpart could be TS |
datetime | TS | dateTime | |
decimal | - | decimal | Does not have a zib counterpart currently. Theoratically this could be REAL |
duration | - | Duration | Does not have a zib counterpart currently. Closest counterpart could be PQ |
identifier | II | Identifier | |
ordinal | CO | CodeableConcept or coding or code | See Using Codes in Resources for details. |
string | ST | string or markdown | |
ratio | - | Ratio | Does not have a zib counterpart currently. Closest counterpart could be RTO |
text | - | string | Does not have a zib counterpart currently. |
quantity | PQ | Quantity |