[%settitle RDF Representation%]
[%file newheader%] [%file newnavbar%] <%fmtheader rdf%>[%wgt its%] Work Group | Maturity Level: 3 | Standards Status:Trial Use |
This page and the RDF forms are jointly maintained by the HL7 FHIR project -- especially the RDF subgroup of the ITS work group -- and the W3C Semantic Web Health Care and Life Sciences Interest Group. |
FHIR resources can be represented as an RDF graph serialized in the Turtle format. The RDF format is
defined to assist the process of bridging between operational
data exchange and formal knowledge processing systems. While the
RDF form offers a fully functional representation of FHIR
resources, it has different operational characteristics from the
JSON and XML
representations, and would be used for different reasons.
Systems focused on operational exchange of data would not
generallyusually choose to use RDF.
This page describes:
Each resource page has a set of language templates describing the FHIR expression in that language. The Turtle representation for a resource is described using this format:
[ a fhir:Observation; fhir:nodeRole fhir:treeRoot; # if this is the parser root # from Resource: id; meta; implicitRules; and language # from DomainResource: text; contained; extension; and modifierExtension fhir:Observation.identifierfhir:identifier [ Identifier ]; # 0..* Unique Id for this particular observation fhir:Observation.statusfhir:status [ fhir:v "<code>" ]; # R! registered | preliminary | final | amended + fhir:Observation.codefhir:code [ CodeableConcept ]; # 1..1 R! Type of observation (code / type) fhir:Observation.subjectfhir:subject [ fhir:reference [ Patient|Group|Device|Location ... ] ]; # 0..1 Who and/or what this is about fhir:Observation.encounterfhir:encounter [ fhir:reference [ Encounter ] ]; # 0..1 Healthcare event during which this observation is made # effective[x]: 0..1 Clinically relevant time/time-period for observation. One of these 4: fhir:Observation.effectiveDateTimefhir:effectiveDateTime [ fhir:v "<dateTime>" ]; fhir:Observation.effectivePeriodfhir:effectivePeriod [ Period ]; fhir:Observation.effectiveTimingfhir:effectiveTiming [ Timing ]; fhir:Observation.effectiveInstantfhir:effectiveInstant [ fhir:v "<instant>" ]; ]
Using this format:
An example FHIR RDF Observation illustrates the Turtle language and the additional conventions used by FHIR RDF:
PREFIX fhir: <http://hl7.org/fhir/> PREFIX xs:xsd: <http://www.w3.org/2001/XMLSchema#> PREFIX owl: <http://www.w3.org/2002/07/owl#> # Obs123 (subject) hasType (predicate) fhir:Observation <http://hl7example.org/fhir/Observation/Obs123> a fhir:Observation; fhir:nodeRole fhir:treeRoot; # (subject) is the serialization root of this document fhir:statusfhir:id [ fhir:v "final""Obs123" ]; # (subject) has an id of "Obs123" fhir:status [ fhir:v "final" ]; # (subject) has an (extensible) status of "final" fhir:code [ # (subject) as a code fhir:coding ( # which has codings [ # with a concept IRI, system, and code and concept identifier a <http://loinc.org/rdf#29463-7> ; fhir:system [ fhir:v "http://loinc.org"^^xs:anyURIorg"^^xsd:anyURI ]; fhir:code [ fhir:v "29463-7" ] ] [ # and another with a display text a <http://loinc.org/rdf#3141-9> ; fhir:system [ fhir:v "http://loinc.org"^^xs:anyURIorg"^^xsd:anyURI ]; fhir:code [ fhir:v "3141-9" ]; fhir:display [ fhir:v "Body weight Measured" ] ] ) ]; fhir:value [ # the value is an anonymous node a fhir:Quantity; # which has a type (Quantity), and 21090 parts. fhir:value [ fhir:v "185"^^xs:decimal"185"^^xsd:decimal ]; fhir:unit [ fhir:v "lbs" ]; fhir:system [ fhir:v "http://unitsofmeasure.org"^^xs:anyURIorg"^^xsd:anyURI ]; fhir:code [ fhir:v "[lb_av]" ] ]. # Metadata aboutto help OWL interpretation <http://hl7example.org/fhir/Observation/Obs123.ttl> a owl:Ontology; owl:imports fhir:fhir.ttl; owl:versionIRI <http://hl7example.org/fhir/Observation/Obs123.ttl>.
In this example,
< ... >
'.fhir:Observation
) and
following predicates (e.g. fhir:status
)
are prefixed names (like XML namespaced names),[ ... ]
's,"final"
).text/turtle
, the
use of Turtle for FHIR RDF uses the specialized media type application/fhir+turtle
. FHIR uses Shape
Expressions (ShEx) to define and validate FHIR RDF. See
fhir.shex
for the complete FHIR RDF schema. Each Resource page includes
a link for the subset of fhir.shex needed to describe that
Resource. The media type for ShEx is text/shex.
Each resource is represented as a set of RDF triples. When
a resource has a persistent identity (e.g. it can be found
at a particular URL -- usually a FHIR RESTful server), then
that URL is its identity. Resources with no persistent
identity (e.g. bundles from search results) have the
identity of the root document -- "<>" in Turtle syntax.
In the above example, the resource is the subject: <http://hl7example.org/fhir/Observation/Obs123>
.
Some resources can contain other resources. Given that the
relationships can appear in any order in RDF, it cannot be
assumed that the first encountered element represents the
resource of interest that is being represented by the set of
Turtle statements. The focal resource -- where to start when
parsing -- is the resource with the relationship fhir:nodeRole
to fhir:treeRoot
. If there is more than one
node labeled as a 'treeRoot' in a set of Turtle statements,
it cannot be determined how to parse them as a single
resource.
While RDF predicate names are case-sensitive, FHIR avoids
confusion by assuring that there are no predicates that
differ only in case. For example, there will be no fhir:Code predicate because there is
already a fhir:code predicate.
Content within a resource is always represented with anonymous nodes (a/k/a "blank nodes"). Only FHIR Resource nodes can be IRIs. For example, this Turtle:
< http://example... org/fhir/Observation/Obs123> fhir:status [ fhir:v "final" ]asserts that:
A great deal of effort has gone into unifying FHIR property names across resources and datatypes. These defined properties effectively declare the FHIR RDF namespace with a set of polymorphic, reuseable predicates. For example, fhir:status is spelled the same way regardless of whether it appears in an Observation, Diagnosis, or any other FHIR Resource.
In other formats (XML, JSON), FHIR properties with choice
datatypes, like value[x], are
appended with the datatype, e.g. valueQuantity.
In RDF, this is written fhir:value
and the object asserts its type explicitly, as in the above
example:
fhir:value [ a fhir:Quantity; ... ]
Elements that can repeat are represented with RDF lists
(officially called "RDF collections") in order to retain the
order of their elements.
( elt1 elt2 ... )
which produces an RDF list structure the the elements elt1
and elt2. In the above
example of a FHIR Observation, the fhir:code
has a fhir:coding
with two members:members in an RDF list:
fhir:coding ( [ a <http://loinc.org/rdf#29463-7> ... ] [ a <http://loinc.org/rdf#3141-9> ... ] )
A Since RDF lists can cause problems for OWL users, a script can convert RDF lists to OLO-style lists, which may be helpful for OWL usersan alternate representation. See Using FHIR RDF with OWL for more info.
Primitive elements -- elements with a primitive type -- are represented as anonymous nodes, both so that the element extensions can be attached and so that they can consistently be treated as OWL object properties (versus sometimes being datatype properties). The actual value of the primitive type is represented as an RDF Literal using the fhir:v predicate. fhir:v is the only FHIR property that directly holds an RDF literal -- i.e., it is the only OWL datatype property in FHIR RDF -- and it always holds an RDF Literal:
fhir:v "[value]"^^xs:type"[value]"^^xsd:type
The value has two parts: a literal string that contains
the value, and, if applicable, one of the following schema
types:
In the Observation example above example, the
Quantity has a fhir:value whichthat is an anonymous node with a
fhir:v
in it:
[ fhir:v "185"^^xs:decimal"185"^^xsd:decimal ]
Note that the correct XSD type for a FHIR decimal,
date,
or dateTime
must be determined by inspecting the value of the date for
conformance with one of the union types for that type. In
the case of FHIR decimal,
which is a union of XSD decimal
and double,
any value with an 'e' or 'E' in it is a double, otherwise it
is a decimal. For example, the lexical value "185" is given the datatype xs:decimalxsd:decimal
.
The fhir:v property can never be empty. Either the
relationship is absent, or it is present with at least one
character of content. XHTML is represented as an escaped
xs:stringxsd:string.
A Reference element is represented using the same rules as above:
fhir:Observation.subjectReferencefhir:subjectReference [ fhir:Reference.referencefhir:reference [ fhir:v "Patient/example" ]; fhir:Reference.displayfhir:display [ fhir:v "Example Patient" ]; ];
This allows faithful round tripping of the resource between the Turtle format and the JSON and XML formats. However, it's very useful for an RDF processor if the RDF graph links to the target of the reference directly. This can be represented using the (optional) fhir:link property:
fhir:Observation.subjectReferencefhir:subjectReference [ fhir:link <http://hl7example.org/fhir/Patient/example> ; fhir:Reference.referencefhir:reference [ fhir:v "Patient/example" ]; fhir:Reference.displayfhir:display [ fhir:v "Example Patient" ]; ];
The correct value for the fhir:link relationship must be determined by resolving the rules for resolving references for the various reference types to a literal URL that refers to the correct content in the local RDF context.
The fhir:link relationship can be added automatically as part of generating the resource representation, or it can be injected by a post-processor that knows how to convert the raw references into RDF-suitable references.
Inline resources -- when a resource is contained directly in another element -- occur in the following places:
Inline resources are represented as anonymous nodes. This is an example for a contained Medication resource:
fhir:DomainResource.containedfhir:contained ([ a fhir:Medication; # triples for the Medication ])
Note that DomainResource.contained has a cardinality of 0..*, so an RDF List is used to order the array.
The same logic applies to the Coding data type. These are represented directly in Turtle by serializing their properties as specified above:
fhir:Observation.codefhir:code [ fhir:CodeableConcept.codingfhir:coding ( [ fhir:Coding.systemfhir:system [ fhir:v "http://loinc.org" ]; fhir:Coding.codefhir:code [ fhir:v "29463-7" ]; fhir:Coding.displayfhir:display [ fhir:v "Body Weight" ] ] [ fhir:Coding.systemfhir:system [ fhir:v "http://snomed.info/sct" ]; fhir:Coding.codefhir:code [ fhir:v "27113001" ]; fhir:Coding.displayfhir:display [ fhir:v "Body weight" ] ] ) ];
For reasoners using the RDF graph, it's very useful to
make the implicit concept references in these Codings
explicit, by specifying a concept IRI in an
(optional) rdf:type assertion, written as a
in
Turtle:
fhir:Observation.codefhir:code [ fhir:CodeableConcept.codingfhir:coding ( [ a loinc:29463-7; fhir:Coding.systemfhir:system [ fhir:v "http://loinc.org" ]; fhir:Coding.codefhir:code [ fhir:v "29463-7" ]; fhir:Coding.displayfhir:display [ fhir:v "Body Weight" ] ] [ a sct:27113001; fhir:Coding.systemfhir:system [ fhir:v "http://snomed.info/sct" ]; fhir:Coding.codefhir:code [ fhir:v "27113001" ]; fhir:Coding.displayfhir:display [ fhir:v "Body weight" ] ] ) ];
A concept IRI typically has two parts: an IRI stem and a
code. An IRI stem is the initial substring, of
an IRI, that is used to createuniquely identifies a concept IRIs for codes in a
particular vocabulary. The IRI stem normally
corresponds directly to an IRI prefix in Turtle, such as loinc:
or sct: in the above example. The
concept IRI for a giventhat would otherwise
be identified by a <Coding.system, Coding.code
> pair. A concept
IRI has two parts: an IRI stem and a code.
An IRI stem is the initial substring of the concept IRIs
that correspond to the codes in a particular vocabulary.
The concept IRI is formed by concatenating the IRI stem with
the code (after percent-encoding any reserved characters
-- see Appendix 1: Algorithm for Creating a Concept IRI
for details). The IRI stem is typically formed by: 1used to define an
IRI prefix in Turtle and SPARQL, such as loinc:
or sct:
in
the above example. looking up the appropriate
This approach allows the Compact URI
loinc:29463-7
(in Turtle or SPARQL) to be translated into the
concept IRI http://loinc.org/rdf/29463-7
by concatenating
the IRI stem corresponding tohttp://loinc.org/rdf/
with the code
29463-7
. This particular IRI stem is defined in the
LOINC User Guide S12.7.2.
One might wonder why the Coding.system
;
2 is not used directly
as the IRI stem for a given vocabulary. concatenating the IRI stem with the percent encoded One reason is that
Coding.codesystem
s often lack a convenient separator
character as their final character, such as "/" or "#", which
could cause problems if they were directly concatenated with codes,
leading to erroneous concept IRIs such as http://loinc. Some vocabularies may also defineorg35217-9
.
But the main reason is that the Coding.codesystem
s
that are already concept IRIs and the IRI stem of some vocabularies
were chosen independently and differ in unpredictable ways.
Hence, bypassing the need for the
there is no simple formula for determining the correct
IRI stem. For details see Appendix: Algorithm for
creating a Concept IRI.
If an IRI stem for the from a Coding.system
.
To address this problem, and to facilitate ease of use,
HL7 maintains a mapping from Coding.system
s
to IRI stems: IRI stems can be registered and looked
up in the HL7 terminology website, based on the desired
Coding.system
.
If an IRI stem for a Coding.system
is published at
https://terminology.hl7.org/ it SHOULD be used. An
An NPM
package is also available to efficiently automate lookup of
IRI stems from Coding.systemssystem
s.
To add an IRI stem to that site,
see Appendix 2: Registering an IRI Stem on the HL7 Terminology Website.
A Resource may have any number of non-modifier extensions:extensions, represented as an RDF list like this:
<http://hl7example.org/fhir/MedicationRequest/MR321> a fhir:Observation; fhir:nodeRole fhir:treeRoot; fhir:extension ( ( [ fhir:url [ fhir:v "http://hl7example.org/fhir/StructureDefinition/observation-bodyPosition"^^xs:anyURIbodyPosition"^^xsd:anyURI ] ; fhir:value [ fhir:coding ( a sct:33586001; fhir:system [ fhir:v "http://snomed.info/sct" ]; fhir:code [ fhir:v "33586001" ]; fhir:display [ fhir:v "Sitting position (finding)" ] ) ] ] [ fhir:url [ fhir:v "http://hl7example.org/fhir/StructureDefinition/observation-delta"^^xs:anyURIdelta"^^xsd:anyURI ] ; fhir:value [ fhir:coding ( a sct:1250004; fhir:system [ fhir:v "http://snomed.info/sct" ]; fhir:code [ fhir:v "1250004" ]; fhir:display [ fhir:v "Decreased (qualifier value)" ] ) ] ] ) ...
FHIR allows modifierExtension
s
on DomainResources,
BackboneElements
and BackboneTypes.
The type of any DomainResource with any modifierExtension
is prefixed with '_' in RDF.
The '_' prefix helps prevent FHIR RDF
processors that do not understand a particular modifier
extension from blindly processing it as though it still had
the original semantics. The structure of the
element is otherwise unchanged:unchanged. Note the underscore at the
beginning of "_MedicationRequest" in the following example:
<http://hl7example.org/fhir/MedicationRequest/MR321> a fhir:_MedicationRequest; fhir:nodeRole fhir:treeRoot; fhir:extension ( ... ); # above bodyPosition and delta extensions fhir:modifierExtension ( [ fhir:url [ fhir:v "http://example.org/fhir/StructureDefinition/anti-prescription"^^xs:anyURIprescription"^^xsd:anyURI ] ; fhir:value [ a fhir:boolean ; fhir:v true ] ] ) ...
BackboneElements and BackboneTypes are object types. Any RDF predicate that references a modified BackboneElement or BackboneType is prefixed with a '_'. Note the underscore at the beginning of "_value" in the following example:
<http://hl7example.org/fhir/Observation/Obs123> a fhir:Observation; ... fhir:_value [ a fhir:Quantity; fhir:value [ fhir:v "185"^^xs:decimal"185"^^xsd:decimal ]; fhir:unit [ fhir:v "lbs" ]; fhir:system [ fhir:v "http://unitsofmeasure.org"^^xs:anyURIorg"^^xsd:anyURI ]; fhir:code [ fhir:v "[lb_av]" ]; fhir:modifierExtension ( [ fhir:url [ fhir:v "http://example.org/fhir/StructureDefinition/anti-observation"^^xs:anyURIobservation"^^xsd:anyURI ] ; fhir:value [ a fhir:boolean ; fhir:v true ] ] ) ; ]
In addition to the basic representation of FHIR resources in Turtle format, a Turtle representation of the FHIR infrastructure and definitions is also published, for the following purposes:
The RDF definitions are published as a series of Turtle
files: HL7 v3 RIM (Reference
Information Model) and FHIR. ShEx
schemas that describe FHIR's RDF format are also available.
This page documents an RDF format that can be used to exchange FHIR data, on the basis that RDF is a universal information representation. Using RDF enables FHIR data to be used with other RDF data and RDF-aware applications to support inference, shared semantics across multiple standards and data formats, data integration, semantic data validation, compliance enforcement, SPARQL queries and other uses. Implementers using FHIR in this fashion should be aware of the relationship between FHIR's RDF format and other uses of ontologies.
FHIR's RDF format is based on the same abstract information
model as the XML and JSON formats and carries the same
information content. Resources are losslessly round-trippable
between XML, JSON and RDF formats and data expressed in the
RDF format corresponds closely to the XML and JSON formats in
its look and feel. However, there arethough a few additional FHIR-specific terms
that may appear in the RDF format, which areas explained on this
page above:
fhir:nodeRole
, fhir:treeRoot
, and
fhir:v
and fhir:concept.
In addition to defining the RDF format, this specification provides provides an associated ontology that providescontaining formal definitions for the relationshipsof the classes and properties that appear in the RDF format. Ontologies that were designed independently almost always have some impedance mismatch when attempting to use them together. Many of the ontologies in the medical and life sciences domain are designed to capture facts about the world for research, such as the fact that the mitral valve is a kind of heart valve. But FHIR was designed to support the day-to-day operations of healthcare providers exchanging electronic health records (EHRs), and in this context, the orientation has historically been different. When using FHIR RDF with other ontologies, impedance differences are likely to show up in two main ways:
For both of these reasons, to maintain monotonicity in RDF, FHIR RDF should not be directly interpreted as stating facts; transformations. Transformations are required to remove or isolate non-monotonic elements and reconcile the records across time and perspective.
Application developers should also be aware that some FHIR
data attributes have a major impact on the interpretation of
the enclosing data element: the meaning of the enclosing
element cannot be determined in isolation. For example, a
status of 'entered-in-error' means that the resource was
created accidentally and should be ignored for most purposes.
Application developers wishing to use FHIR RDF will often need to perform the following rough steps, though exact steps will depend on your application:
RDF lists use a ladder of rdf:first and rdf:rest properties. This can cause problems in OWL DL, which disallows axioms over the rdf: namespace. To work around this problem, OWL users can convert RDF lists in their FHIR data to use OLO-style listsa different list representation. A script is available for doing thesuch a conversion.
Slides
by Eric Prud'hommeaux illustrate how
inference can be used on FHIR RDF data to perform a query for
FHIR Observations of rheumatoid arthritis, using the SNOMED-CT
ontology.
Caveat: These slides were based on an earlier
version of FHIR, so some specifics may have changed.
A webinar
by Harold Solbrig shows how FHIR RDF data can be used with
the SNOMED-CT
ontology to recognize a cancer diagnosis. An associated
tutorial details the steps used. Caveat: thisThis
webinar and tutorial usedwere based on a previous version of FHIR RDF,
so some specifics may have changed.
This section defines a standard algorithm for generating a
Concept IRI from a <Coding.system
, Coding.code
>
pair. In many cases it involves merely concatenating the
associated IRI Stem with the Coding.code
.
But because a Coding.code
could contain reserved
characters that are used to delineate different parts of the
IRI, percent-encoding of reserved characters is required, as
defined below.
Given:
Coding.system
, s, that
identifies a terminology t; and Coding.code
, c, that is defined
within t;a Concept IRI, conceptIRI, corresponding to s
and c is computed as follows:
urn:ietf:rfc:3987
, then conceptIRI is c,
and c MUST be a syntactically valid absolute-IRI as
defined by RFC
3987. Halt. (Informative comments: The
purpose of this special case is to permit System.code
s
that are already IRIs to be used directly as Concept IRIs,
without any transformation. Note that an absolute-IRI may
also be a URL or a URN.)The IRI-safe version of a string is obtained by applying the following transformation to any character that is not in the iunreserved production in [RFC3987]:The iunreserved production defined in RFC 3987, section 2.2 using ABNF is also quoted here for convenience (informative):
1. Convert the character to a sequence of one or more octets using UTF-8 [RFC3629]
2. Percent-encode each octet [RFC3986]
The ucschar production defined in RFC 3987, section 2.2 is also quoted here for convenience (informative). (Informative comment: The ucschar production defines international character ranges that are valid unicode characters within the intersection of path components (ipath), query strings (iquery) and fragment identifiers (ifragment). They do not include any reserved characters involved in parsing apart the various components of an IRI.)iunreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" / ucschar
ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
/ %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
/ %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
/ %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
/ %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
/ %xD0000-DFFFD / %xE1000-EFFFD
|
|
IRI Stem |
Concept IRI |
ICD 10: |
|
|
|
SNOMED CT:* |
|
|
|
MeSH: |
|
|
|
LOINC: |
|
|
|
Example coding system that uses a Unicode smiling
face character (U+263A) as a code: |
|
|
|
Example coding system that uses a Unicode waving hand
character (U+1F44B) from the Miscellaneous
Symbols and Pictographs block,
combined with the medium-dark skin tone (U+1F3FE): |
|
|
|
*As of this writing (5-Sep-2022) it is not clear what IRI stem should be used when writing a SNOMED CT post-coordinated code expression.
IRI stems have not been standardized for all FHIR
Coding.system
s. But any that have been
standardized should be registered in the HL7 terminology
website by adding appropriate CodeSystem and NamingSystem
entries, using the system "urn:ietf:rfc:3987" and
identifier type
of "iri-stem". You can see an
example of this in the HL7 description of the
LOINC CodeSystem
and the
LOINC NamingSystem.
Assuming that the Coding.system
for your desired IRI stem has already been registered, the
process for registering an IRI stem for it includes:
doi:10.1111/
urn:loinc.org:
← Note the trailing colon (":")http://loinc.org/rdf/
http://purl.obolibrary.org/obo/HP_
← Note the trailing underscore ("_")https://example.org/terminologies/?action=search&id=
ftp://user@example.org:2222/loinc/
gen-delims
or sub-delims
productions from
section 2.2 of RFC 3987
or one of the characters "-", ".", "_"
or "~") . An IRI stem that ends with an alphanumeric
character is likely to have the meaning of the final term
altered when the code is concatenated. For example, an IRI
stem of "http://example.org" when concatenated with the code
"39" will result in a concept IRI of "http://example.org39",
which is probably not the concept IRI intended.
On the HL7 Terminology website (https://terminology.hl7.org), add the IRI stem to the NamingSystem and CodeSystem records corresponding to the desired Coding.system, by following the process for submitting a UTG change proposal. The IRI stem SHOULD be added to both the NamingSystem and the CodeSystem. Additions, deletions and modifications of an IRI stem to an existing NamingSystem or CodeSystem will generally be considered a minor change under the UTG Versioning policy.
As of this writing (17-Dec-2022), the change proposal process for doing this included the following steps. However, since the process may have later changed, you should verify it prior to proceeding. You can also see an example of such a change proposal, including the associated changes in the XML files, in the MeSH IRI stem change proposal.