This
page
is
part
of
the
FHIR
Specification
(v3.0.2:
(v4.0.1:
R4
-
Mixed
Normative
and
STU
3).
)
in
it's
permanent
home
(it
will
always
be
available
at
this
URL).
The
current
version
which
supercedes
this
version
is
5.0.0
.
For
a
full
list
of
available
versions,
see
the
Directory
of
published
versions
.
Page
versions:
R5
R4B
R4
R3
R4
R3
FHIR
Infrastructure
Work
Group
|
Maturity Level : 0 (Draft) |
|
The
FHIR
Specification
includes
a
mapping
language.
The
mapping
language
has
a
concrete
syntax,
defined
and
described
in
this
page,
and
an
abstract
syntax,
which
is
found
in
the
StructureMap
resource
(and
there
is
an
antlr
grammar
for
the
concrete
syntax
).
resource.
See
also
the
Tutorial
.
The mapping language describes how one set of Directed Acyclic Graphs (an instance) is transformed to another set of directed acyclic graphs. It is not necessary for the instances to have formal declarations and/or be strongly typed - just that they have named children that themselves have properties. On the other hand, when the instances are strongly typed - specifically, when they have formal definitions that are represented as Structure Definitions , the mapping language can use additional type related features.
The mapping language addresses two very different kinds of transformations:
A map has 6 parts:
Maps are executed by a mapping engine. This takes one or more inputs of instances (directed acyclic graphs) and a map, and produces a set of outputs as specified by the map. The exact details of the form that the instances take are a matter for the map engine / application API. This language assumes that the engine can query an element in the instance for its children, its primitive value, and (optionally) its type. The language also assumes that the engine has application support for the following operations:
These functions constitute a Mapping Support API that makes maps portable between different systems
Generally, it is assumed the invocation of the engine follows some pattern like this:
Some host applications may be able to determine how to combine maps and inputs on the fly based on their metadata, and require minimal configuration, while others may require manual arrangements in order to manage the map execution process.
Mapping
files
are
always
plain
text
in
unicode.
Unicode.
Whitespace
is
any
unicode
Unicode
whitespace,
and
the
particular
whitespace
used
is
not
significant,
except
that
unicode
Unicode
end
of
line
characters
terminate
a
comment.
Comments
are
started
by
the
characters
"//".
"//"
and
can
be
found
anywhere.
The abstract model includes documentation for each item. The canonical text representation is for each item to be on its own line, with documentation at the end of the line as a comment.
All
names
defined
by
the
map
language
-
group,
rule
and
variable
names
-
must
be
valid
ids
(1-64
characters,
upper
and
lowercase
letters,
numbers,
dashes,
dots
and
underscores),
dashes
and
must
dots).
To
avoid
parsing
ambiguities
however,
they
cannot
start
with
a
letter.
The
special
boolean
values
'true'
character,
cannot
be
one
of
the
keywords
used
in
the
language
(see
section
Reserved
Keywords
below)
and
'false'
are
not
allowed
as
variable
names.
cannot
contain
a
dot
or
dash,
unless
the
names
can
be
escaped.
Escaping
can
be
done
by
surrounding
them
by
backticks
or
double
quotes.
For
example:
src document4 "not-found" "section4.5" `group`
The
first
part
of
the
mapping
syntax
establishes
the
name
of
the
mapping:
mapping.
For
example:
map "[url]" = "[name]"map "http://hl7.org/fhir/StructureMap/CodeSystem3to4" = "R3 to R4 Conversions for CodeSystem"
The
letters
"map"
"map"
are
the
first
non-whitespace
non-comment
characters
in
the
source.
This
is
followed
by
the
canonical
URL
that
identifies
the
map
uniquely,
and
then
a
human
readable
name
for
the
map.
map,
quoted
in
strings.
todo: add additional metadata? Yes, maybe in comments like javadoc or C# xmldoc?
The next optional section of the map references the set of structure definitions that are used or produced by this map. For example:
uses "[url]" (alias name) as [mode] // documentationuses "http://hl7.org/fhir/3.0/StructureDefinition/CodeSystem" alias CodeSystemR3 as source // documentation uses "http://hl7.org/fhir/StructureDefinition/CodeSystem" as target // documentation
This
optional
section
lists
one
or
more
structure
definitions
that
the
map
makes
use
of,
and
indicates
for
each
structure
definition,
how
it
is
used.
It
may
also
provide
an
Alias
alias
-
a
name
used
for
the
type
inside
the
mapping
language
-
this
may
be
necessary
when
transforming
from
source
to
target
where
both
source
and
target
use
overlapping
type
names
(not
unusual).
If
no
alias
is
given,
the
name
for
the
type
will
default
to
the
name
given
in
the
StructureDefinition
(StructureDefinition.name).
Any kind of structure definition may be referenced, including data types, resources, constraints on those, and logical models.
There are 4 modes in which a structure definition may be used:
The simplest case, which is common, is where a single structure is converted to another single structure. in this case, the map specifies one target, and one source. Such maps are easy to use automatically - the host application has content in one format, creates an empty instance of the target, and asks the mapping engine to convert.
However,
many
mappings
are
not
so
simple.
For
instance,
converting
from
a
single
CDA
document
to
FHIR
typically
creates
a
set
of
resources.
In
this
case,
there
is
a
single
target
-
a
Bundle
,
but
it
is
also
useful
to
specify
a
set
of
other
structure
definitions
for
resources
that
may
be
created
as
part
of
the
bundle.
Alternatively
Alternatively,
converting
from
one
source
model
to
another
might
involve
looking
up
other
information
in
other
instances
of
data.
It's
also
possible
for
a
map
not
so
to
specify
any
structure
definition
dependencies.
A
map
that
doesn't
indicate
any
structure
definitions
can
still
be
used,
but
the
type
features
of
the
map
language
can't
be
used,
and
such
maps
typically
require
special
development
to
integrate
the
execution
of
the
map
into
an
application.
This
next
optional
section
references
additional
maps
that
are
used
by
this
map:
map.
For
example:
imports "[url]" // documentationimports "http://hl7.org/fhir/StructureMap/*3to4" // documentation
Typically,
maps
that
are
imported
are
type
based,
such
as
Maps
can
be
broken
up
into
several
files,
each
containing
a
coherent
set
of
groups.
For
example,
when
writing
mappings
for
CDA
-->
FHIR
to
FHIR,
one
might
have
one
file
to
map
that
makes
use
of
a
the
main
document,
and
another
file
containing
the
mappings
for
the
datatypes
(e.g.
CD
-->
CodeableConcept
map.
to
CodeableConcept).
How
imported
maps
are
actually
used
is
discussed
below.
The
[url]
url
in
the
import
statement
may
contain
a
"*"
"*"
as
a
wildcard
character
(as
shown
above)
to
include
any
matching
maps
that
are
available
to
the
mapping
engine.
Each
Mapping
source
contains
one
or
more
groups
of
groups,
each
containing
one
or
more
mapping
rules.
Each
group
defines
declares
a
set
of
related
mapping
rules
that
take
the
same
input
and
output
variables,
variables
that
are
shared
by
the
rules.
The
in-
and
output
variables
define
exactly
which
instances
are
passed
to
the
mapping,
and
provides
names
by
which
they
may
be
passed
when
invoking
the
map:
For example:group (for type) [group-name] (extends [other-group]) input [name] : [type] as [mode] // documentationgroup [group-name] (inputs) (extends [other-group]) (<<stereotype>>) { // documentation .. rules .. }
group CodeSystem(source src : CodeSystemR3, target tgt : CodeSystem) extends DomainResource <<type+>>
{
// documentation
.. rules ..
}
Each group has a name, which is how the mapping is invoked. The first group is special, in that this is the group invoked if no name is provided (e.g. starting the mapping by a host application).
The
inputs
of
a
group
are
also
referred
to
(below)
as
its
input
parameters,
or
just
as
parameters;
or
as
input
variables.
variables,
and
are
a
comma
separated
list
where
each
items
has
the
format:
[mode] [name]( : [type])
Each
input
to
the
group
has
a
name.
This
is
the
name
that
applications
use
when
passing
the
instance
to
the
invocation
engine,
or
that
rules
use
when
invoking
the
group.
Inputs
may
have
a
type
-
and
should
have
(see
the
discussion
above),
but
are
not
required
to.
Input
All
input
variables
also
have
a
mode,
which
may
be
one
of
source
or
target
(see
above).
Inputs
may
have
a
type,
but
are
not
required
to.
There
must
be
at
least
two
input
variables
(source
and
target)
-
else
there's
nothing
to
map.
Maps
map,
except
for
the
special
case
of
the
first
group
that
may
only
have
a
single
input.
Groups
may
have
additional
input
or
output
inputs,
where
that's
necessary.
Groups
may
extend
other
groups,
which
means
that
the
rules
in
the
other
group
also
apply
(typically,
this
is
used
with
specialising
specializing
classes
in
an
OO
context).
When
a
group
extends
another
group,
it
SHALL
have
the
same
input
parameters
(by
mode,
name,
type
and
mode)
type
if
specified)
though
their
order
may
differ,
and
it
MAY
have
additional
parameters.
The
key
word
for
is
used
stereotypes
<<types>>
or
<<type+>>
can
be
added
to
the
end
of
the
group
declaration
to
indicate
that
this
group
provides
a
set
of
mappings
that
are
intended
to
be
used
as
the
default
way
to
map
from
source
to
target.
There
are
2
variants:
for
types
:
Use
this
by
default
when
a
[source]
of
the
specified
type
must
be
converted
to
a
[target]
of
the
specified
type,
and
no
specific
dependent
rules
(see
below)
are
specified.
for
type+types
:
in
addition,
to
the
above
use,
when
a
[source]
of
the
specified
type
must
be
converted
to
a
[target]
and
the
type
of
For
more
information,
see
the
target
is
not
fixed,
use
this
group
section
on
"Default
mapping
groups"
below.
In
both
these
cases,
the
group
Default
mapping
groups
SHALL
have
2
two
parameters,
a
source,
and
a
target,
in
that
order,
and
both
SHALL
have
specified
types
for
the
inputs.
The main portion of a map consists of a set of transform rules that describe how source content is transformed into target content. The full format for a rule looks like this:
For example:name_of_rule: for src_context.field as new_variable where condition make tgt_context.field as new_variable = create([type]) then [details].src_context.field as new_variable where condition -> tgt_context.field = create([type]) as new_variable then [details] "name";
src.value : code as vs0 -> tgt.value = create("code") as vt0 then code(vs0, vt0) "valueCode";
Each
rule
has
4
three
main
sections:
parts:
Rules
in
a
group
may
be
applied
in
any
order;
there
is
no
sense
of
sequentially
applying
one
rule
after
another.
7.6.0.7.1
Name
Each
rule
is
may
be
assigned
a
name.
name,
though
this
is
usually
inferred
by
the
parser
and
not
specified
directly.
The
name
is
used
when
specifying
rule
links,
and
in
traces
trace
logs
(a
record
generated
by
the
conversion
engine
recording
the
transform
process).
Names
must
be
unique
within
the
context
of
the
map.
Typically,
the
name
is
trivial
and
can
be
safely
and
usefully
generated
by
the
engine
processing
the
map,
so
this
is
often
left
out.
The three main parts are described in more detail in the following sections.
Each
rule
specifies
The
source
content
is
formed
by
one
or
more
elements
taken
from
the
source
that
define
variables
that
statements,
which
can
be
assigned
a
variable
name
and
then
be
used
when
specifying
target
content,
or
re-used
in
subsequent
transforms
on
the
rule.
and
dependent
rules.
Multiple
source
elements
statement
are
separated
by
a
comma,
like
this:
comma:
rule_name: for [source], [source], make ...[source], [source] -> ...
Each [source] contains the following items:
context.element { : type {min..max}} {default [value]} { list-option } as variable where [FHIRPath] check [FHIRPath]
For example:
src.value : integer 0..* default 10 first as vs0
where value >= 10 check value <= 100
log value
The
context
is
an
identifier
which
is
either
declared
elsewhere
in
as
a
source
for
the
map
('as
variable'
below,
or
in
the
input
as
a
source
variables)
parameter
or
any
named
variable
within
the
group
in
which
this
rule
is
nested.
The
element
:
An
optional
is
an
(optional)
name
of
a
child
element
of
the
context.
If
this
the
name
is
not
provided,
the
source
is
the
context.
If
this
it
is
provided,
the
rule
will
apply
once
for
each
element
on
the
context
that
matches
this
name.
If
the
element
name
contains
spaces
(possible
in
some
contexts),
it
can
be
quoted
using
"
If
all
the
there
are
multiple
source
elements
have
a
match
statements,
the
rule
applies
for
the
permutation
of
the
source
elements
(e.g.
from
each
source
statement.
E.g.
if
there
are
2
elements,
source
statements,
each
with
2
matches,
matching
elements,
the
rule
applies
4
times,
one
for
each
combination).
combination.
Typically,
if
there
is
more
than
one
source
element,
statement,
only
one
of
the
elements
can
would
repeat.
Once
the
source
statement
content
is
evaluated,
the
engine
performing
the
evaluation
has
a
list
of
variables,
elements
assigned
to
variables.
For
each
time
the
rule
is
applied,
each
of
which
the
variables
contains
a
single
value
for
each
named
variable.
value.
These
variables
are
now
mapped
into
the
target
structures
in
the
target
transformation.
Each source can include a log statement:
log [expression]
Where expression is a FHIRPath statement. e.g.
log 'not handled yet'
Puts a plain string in the log file. Alternatively, the log statement can contain FHIRPath:
log src.field
Log statements are often used to note that some particular source element is not yet mapped.
Each
rule
specifies
zero
or
more
elements
target
transformation
statements,
which
specify
how
source
content
is
used
to
be
created
in
the
create
target
structure.
content.
These
targets
target
statements
can
also
be
assigned
to
variables
that
can
be
used
in
subsequent
transform
rules.
If
no
targets
are
specified,
specified
(no
->),
no
transformation
is
done
and
there
are
not
no
created
targets,
just
newly
defined
source
variables.
variables,
which
can
then
be
used
in
subsequent
dependent
rules.
Multiple
target
elements
statements
are
separated
by
a
comma,
like
this:
... make [target], [target] then by...... -> [target], [target] then...
Each [target] contains the following items:
make context.element = transform_code(parameters...) as variable {list_modes}context.element = transform_code(parameters...) as variable {list_modes}
For example:
context.element = copy(parameter, ...) as vt1 first
The
context
is
an
identifier
which
is
either
declared
elsewhere
in
as
a
target
for
the
map
('as
variable'
below,
map,
a
taret
parameter
or
in
any
named
variable
within
the
input
target
variables)
element
:
group
(including
the
variables
from
the
source
content)
in
which
this
rule
is
nested.
The element is the name of a child element that is valid in the context. The created value will be placed into the named element
Context
and
Element
are
optional
as
Transform
statements
may
just
contain
an
invocation
of
a
pair.
If
no
context/element
is
specified,
then
transform
function.
In
this
case,
a
variable
must
be
defined,
and
the
created
value
is
only
available
in
the
variable.
variable
for
use
in
subsequent
transformations.
Each
time
the
rule
is
applied,
the
engine
determines
the
value
from
the
transforms,
considers
the
list
mode,
if
required,
required
and
creates
that
specified
content
in
the
target
instance.
Within
a
given
transform
url,
target
transform,
the
targets
target
statements
are
processed
in
order,
so
that
a
transform
rule
statement
may
refer
to
a
variable
defined
by
a
prior
transform
rule.
statement.
The following list specifies that transforms that can be specified. Each transform takes one or more parameters:
| Name | parameters | Documentation |
|
|
type | use the standard API to create a new instance of data. Where structure definitions have been provided, the type parameter must be a string which is a known type of a root element. Where they haven't, the application must know the name somehow |
| copy | source | simply copy the source to the target as is (only allowed when the types in source and target match- typically for primitive types). In the concrete syntax, this is simply represented as the source variable, e.g. src.a = tgt.b |
| truncate | source, length | source must be some stringy type that has some meaningful length property |
| escape | source, format1, format2 | Change the internal escaping of a string element. Note: this is not often needed, as mostly the escaping is done on the base format |
| cast | source, type? | cast source from one type to another. target type can be left as implicit if there is one and only one target type known |
| append | source... | source is element or string - just append them all together |
| translate | source, map_uri, output | use the translate operation . The source is some type of code or coded datatype, and the source and map_uri are passed to the translate operation. The output determines what value from the translate operation is used for the result of the operation (code, system, display, Coding, or CodeableConcept) |
| reference | source | return a string that references the provided tree properly |
| dateOp | ?? | Perform a date operation. Parameters to be documented |
| uuid | n/a | Generate a random UUID (in lowercase). No Parameters |
| pointer | resource | Return the appropriate string to put in a Reference that refers to the resource provided as a parameter |
| evaluate | resource | Execute the supplied FHIRPath expression and use the value returned by that. The 2nd parameter - FHIRPath expression - is evaluated in the context of the first parameter, and the result used as the value. In the concrete syntax, there is a short hand for this operation, by supplying () around the parameter. In this case, there is no context for the FHIRPath expression, and it must start with a reference to one of the defined variables |
| cc | (text) or (system. Code[, display]) | Create a CodeableConcept from the parameters provided |
| c | system. Code[, display] | Create a Coding from the parameters provided |
| qty | (text) or (value, unit, [system, code]) |
Create
a
quantity.
Parameters
=
(text)
or
(value,
unit,
[system,
code])
where
text
=s
the
natural
|
| id | system, value[, type] | Create an identifier. where type is a code from the identifier type value set |
| cp | (value) or (system, value) |
Create
a
contact
|
TODO: explain how optional parameters work with transforms (append only?), document list mode
Once
the
source
elements
are
evaluated,
and
any
specifed
specified
targets
created,
the
engine
has
a
set
of
variables
that
represent
source
and
target
contexts
in
which
further
mapping
may
occur.
The
set
of
variables
includes
those
provided
to
the
group
that
contains
the
rule,
and
those
created
by
the
application
of
the
rule.
For
some
created
elements
that
are
primitive
types,
that's
the
end
of
the
road
-
there's
nothing
more
to
do
with
them.
But
if
either
or
both
the
source
and
target
types
are
complex,
there
are
usually
additional
mapping
rules
that
need
to
apply
to
the
newly
created
variables.
Transform
Dependent
rules
specify
what
additional
rules
are
evaluated
when
the
rule
is
complete,
by
containing
other
rules:,
complete:
.. then {
.. other rules...
}
When
a
rule
contains
other
rules,
the
variables
from
the
containing
rules
are
all
available
to
the
contained
rules.
Alternatively,
a
rule
can
nominating
nominate
another
group
of
rules
from
the
same
or
an
imported
mapping.
Each
rule
or
group
is
listed
by
name,
and
then
a
set
of
parameters
are
provided.
.. then rule(param, param)
The
parameters
provided
must
match
the
parameters
required
by
the
dependenct
dependent
rule,
in
order.
In
addition,
the
mode
of
the
variable
must
match
-
inputs
that
are
targets
must
be
target
variables.
Note,
though,
that
target
variables
can
be
treated
as
source
for
a
group.
Groups
are
resolved
by
name
by
looking
through
all
the
groups
in
all
the
available
maps
referened
referenced
by
the
uses
(see
above)
statements.
The
name
must
be
unique
within
the
scope
of
these
maps.
If
no
dependent
rules
are
specified,
and
if
the
is
only
one
source
and
target,
and
they
both
speecify
specify
a
variable,
the
rule
can
be
written
in
an
abbreviated
form:
"name" : for src.element make tgt.elementsrc.element -> tgt.element;
This is implicitly the same as
"name" : for src.element as vvs make create([type]) tgt.element as vvt then [typeGroup](vvs, vvt)src.element as vvs -> tgt.element = create('type') as vvt then defaultMappingGroup(vvs, vvt)
Where
the
name
of
the
type
given
as
a
parameter
to
'create'
and
typeGroup
the
group
invoked
by
the
'then'
are
determined
by
the
context
of
src.element
and
tgt.element:
tgt.element
and
the
selected
default
mapping
group,
as
documented
in
the
next
section.
Note
that
default
mapping
groups
are
only
invoked
when
no
dependent
rules
or
explicit
group
invocations
are
specified.
It
is
determined
by
looking
through
the
available
rule
not
necessary
to
explicitly
invoke
groups
labeled
for
each
mapping.
Instead
groups
can
be
declared
to
be
the
"default"
mapping
for
a
given
source
and
target
type.
Groups
acting
as
"for
types"
defaults
have
either
<<types>>
or
"for
type+types"
<<type+>>
in
their
declaration.
Groups
marked
with
types
are
used
by
default
when
the
engine
encounters
a
mapping
with
a
source
and
checking
target
type
where
the
types
of
their
inputs
looking
for
a
match
to
the
source
and
target
type
of
src.element,
the
group.
Of
course,
there
can
be
only
one
such
group
for
each
combination
of
source
and
[type]
target
type
for
the
engine
to
unambiguously
determine
which
default
group
to
invoke.
In
addition
to
the
above
use,
groups
may
be
marked
with
type+
.
They
will
act
like
a
default
mapping
group,
just
like
determined
by
not
fixed,
i.e.
when
mapping
to
an
element
with
a
choice
type.
This
means
that
a
type+
group
will
be
used
as
the
default
as
long
as
the
source
type
of
tgt.element.
If
tgt.element
can
have
more
than
one
type,
then
the
instance
to
map
matches
the
source
type
is
inferred
by
looking
through
of
the
available
groups
labeled
"for
type+types"
for
a
match
group.
Even
so,
the
target
will
then
always
be
taken
to
be
the
target
type
of
src.element
the
group.
todo
The
formal
grammar
for
the
mapping
language,
specified
using
ANTLR,
can
be
found
here
.
Note
that
this
grammar
uses
FHIRPath
as
an
embedded
syntax.
Full
details
on
FHIRPath
and
its
grammar
can
be
found
here
.
todo
This is the list of reserved keywords, which cannot be used as identifiers and names for variables, unless escaped.
map uses as alias imports group extends default where check log then true false types type first not_first last not_last only_one share collate source target queried produced conceptMap prefix