This
page
is
part
of
the
FHIR
Specification
(v3.0.2:
STU
3).
The
current
version
which
supercedes
this
version
is
5.0.0
.
For
a
full
list
Continuous
Integration
Build
of
available
versions,
see
FHIR
(will
be
incorrect/inconsistent
at
times).
See
the
Directory
of
published
versions
.
Page
versions:
R5
R4B
R4
R3
R2
Responsible
Owner:
FHIR
Infrastructure
Work
Group
|
|
The base FHIR specification (this specification) describes a set of base resources, frameworks and APIs that are used in many different contexts in healthcare. However, there is wide variability between jurisdictions and across the healthcare ecosystem around practices, requirements, regulations, education and what actions are feasible and/or beneficial.
For
this
reason,
the
FHIR
specification
is
a
"platform
specification"
"platform
specification"
-
it
creates
a
common
platform
or
foundation
on
which
a
variety
of
different
solutions
are
implemented.
As
a
consequence,
this
specification
usually
requires
further
adaptation
to
particular
contexts
of
use.
Typically,
these
adaptations
specify:
Note that because of the nature of the healthcare ecosystem, there may be multiple overlapping sets of adaptations - by healthcare domain, by country, by institution, and/or by vendor/implementation.
There is a general hierarchy of implementation guidance, each making more agreements with an ever smaller community, where the smaller communities have more in common:
International
Base
Agreements,
e.g.,
IPS
,
IPA
,
SDC
etc.
| |
National
Base
Implementation
Guides,
e.g.,
US-Core
,
AU-Base
etc.
|
Healthcare
Clinical
Domain,
e.g.,
mCode
,
Vital
Signs
![]() |
National
Project
Agreements
e.g.,
Dk-Medcom
,
Da
Vinci
DEQM
![]() |
Workflow
profiles
e.g.,
IHE
MHD
,
CH
Lab
Forms
![]() |
| Vendor Specific Implementation Guides | |
| Instution Specific Implementation Guides | |
Note that the implementation guides and profiles that are further down the cascade are generally less likely to be publically available, and more concerned with presence or absence of data and local extensions, while those higher in the cascade are more concerned with meaning, consistent functionality and exchange of data defined in regulation, and are much more likely to be freely publicly available.
HL7
has
a
Guidance
Implementation
Guide
that
provides
specific
guidance
on
best
practices
around
IG
creation
as
well
as
information
about
some
of
the
tooling
extensions
and
capabilities
relevant
to
creation
and
publication
of
implementation
guides.
FHIR defines a cascade of artifacts for this purpose:
| Artifact | Description |
example
|
| Implementation Guide (IG) | A coherent and bounded set of adaptations that are published as a single unit. Validation occurs within the context of the Implementation Guide |
|
| Package | A group of related adaptations that are published as a group within an Implementation Guide |
|
| Conformance Resource | A single resource in a package that makes rules about how an implementation works. These are described below |
![]() |
| Profile |
A
set
of
constraints
on
a
resource
represented
as
a
structure
definition
with
derivation
=
constraint
|
US
Core
Medication
Request
|
The
term
"profile"
is
a
general
one
that
is
used
about
either
a
"package"
verb
'profile',
or
an
"item".
"Profiling"
'profiling',
is
a
general
term
that
describes
used
to
describe
the
process
of
creating
an
implementation
guide,
or
any
of
the
conformance
resources
found
in
one.
a
profile.
Typically, Implementation Guides both restrict and extend APIs, resources and terminologies. FHIR provides a set of resources that can be used to represent and share the decisions that have been made, and allows implementers to build useful services from them. These resources are known as the conformance resources. These conformance resources allow implementers to:
These
resources
need
to
be
used
as
discussed
below,
and
also
following
the
basic
concepts
for
extension
that
are
described
in
"Extensibility"
"Extensibility"
.
For
implementer
convenience,
the
specification
itself
publishes
its
base
definitions
using
these
same
resources.
The
CapabilityStatement
resource
describes
two
different
uses
for
profiles
on
resources:
Resource
Profiles
and
System
Supported
Profiles.
Resource
Profiles
are
specified
using
the
CapabilityStatement.rest.resource.profile
element
and
System
Supported
Profiles
are
specified
using
the
CapabilityStatement.profile
CapabilityStatement.rest.resource.supportedProfile
element.
These profiles describe the general features that are supported by the system for each kind of resource. Typically, this is the superset of all the different use-cases implemented by the system. This is a resource-level perspective of a system's functionality.
These profiles describe the information handled/produced by the system on a per use case basis. Some examples of the uses for these kind of profiles:
Typically,
these
These
profiles
are
a
series
of
variations
on
the
same
set
of
resources
-
represent
different
use
cases
leading
to
handling
the
resources
that
represent
them
differently.
These
use
cases
described
above
all
pertain
to
system
that
produce
and
publish
data,
but
of
the
same
concept
applies
to
systems
that
consume
data.
type
indicated
by
the
CapabilityStatement.rest.resource.type
differently.
For
instance:
For
a
producer
system
and
a
consumer
system
to
exchange
data
successfully
based
on
one
of
these
supported
system
profiles,
it's
it
is
not
enough
to
know
that
the
systems
happen
to
have
system
profiles
that
overlap
for
the
use
case
of
interest;
the
consumer
must
be
able
to
filter
the
total
set
of
resources
made
available
by
the
producer
system
and
deal
only
with
the
ones
relevant
to
the
use
case.
As
an
example,
consider
a
laboratory
system
generating
thousands
of
reports
a
day.
1%
of
those
reports
are
a
particular
endocrine
report
that
a
decision
support
system
knows
how
to
process.
Both
systems
declare
that
they
support
the
particular
endocrine
report
profile,
but
how
does
the
expert
decision
support
system
actually
find
the
endocrine
reports
that
it
knows
how
to
process?
One
possible
option
is
for
the
expert
decision
support
system
to
receive
every
single
report
coming
from
the
lab
system,
check
whether
it
conforms
to
the
profile
or
not,
and
then
decide
whether
to
process
it.
Checking
whether
a
resource
conforms
to
a
particular
profile
or
not
is
a
straight
forward
operation
(one
option
is
to
use
the
provided
tools
for
this
),
but
this
is
a
very
inefficient
way
-
the
expert
decision
support
system
has
to
receive
and
process
100
times
as
many
resources
as
it
uses.
To
help
a
consumer
find
the
correct
set
of
reports
for
a
use-case,
use
case,
a
producer
of
resources
also
SHALL,
for
any
profile
declared
in
Conformance.profile:
may:
Beyond
these
requirements,
a
producer
of
resources
SHOULD
ensure
that
any
resource
instance
that
would
reasonably
To
communicate
which
profiles
will
be
expected
to
conform
to
declared,
the
declared
profiles
producer
SHOULD
be
published
in
this
form.
use
the
standard
Declared
Profile
extension
on
the
CapabilityStatement.
STU Note:Note to Implementers:thereThere are many uninvestigated issues associated with this use of profiles. HL7 is actively seeking feedback from users who experiment in this area, and users should be prepared for changes to features and obligations in this area in the future.Feedback is welcome here
.
A
CapabilityStatement
resource
lists
the
REST
interactions
(read,
update,
search,
etc.)
that
a
server
provides
or
that
a
client
uses,
along
with
some
supporting
information
for
each.
It
can
also
be
used
to
define
a
set
of
desired
behavior
(e.g.
behaviors
(e.g.,
as
part
of
a
specification
or
a
Request
for
Proposal).
The
only
interaction
that
servers
are
required
to
support
is
the
capabilities
interaction
itself
-
to
retrieve
the
server's
CapabilityStatement.
Beyond
that,
servers
and
clients
support
and
use
whichever
API
calls
are
relevant
to
their
use
case.
In
addition
to
the
operations
that
FHIR
provides,
servers
may
provide
additional
operations
that
are
not
part
of
the
FHIR
specification.
Implementers
can
safely
do
this
by
appending
a
custom
operation
name
prefixed
with
'$'
to
an
existing
FHIR
URL,
as
the
Operations
framework
does.
The
Conformance
resource
supports
defining
what
OperationDefinitions
make
use
of
particular
names
on
an
end-point.
If
services
are
defined
that
are
not
declared
using
OperationDefinition,
it
may
be
appropriate
to
use
longer
names,
reducing
the
chance
of
collision
(and
confusion)
with
services
declared
by
other
interfaces.
The
base
specification
will
never
define
operation
names
with
a
"."
"."
(period)
in
them,
so
implementers
are
recommended
to
use
some
appropriate
prefix
for
in
their
names
(such
as
"ihe.someService")
"ihe.someService")
to
reduce
the
likelihood
of
name
conflicts.
Implementations are encouraged, but not required, to define operations using the standard FHIR operations framework - that is, to declare the operations using the OperationDefinition resource, but some operations may involve formats that can't be described that way.
Implementations are also able to extend the FHIR API using additional content types. For instance, it might be useful to read or update the appointment resources using a vCard based format. vCard defines its own mime type, and these additional mime types can safely be used in addition to those defined in this specification.
Extending
and
restricting
resources
(collectively
known
as
'profiling
a
resource')
is
done
with
a
"StructureDefinition"
"StructureDefinition"
resource,
which
is
a
statement
of
rules
about
how
the
elements
in
a
resource
are
used,
and
where
extensions
are
used
in
a
resource.
One key function of profiles is to change the cardinality of an element. A profile can restrict the cardinality of an element within the limits of the base structure it is constraining. This table summarizes what types of restrictions are allowed:
|
derived
(across)
base (down) |
0..0
(Not used) |
0..1
(optional) |
0..n
(optional, many) |
1..1
(required) |
1..n
(at least 1) |
| 0..1 | yes | yes | no | yes | no |
| 0..* | yes | yes | yes | yes | yes |
| 1..1 | no | no | no | yes | no |
| 1..* | no | no | no | yes | yes |
When
a
profile
is
constraining
another
profile
where
there
are
more
cardinality
options
(e.g.
(e.g.,
low
is
not
just
0
or
1,
and
high
is
not
just
1
or
*),
the
same
principles
still
apply:
the
constraining
profile
can
only
allow
what
the
base
profile
allows.
Note that though a profile can constrain an element from x..* to x..1, this doesn't make any difference to the representation in the JSON format - the element will still be represented in an array. As an example, take Patient.name which has a cardinality of 0..*. In an unprofiled Patient, this will be represented as:
{
"resourceType" : "Patient",
"name" : [{
"text" : "Peter James"
}]
}
Even if a profile is created on the resource that narrows the cardinality to 1..1, applications will still process the resource without knowledge of the profile. For this reason the representation will still be the same.
What
Structure
Definitions
StructureDefinitions
can
do
when
they
are
constraining
existing
resources
and
datatypes
is
limited
in
some
respects:
The consequence of this is that if a profile mandates extended behavior that cannot be ignored, it must also mandate the use of a modifier extension . Another way of saying this is that knowledge must be explicit in the instance, not implicit in the profile.
As
an
example,
if
a
profile
wished
to
describe
that
a
Procedure
resource
was
being
negated
(e.g.
(e.g.,
asserting
that
it
never
happened),
it
could
not
simply
say
in
the
profile
itself
that
this
is
what
the
resource
means;
instead,
the
profile
must
say
that
the
resource
must
have
an
extension
that
represents
this
knowledge.
There is a facility to mark resources to indicate that they can only be safely understood by a process that is aware of and understands a set of published rules. For more information, see Restricted Understanding of Resources .
Some properties of an element are purely descriptive and aren't used as part of the validation process. These elements can be refined to reflect constraints applied elsewhere for the element and/or to reflect the context of use of the element within the profile. Changes need to be made cautiously however. The meaning and guidance provided in the base resource or profile can't be invalidated, only constrained or contextualized.
There are two types of changes that can be made to descriptive elements - revising the existing content, or adding or removing elements. Removing an element is only appropriate if the element no longer applies in the context of the constraints/domain space of the profile. The following table indicates which types of changes are allowed for which elements:
| Element | Revise? | Add? | Remove? |
|---|---|---|---|
| label | Yes | ||
| code.coding | Yes | Yes | |
| short | Yes | ||
| definition | Yes | ||
| comment | Yes | Yes | Yes |
| requirements | Yes | Yes | |
| alias | Yes | Yes | Yes |
| example | Yes | Yes | Yes |
| mapping | Yes | Yes | Yes |
A
"constraint"
Structure
Definition
"constraint"
StructureDefinition
specifies
a
set
of
restrictions
on
the
content
of
a
FHIR
resource
or
data
type,
datatype,
or
an
additional
set
of
constraints
on
an
existing
profile.
A
given
structure
definition
is
identified
by
its
canonical
URL,
which
SHOULD
be
the
URL
at
which
it
is
published.
The
following
kinds
of
statements
can
be
made
about
how
an
element
is
used,
using
a
series
of
Element
Definitions
:
or
HL7
v3
)
for
the
resource
when
used
in
a
particular
context
Any
changed
definitions
SHALL
be
restrictions
that
are
consistent
with
the
rules
defined
in
the
resource
in
the
FHIR
Specification
from
which
the
profile
is
derived.
Note
that
some
of
these
restrictions
can
be
enforced
by
tooling
(and
are
by
the
FHIR
tooling),
but
others
(e.g.
(e.g.,
alignment
of
changes
to
descriptive
text)
cannot
be
automatically
enforced.
Note that structure definitions cannot 'remove' mappings and constraints that are defined in the base structure, but for purposes of clarity, they can refrain from repeating them.
A structure definition contains a linear list of element definitions . The inherent nested structure of the elements is derived from the path value of each element. For instance, a sequence of the element paths like this:
defines the following structure:
<Root>
<childA>
<grandChild1/>
</childA>
<childB/>
</Root>
or its JSON equivalent. The structure is coherent - children are never implied, and the path statements are always in order. The element list is a linear list rather than being explicitly nested because element definitions are frequently re-used in multiple places within a single definition, and this re-use is easier with a flat structure.
Some backbone elements recurse. e.g., Questionnaire.item. When a profile defines constraints on such elements, the constraints apply to the recursive references to those elements as well. i.e., If Questionnaire.item is constrained to have a type of 'group', that will cause Questionnaire.item.item, Questionnaire.item.item.item, etc. to all have the same constraint.
If there is a need to enforce constraints on a recursive item that apply at some levels but not others (e.g., only the root, or everything except the root), formal constraints using FHIRPath can be used that limit their behavior to only the root or other specific levels of nesting can be used.
Structure
Definitions
StructureDefinitions
may
contain
a
differential
statement,
a
snapshot
statement
or
both.
Differential
statements
describe
only
the
differences
that
they
make
relative
to
another
the
structure
definition
they
constrain
(which
is
most
often
the
base
FHIR
resource
or
data
type).
datatype).
For
example,
a
profile
may
make
a
single
element
mandatory
(cardinality
1..1).
In
the
case
example
of
a
differential
structure,
it
will
contain
a
single
element
with
the
path
of
the
element
being
made
mandatory,
and
a
cardinality
statement.
Nothing
else
is
stated
-
all
the
rest
of
the
structural
information
is
implied
(note:
(note
that
this
means
that
a
differential
profile
can
be
sparse
and
only
mention
the
elements
that
are
changed,
without
having
to
list
the
full
structure.
This
rule
includes
the
root
element
-
it
is
not
needed
in
a
sparse
differential).
Note that a differential can choose not to constrain elements. Doing so means that the profile will be more flexible in terms of compatibility with other profiles, but will require more work to support from implementing systems. Alternatively, a profile can constrain all optional elements to be not present (max cardinality = 0) - this closes the content, which makes implementation easier, but also reduces its usefulness.
In
order
to
properly
understand
a
differential
structure,
it
must
be
applied
to
the
structure
definition
on
which
it
is
based.
In
order
to
save
tools
from
needing
to
support
this
operation
(which
is
computationally
intensive
-
and
impossible
if
the
base
structure
is
not
available),
a
StructureDefinition
can
also
carry
a
"snapshot"
"snapshot"
-
a
fully
calculated
form
of
the
structure
that
is
not
dependent
on
any
other
structure.
The
FHIR
project
provides
tools
for
the
common
platforms
that
can
populate
a
snapshot
from
a
differential
(note
that
the
tools
generate
complete
verbose
snapshots;
they
do
not
support
suppressing
mappings
or
constraints).
StructureDefinitions can contain both a differential and a snapshot view. In fact, this is the most useful form - the differential form serves the authoring process, while the snapshot serves the implementation tooling. StructureDefinition resources used in operational systems should always have the snapshot view populated.
One
common
feature
of
constraining
Structure
Definitions
StructureDefinitions
is
to
take
an
element
that
may
occur
more
than
once
(e.g.
(e.g.,
in
a
list),
and
then
split
the
list
into
a
series
of
sublists,
sub-lists,
each
with
different
restrictions
on
the
elements
in
the
sublist
sub-list
with
associated
additional
meaning.
In
FHIR,
this
operation
is
known
as
"Slicing"
"Slicing"
a
list.
It
is
common
to
"slice"
"slice"
a
list
into
sub-lists
with
each
containing
just
one
element,
effectively
putting
constraints
on
each
element
in
the
list.
This
technique
can
also
be
used
on
elements
that
do
not
repeat,
but
that
have
a
choice
of
data
types.
Here is an example to illustrate the process:
In
this
example,
the
base
structure
definition
for
the
resource
Observation
defines
the
"component"
"component"
element
which
contains
a
nested
code
and
a
value
for
observations
that
have
multiple
values.
A
classic
example
of
this
kind
of
observation
is
a
blood
pressure
measurement
-
it
contains
2
values,
one
for
systolic,
and
one
for
diastolic
(
example
).
This
diagram
shows
the
conceptual
process
of
'slicing'
the
component
list
into
systolic
and
diastolic
slices
(note:
(note
that
to
avoid
clutter,
the
"name"
"name"
attribute
of
Observation
is
shown
as
just
a
code
not
a
full
CodeableConcept).
The
structure
definition
for
Blood
Pressure
splits
the
component
list
into
two
sublists
sub-lists
of
one
element
each:
a
systolic
element,
and
a
diastolic
element.
Each
of
these
elements
has
a
fixed
value
for
the
code
element
(a
fixed
LOINC
code
for
the
name),
and
both
have
a
value
of
type
Quantity.
This
process
is
known
as
"slicing"
"slicing"
and
the
Systolic
and
Diastolic
elements
are
called
"slices".
"slices".
Note
that
when
the
resource
is
exchanged,
the
serialization
format
that
is
exchanged
is
not
altered
by
the
constraining
definition.
This
means
that
the
item
profile
names
defined
in
the
structure
definition
("systolic",
("systolic",
etc.
in
this
example)
are
never
exchanged.
A
resource
instance
looks
like
this:
<Observation> ... <component><code {LOINC="8480-6"}/><code {LOINC="8480-6"}/> <value ...> </component> <component><code {LOINC="8462-4"}/><code {LOINC="8462-4"}/> <value ...> </component> </Observation>
In
order
to
determine
that
the
first
related
item
corresponds
to
"Systolic"
"Systolic"
in
the
structure
definition,
so
that
it
can
then
determine
to
which
additional
constraints
for
a
sub-list
the
item
conforms,
the
system
checks
the
values
of
the
elements.
In
this
case,
the
"code"
"code"
element
in
the
target
resource
can
be
used
to
determine
which
slice
that
target
refers
to.
This
element
is
called
the
"discriminator".
"discriminator".
In
the
general
case,
systems
processing
resources
using
a
structure
definition
that
slices
a
list
can
determine
the
slice
corresponding
to
an
item
in
the
list
by
checking
whether
the
item's
content
meets
the
rules
specified
for
the
slice.
This
would
require
a
processor
to
be
able
to
check
all
the
rules
applied
in
the
slice
and
to
do
so
speculatively
in
a
depth-first
fashion.
Both
of
these
requirements
are
inappropriately
difficult
for
an
operational
system,
and
particularly
for
generated
code
(e.g.
(e.g.,
software
that
is
automatically
produced
based
on
the
StructureDefinition).
Thus,
to
provide
a
better
way
to
distinguish
slices,
a
sliced
element
can
designate
a
field
or
set
of
fields
that
act
as
a
"discriminator"
-
they
are
"discriminator"
used
to
tell
the
slices
apart.
When
a
discriminator
is
provided,
the
composite
of
the
values
of
the
elements
designated
in
the
discriminator
is
unique
and
distinct
for
each
possible
slice
and
applications
can
easily
determine
which
slice
an
item
in
a
list
is.
The
intention
is
that
this
can
be
done
in
generated
code,
e.g.
e.g.,
using
a
switch/case
statement.
When a constraining structure designates one or more discriminators, it SHALL ensure that the possible values for each slice are different and non-overlapping, so that the slices can easily be distinguished.
Each discriminator is a pair of values: a type that indicates how the field is processed when evaluating the discriminator, and a FHIRPath expression that identifies the element in which the discriminator is found. There are five different processing types for discriminators:
| value |
The
slices
have
different
values
in
the
nominated
|
| exists |
The
slices
are
differentiated
by
the
presence
or
absence
of
the
nominated
|
| pattern |
The
slices
have
different
values
in
the
nominated
element,
as
determined
by
|
| type |
The
slices
are
differentiated
by
type
of
the
nominated
|
| profile |
The
slices
are
differentiated
by
conformance
of
the
nominated
element
to
a
|
| position | The slices are differentiated by their index. This is only possible if all but the last slice have min=max cardinality, and the (optional) last slice contains other undifferentiated elements. |
The FHIRPath statement that allows for the selection of the element on which the discriminator is based is a restricted FHIRPath statement that is allowed to include:
component.value
)
extension(url)
to
allow
selection
of
a
particular
extension
resolve()
to
allow
slicing
ofType()
to
allow
choosing
a
type
in
a
polymorphic
element
See the full details about the restricted FHIRPath statement .
The element(s) asserting the constraints that disambiguate the slices may be asserted in different profiles than the one that defines the slicing rule. This will always happen if the discriminator uses 'resolve', but it may occur even when the element in question falls within the same resource. For example, a profile might slice Patient.address by 'use' and then declare multiple profiles for Address.type, each of which has a different fixed value for the 'use' element.
Further notes about the use of the different discriminator types:
| value |
This
is
the
most
commonly
used
discriminator
type:
to
decide
based
on
the
value
of
an
element
as
specified
by
a
fixed
value,
a
pattern
value,
or
a
required
value
set
binding.
Typical
example:
slice
on
the
value
of
Patient.telecom.system
,
for
values
phone,
email,
or
slice
on
the
value
of
Observation.code
,
for
values
LOINC
codes
1234-5,
4235-8
etc.
There
are
some
examples
of
slicing
based
on
discriminator-type
value
with
patterns.
|
| pattern | This code means the same as value, and is retained for backwards compatibility reasons |
| exists | This is not used commonly - it only has 2 values, so not much discrimination power. It's mainly used as an adjunct slicing criteria along with other discriminators. Elements used like this are mostly complex backbone elements. The slices are differentiated by the presence or absence of the nominated element. There SHALL be no more than two slices. The slices are differentiated by the fact that one must have a max of 0 and the other must have a min of 1 (or more). The order in which the slices are declared doesn't matter. Typical example: slice on the pattern of Observation.code and the presence of Observation.component. |
| type |
Used
to
match
slices
based
on
the
type
of
the
item.
While
it
can
be
used
with
polymorphic
elements
such
as
Observation.value[x]
,
mostly
it
is
used
with
Resource
types
on
references,
to
apply
different
profiles
based
on
the
different
resource
type.
Typical
example:
slice
on
the
type
of
List.item.resolve()
for
the
types
Patient,
RelatedPerson.
|
| profile |
Used
to
match
slices
based
on
the
whether
the
item
conforms
to
the
specified
profile.
This
provides
the
most
power,
since
the
full
range
of
profiling
capabilities
are
available,
but
it
is
also
the
hardest
to
implement,
and
requires
the
most
processing
(>1000-fold
compared
to
the
others).
Implementers
should
use
this
only
where
absolutely
required.
Typical
example:
slice
on
the
type
of
Composition.section.entry().resolve()
for
the
profiles
Current-Clinical-Condition,
Past-Medical-Event,
etc.
|
| position |
Used
to
match
slices
based
on
their
index.
This
is
only
possible
if
all
but
the
last
slice
have
a
fixed
cardinality
where
min
>
0
and
min
=
max
.
The
last
slice
MAY
have
min
!=
max
.
Typical
example:
slice
on
Practitioner.name
to
require
that
the
first
name
be
the
usual
name
for
the
practitioner,
and
it
must
be
present
|
Each
slice
must
use
the
element
definition
for
the
element
element(s)
in
the
discriminator(s)
to
ensure
that
the
slices
are
clearly
differentiated
(by
by
assigning
a
fixed
value,
a
specific
type,
or
a
profile,
an
appropriate
value
domain,
depending
on
the
discriminator
type.
If
the
type
is
'value',
value
,
or
pattern
,
then
the
element
definition
must
use
either
either:
It is the composite (combined) values of the discriminators that are unique, not each discriminator alone. For example, a slice on a list of items that are references to other resources could designate fields from different resources, where each resource only has one of the designated elements, as long as they are distinct across slices.
A structure definition is not required to designate any discriminator at all for a slice, but those that don't identify discriminators are describing content that is very difficult to process, and so this is discouraged.
Within
a
structure
definition,
a
slice
is
defined
using
multiple
element
entries
that
share
a
path
but
have
distinct
name
s.
These
entries
together
form
a
"slice
group"
"slice
group"
that
is:
Some
examples
of
descriminators:
discriminators:
| Context | Discriminator Type | Discriminator Path | Interpretation |
| List.entry | value |
|
Entries are differentiated by the name element on the target resource - probably an observation, which could be determined by other information in the profile |
| List.entry | type |
|
Entries are differentiated by the type of the target element that the reference points to |
| List.entry | profile |
|
Entries
are
differentiated
by
a
profile
tag
on
the
target
of
the
reference,
as
specified
by
a
structure
definition
|
| List.entry | value |
|
Entries are differentiated by the value of the code element in the extension with the designated URL |
| List.entry.extension | value | url | Extensions are differentiated by the value of their url property (usually how extensions are sliced) |
| List.entry | type, value |
|
|
| EndPoint.header | value | value | Slicing a primitive field by value, e.g., to specify a set list of headers in a profile |
| Observation.value[x] | type | $this |
Different
constraints
|
Note
that
Notes:
url
element,
though
they
may
be
resliced
on
additional
elements
where
required.
resolve()
,
any
elements
that
are
specified
in
the
discriminator
path
beyond
the
resolve()
function
(e.g.,
'name'
in
item.resolve().name)
are
referring
to
the
corresponding
element
in
the
resource
identified
by
the
reference
,
as
constrained
by
the
applicable
targetProfile
(regardless
of
the
discrinator
type),
and
it
is
in
the
profile
that
the
targetProfile
refers
to
where
a
fixed
value
or
pattern
for
the
element
must
be
declared.
The
targetProfile
itself
is
declared
in
the
element
in
the
slice
that
immediately
precedes
the
resolve()
function
in
the
discriminator
path
(e.g.,
'item'
in
item.resolve().name),
and
that
element
is
the
final
element
that
the
slice
declares.
When an element of a fixed cardinality m..n is sliced, the following rules apply:
n
n
n
m
-
the
only
situation
where
this
is
allowed),
but
the
total
number
of
elements
in
the
instance
must
still
be
greater
or
equal
to
m
m
.
The
cardinality
of
the
sum
of
the
slice
minimums
must
be
met
as
well
as
the
minimum
on
the
base
element.
There
is
a
special
slice,
called
the
default
slice.
This
allows
a
profile
to
describe
a
set
if
of
specific
slices,
and
then
make
a
set
of
rules
that
apply
to
all
of
the
remaining
content
that
is
not
in
one
of
the
defined
slices.
Some
rules
about
the
default
slice:
@default
.
The
sliceName
'@default'
is
reserved
and
cannot
be
used
in
any
other
context
One
use
of
a
default
slice
would
be
the
case
where
the
profile
slices
an
identifier
element
to
require
a
set
of
known
identifiers,
where
the
type
element
is
prohibited
(since
they
are
known
identifiers)
but
requires
type
on
all
other
identifiers
if
any
are
present.
In
this
case,
the
default
slice
makes
no
rules
about
the
identiifer.system
identifier.system
(which
is
the
slicing
discriminator),
but
fixes
the
cardinality
of
type
to
1..1
in
the
@default
slice.
In all the examples above, a profile is applied to an entire resource, and re-useability is at the scope of the entire resource. It is possible, however, to apply a profile at the point of a particular element in a resource. A common case where this would be useful is for section templates in a profile on Composition, where it is common to have a set of rules for the content of a section that are used across multiple different documents (profiles on Composition). This is supported by the profile-element extension.
The profile-element extension is an instruction to a validator to apply the profile starting at the nominated element (by its ID). To use this, a profile author would first define a profile on Composition section:
<StructureDefinition xmlns="http://hl7.org/fhir">
...
<url value="http://hl7.org/fhir/example/StructureDefinition/document-section-library">
<!-- this profile is 'abstract' - it defines a library of sections,
so it doesn't make sense to use it as a profile directly -->
<abstract value="true"/>
<!-- this profile applies rules to the Composition resource -->
<type value="Composition"/>
<baseDefinition value="http://hl7.org/fhir/StructureDefinition/Composition"/>
<derivation value="constraint"/>
<differential>
<!-- set up slicing on Composition.section - by section.code in this case.
This slicing is never used anywhere since this library is abstract,
but it's needed for presenting the library coherently
e.g., in an implementation guide
-->
<element>
<path value="Composition.section"/>
<slicing>
<discriminator>
<type value="value"/>
<path value="code"/>
</discriminator>
<description value="Slice by .section.code when using this section library"/>
<ordered value="true"/>
<rules value="closed"/>
</slicing>
</element>
<!--
a set of rules on a composition section
The value of the id is fixed by the rules on
StructureDefinition/ElementDefinition
-->
<element id="Composition.section:codeB">
<path value="Composition.section"/>
<sliceName value="codeB"/>
</element>
<!-- simple rules for example:
there will be a title and the code will at least contain code-b -->
<element>
<path value="Composition.section.title"/>
<min value="1"/>
</element>
<element>
<path value="Composition.section.code"/>
<min value="1"/>
<patternCodeableConcept>
<coding>
<system value="http://hl7.org/fhir/test/CodeSystem/imaginary"/>
<code value="code-b"/>
</coding>
</patternCodeableConcept>
</element>
...
Then to apply the section level profile to an element:
<element>
<!-- Slice on Composition.section by the code.
It's not necessary to slice to use this extension,
but it normally be necessary to achieve the desired outcome
-->
<path value="Composition.section"/>
<slicing>
<discriminator>
<type value="pattern"/>
<path value="code"/>
</discriminator>
<description value="Slice by .section.code"/>
<ordered value="true"/>
<rules value="closed"/>
</slicing>
</element>
<element>
<!-- first slice -->
<path value="Composition.section"/>
<sliceName value="code-B"/>
<min value="1"/>
<type>
<code value="BackboneElement"/>
<!-- the extension says where in the referenced profile to start -->
<profile value="http://hl7.org/fhir/example/StructureDefinition/document-section-library">
<extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-profile-element">
<valueString value="Composition.section:codeB"/>
</extension>
</profile>
</type>
</element>
Profiles
can
be
based
on
other
profiles,
profiles
and
can
apply
further
constraints
to
those
already
specified.
This
is
a
useful
technique,
but
implementers
should
be
wary
of
over-use
-
humans
have
trouble
understanding
the
implications
of
deep
stacks
of
constraining
profiles.
When
a
profile
constrains
another
profile,
it
can
make
additional
constrainta,
constraints,
including
extending
the
discriminator,
adding
new
slices
(if
the
slices
are
not
already
closed),
and
slicing
inside
the
existing
slices.
The
rules
for
changing
the
slicing
constraining
ElementDefinition.slicing
are
as
follows:
ElementDefinition.slicing.rule
can
be
open
to
closed
ElementDefinition.slicing.ordered
can
be
false
to
true
It's
sometimes
necessary
to
slice
data
that
has
already
been
sliced
in
the
base
profile
-
that
is,
create
new
slices
within
the
existing
slices.
This
is
called
"Re-slicing".
"Re-slicing".
The
rules
for
re-slicing
are
as
follows:
When you slice, you define a name for each new slice. The name has to be unique across the set of slices in the profile. So if profile A defines an element X with cardinality 0..*, and profile B is derived from profile A, then profile B can either:
Then, profile C derives from profile B. Profile C can do the following:
Note:
Note
that
it
is
possible
for
Profile
C
to
make
rules
that
are
incompatible
with
profile
B,
in
which
case
there
is
no
set
of
instances
that
can
be
valid
against
profile
C
In
addition
to
the
above,
there
are
times
when
Profile
C
will
need
to
further
slice
a
slice
defined
in
B.
In
this
case,
there's
a
need
to
reference
both
the
name
ElementDefinition.sliceName
of
the
original
slice
from
Profile
B
as
well
as
to
define
a
name
an
ElementDefinition.sliceName
for
the
slice
defined
within
Profile
C.
This
is
done
by
separating
the
names
using
"/".
"/".
For
example,
if
Profile
B
defines
the
slice
"example",
"example",
and
profile
C
defines
the
slice
"example/example1",
"example/example1",
then
this
is
deemed
to
be
"example1"
"example1"
slice
of
the
example
slice.
This
process
can
continue
indefinitely
by
separating
each
layer
of
slicing
names
with
the
"/"
"/"
character.
This
pattern
applies
to
@default
too:
@default/@default.
An
extension
definition
defines
the
URL
that
identifies
the
extension
and
which
is
used
to
refer
to
the
extension
definition
when
it
is
used
in
a
resource.
The
extension
definition
also
defines
the
context
where
the
extension
can
be
used
(usually
a
particular
path
or
a
data
type)
datatype)
and
then
defines
the
extension
element
using
the
same
details
used
to
profile
the
structural
elements
that
are
part
of
resources.
This
means
that
a
single
extension
can
be
defined
once
and
used
on
different
Resource
resources
and/or
datatypes,
e.g.
e.g.,
one
would
only
have
to
define
an
extension
for
"hair
color"
"hair
color"
once,
and
then
specify
that
it
can
be
used
on
both
Patient
and
Practitioner.
For further discussion of defining and using extensions, along with some examples, see Extensibility .
Once defined, an extension can be used in an instance of a resource without any Profile declaring that it can, should or must be, but Profiles can be used to describe how an extension is used.
To
actually
prescribe
the
use
of
an
extension
in
an
instance,
the
extension
list
on
the
resource
needs
to
be
sliced.
This
is
shown
in
the
extensibility
examples
Note
that
the
minimum
cardinality
of
an
extension
SHALL
be
a
valid
restriction
on
the
minimum
cardinality
in
the
definition
of
the
extension.
if
If
the
minimum
cardinality
of
the
extension
is
1
when
it
is
defined,
it
can
only
be
mandatory
when
it
is
added
to
a
profile.
This
is
not
recommended
-
the
minimum
cardinality
of
an
extension
should
usually
be
0.
Coded elements have bindings that link from the element to a definition of the set of possible codes that the element may contain. The binding identifies the definition of the set of possible codes and controls how tightly the set of the possible codes is interpreted.
The
set
of
possible
codes
is
either
a
formal
reference
to
a
ValueSet
resource,
which
may
be
version
specific,
or
a
general
reference
to
some
web
content
that
defines
a
set
of
codes.
The
second
is
most
appropriate
where
a
set
of
values
is
defined
by
some
external
standard
(such
as
mime
types).
Alternatively,
where
the
binding
is
incomplete
(e.g.
(e.g.,
under
development)
just
a
text
description
of
the
possible
codes
can
be
provided.
Bindings
have
a
property
that
defines
how
the
strongly
implementations
are
required
to
use
degree
of
flexibility
associated
with
the
set
use
of
codes.
the
codes
in
the
value
set.
See
Binding
Strength
.
for
further
information.
When deriving an element from an element that has additional bindings, an additionalBinding can be constrained if it has the same key. If the base additionalBinding does not have a key, it cannot be constrained. Rules for constraining additionalBinding uses and value sets are the same as for constraining regular bindings.
CodeSystem
resources
can
be
used
to
carry
definitions
of
local
codes
(
Example
)
and
ValueSets
can
mix
a
combination
of
local
codes
and
standard
codes
(e.g.
(e.g.,
LOINC,
SNOMED),
or
just
to
choose
a
particular
set
of
standard
codes
(examples:
LOINC,
SNOMED,
RxNorm).
Profiles
can
bind
to
these
value
sets
instead
of
the
ones
defined
in
the
base
specification,
following
these
rules:
| Binding Strength in base specification | Customization Rules in Profiles |
| required | The value set can only contain codes contained in the value set specified by the FHIR specification |
| extensible | The value set can contain codes not found in the base value set. These additional codes SHOULD NOT have the same meaning as existing codes in the base value set |
|
preferred
|
The value set can contain whatever is appropriate for local use |
Note
that
local
codes
are
not
as
interoperable
as
standard
published
code
systems
(e.g.
(e.g.,
LOINC,
SNOMED
CT,
CT),
so
it
is
preferable
to
use
standard
code
systems.
A profile can change the terminology binding of an element - both strength and value set - within the limits of the base structure it is constraining. This table summarizes the changes that can be made to the binding strength:
|
derived
(across)
base (down) |
required | extensible | preferred | example |
| required | yes | no | no | no |
| extensible | yes | yes | no | no |
| preferred | yes | yes | yes | no |
| example | yes | yes | yes | yes |
Note
that
a
constraining
profile
may
leave
the
binding
strength
the
same
and
change
the
value
set
instead.
Whatever
the
constraining
profile
does,
it
cannot
make
codes
valid
that
are
invalid
in
the
base
structure/profile.
profile.
One
property
of
the
properties
that
can
be
declared
on
profiles
that
is
but
not
declared
on
the
resource
or
data
type
datatype
definitions
is
"Must
Support".
This
'mustSupport',
which
is
a
boolean
property.
If
true,
it
means
that
systems
claiming
to
conform
to
a
given
profile
must
"support"
"support"
the
element.
This
is
distinct
from
cardinality.
It
is
possible
to
have
an
element
with
a
minimum
cardinality
of
"0",
"0",
but
still
expect
systems
to
support
the
element.
The
meaning
of
"support"
"support"
is
not
defined
by
the
base
FHIR
specification,
but
it
can
be
set
to
true
in
a
profile.
When
a
profile
does
this,
it
SHALL
also
make
clear
exactly
what
kind
of
"support"
"support"
is
required.
Examples
might
include:
The
specific
meaning
of
"Must
Support"
for
the
purposes
of
a
particular
profile
"Must
Support"
SHALL
be
described
defined.
Profiles
can
do
this
in
one
of
two
ways:
element.definition
ElementDefinition.comment
,
the
general
StructureDefinition.description
or
in
other
documentation
for
the
implementation
guide
that
includes
the
profile
If creating a profile based on another profile, Must Support can be changed from false to true, but cannot be changed from true to false. Obligations can be added, particularly for different actors, but existing actor obligations cannot be undone or loosened.
When one implementation guide or profile depends on another, the meaning of mustSupport defined in the base artifact applies to those elements marked as mustSupport in that base artifact. However, elements newly defined as mustSupport in the derived artifact take their definition of mustSupport from the new IG/profile. Note that it is possible for the new IG or profile to simply reference the mustSupport artifacts defined in an ancestor artifact if that is the behavior desired.
When a child element is defined as Must Support and the parent element isn't, a system must support the child if it supports the parent, but there's no expectation that the system must support the parent.
Note
that
an
element
that
has
the
property
IsModifier
is
not
necessarily
a
"key"
"key"
element
(e.g.
(e.g.,
one
of
the
important
elements
to
make
use
of
the
resource),
nor
is
it
automatically
mustSupport
-
however
both
of
these
things
are
more
likely
to
be
true
for
IsModifier
elements
than
for
other
elements.
When a child element is defined as Must Support and the parent element isn't, a system must support the child if it support the parent, but there's no expectation that the system must support the parent.
If an Implementation Guide defines a complex element as Must Support, and does not declare any of its child elements as Must Support, then the Implementation Guide should provide further guidance; if there is no further guidance, then the expectation is that implementers must support at least a subset of the child elements of the must-support parent.
The FHIR profile ecosystem has grown rapidly in volume and complexity, with the real-world profusion of use cases being faithfully represented in a profusion of related but different profiles. This specification recommends that profile designers consider these patterns to minimize the complexity to only that which must exist:
The
final
thing
implementations
Implementations
can
do
is
to
define
search
criteria
in
addition
to
those
defined
in
the
specification
itself.
Search
criteria
fall
into
one
of
four
categories:
Additional Search Parameters can be defined using the SearchParameter resource.
When this specification describes a profile, the profile is presented in 5 different forms:
| Text Summary | This presents a short summary human readable summary of the profile - a combination of the author's summary, and some automatically generated summary content |
| Differential Table |
This
is
a
view
of
the
differential
statement
(
see
above
).
For
context,
additional
information
not
in
the
differential
is
also
|
| Full Structure |
This
is
a
view
of
the
snapshot
produced
by
the
profile
(
see
above
).
The
information
is
a
comprehensive
view
of
what
the
profile
|
|
XML
Template
|
An example of what the profile looks like in XML format |
| JSON Template | An example of what the profile looks like in JSON format |
Applications
may
be
required
to
support
more
than
one
profile
at
a
time.
A
typical
example
might
be
an
EHR
application
that
is
required
to
support
a
general
purpose
data
sharing
profile
(such
as
DAF
),
and
also
must
support
specific
profiles
for
decision
support
using
the
same
interface.
The impact of supporting two sets of profiles depends on whether resources are being created or consumed. When an application is creating content, it must create content that conforms to both sets of profiles - that is, the intersection of the profiles. When an application is consuming information, then it must be able to consume content that conforms to either set of profiles - that is, the union of the profiles.
Since
applications
generally
consume
and
produce
resources
at
the
same
time,
conforming
to
more
than
one
profile
may
might
not
be
possible,
unless
the
profiles
are
designed
to
make
statements
at
different
levels
-
and
the
case
above
is
one
such
case,
where
one
profile
is
focused
on
data
access,
provenance,
and
availability,
the
other
profile
is
focused
on
clinical
content.
Accordingly, profiles can relate to each other in four different ways. Each profile can be thought of in terms of the set of instances that conform to the profile:
The following guidance for designing profiles will maintain broader compatibility of resource instances across diverse profiles and minimize non-overlapping profiles of a given resource type:
Profiles
can
be
compared
to
determine
their
compatibility.
One
such
comparison
can
be
found
(no
-
todo:
bring
this
into
the
build)
between
DAF
See
Comparing
Profiles
and
QICore
.
Note
that
this
comparison
is
generated
by
tooling
under
ongoing
development,
and
is
purely
draft
content
to
demonstrate
on
the
idea
of
profile
comparison.
HL7
Confluence
page.