This document defines the RDF representation of FHIR Resources. Later versions of this document will include RDF representations of value sets and structure definitions. A companion document describes the OWL ontology for FHIR/RDF.

Revision History

The detailed list of changes and their diffs can be found in the Git repository.

Resource Description Framework (RDF) Representation

[%wgt fhir%] Work GroupMaturity Level: 0Ballot Status: Draft

This page and the RDF forms are particularly prone to change. The page is not part of the current ballot, and so at the most it can be a draft page in DSTU 2. Comments on this and the page content are welcome.

FHIR resources can be represented as an RDF graph serialised in one of a number of RDF syntaxes. When represented in RDF, the resources are described as instances of classes that are also defined in RDF, and published with this specification. This page describes:

Note: this page uses turtle for clarify and readability, but there is no requirement or expectation that turtle should be used in preference to other syntaxes. Note that production turtle instances would not be laid out so clearly either.

Implementer Note: The FHIR 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 very different operational characteristics from the JSON and XML, and would be implemented for different reasons. Systems focused on operational exchange of data would not generally use RDF.

RDF Representation of FHIR

The FHIR RDF definitions are defined for the following purposes:

The RDF definitions are published as a series of turtle files RIM and FHIR.

RDF Class Definitions

The backbone of the RDF definitions are a formal definition of the FHIR resources as RDF classes. Each data type, resource, or element within a resource is defined as rdf:Class with a series of rdf:Property items. Each property has a rdfs:range the specifies the value domain for the property. In most cases, the conversion from the base resource definitions is straightforward.

Constraints are represented in two ways - as OWL statements, and as SHACL predicates. Implementers wishing to enforce constraints can use tools from either language, or process the knowledge represented in these constraints in any other way they see fit.

Enumerated Codes

FHIR elements that have a code data type with a Required binding to an extensional ValueSet are bound directly to the concepts defined in the code system. The RDF defines the value set, an associated code system, and an RDF class for the code system. Each code in the code system is defined as a singleton class where the class elucidates the definition and relationships of the concept, and the single instance is used to refer to the concept.

The Ontological RIM

THe RDF definitions for the resources and classes are also mapped to an ontological representation of the v3 RIM, which is also distributed as part of this specification (turtle and RDF/XML). The resources and type definitions refer to both classes and code systems defined as part of the RIM. The references to the classes defined in the RIM are generally only of interest from a RIM perspective; they do not define semantics that are necessary to understand the FHIR resources directly.

The Ontological RIM is a variant of the v3 RIM optimised for its use as an ontology supporting FHIR and other reasonsing uses. It has the following variations from the classical HL7 v3 RIM:

Other Mappings

In addition to mappings to the Ontological RIM, the RDF contains mappings to other sources of knowledge, including LOINC, SNOMED CT, OBO, etc. In these cases, the mappings reference concepts that are not defined within the RDF content provided as part of this specification, and implementers will need to locate them elsewhere.

Decimal Precision

todo.

RDF Representation of Profiles

todo.

RDF Resource Instances

A FHIR resource is represented by a series of RDF triples, starting with the fixed identifier ":resource". For readability, this page presents instances using turtle, but production instances can use any valid RDF syntax.

@prefix fhir: <http://hl7.org/fhir/> .
@prefix flag: <http://hl7.org/fhir/Flag.> .

:resource a fhir:Flag;...

The ":resource" object has a type predicate ("a") that indicates what kind of resource it is. In addition, the object will have a series of predicates for the properties defined in the RDF class definitions:

:resource a fhir:Flag;
  flag:id "example";
  flag:text [...];
  flag:category [...];
  flag:status fhir:flag-status\#active.

Enumerated fields are represented using an anonymous concept that has an rdf:type which is the concept as defined in the RDF code system definitions.

Property names are defined by class, and follow into the data types:

  flag:category [
    fhir:CodeableConcept.coding [
	  fhir:Coding.system <http://example.org/local>;
	  fhir:Coding.code "admin";
	  fhir:Coding.display "Admin";
	];
	fhir:CodeableConcept.text "admin"
  ];

The primitive types are represented using the same W3C schema based types as in the XML and JSON formats. Since the types are defined in advance, there is not usually a need to specify the type explicitly unless the RDF syntax requires this (e.g. in turtle, it would not be specified).

There are several special issues for the RDF based representation:

Missing elements

There are a number of elements in the FHIR resources and data types that have an explicit meaning or a default value when they are missing. Default values are represented explicitly in the RDF representation; they are not not omitted. For example, Patient.active has a default value of "false", and is defined like this:

fhir:Patient.active a rdf:Property;
  os:occurs os:Zero-or-one;
  rdfs:range fhir:boolean;
  fhir:default [
     a fhir:boolean;
     fhir:value [ fhir:Boolean.value "true"]
  ].

Since it has a default value, it can never be omitted from an instance:

:resource a fhir:Patient;
  fhir:Patient.active [ fhir:Boolean.value "true"],
  ...etc

Some elements do not have a default value, but they do have a meaning when there is no element present. As an example, if Patient.animal is not present, the patient is a human. In RDF (OWL particularly), reasoners cannot infer meaning from missing elements, so the element must always be present, but may have a value of http://hl7.org/fhir/nil (in RDF, fhir:nil).

Here's a patient resource with an animal property:

:resource a fhir:Patient;
  pat:animal [ ... ]

If the patient is human then the representation will be:

:resource a fhir:Patient;
  pat:animal fhir:nil;

Note: fhir:nil may be used for any property that has no value in a JSON or XML instance, but when the element has a 'meaning when missing', there SHALL be either an explicit value or else fhir:nil in the instance.

Order

FHIR elements with cardinality > 1 are inherently ordered (though the meaning of the order may not be known, or the order may have no real significance). This order must be maintained when round-tripping FHIR instances.

TODO: it is not yet resolved how this will be done.

Contained Resources

Contained resources are represented like this:

:resource a fhir:Observation;
  fhir:contained :resource\#23;
  fhir:Observation.subject [
     fhir:Reference.reference [ fhir:string.value :resource\#23]
  ].

:resource\#23 a fhir:Patient;
  fhir:Patient.name [
    fhir:text [ fhir:string.value "John Smith"]
  ].

In order to make it easy to serialise multiple resources, the id within the resource is scoped by the URL of the resource that contains it.

Extensions

In RDF, extensions are represented in two parts. The first part is a definition of the resource, and the second part is the extension value. Extensions are split like this in RDF to take advantage of RDF and to make reasoning easier.

The first part is the definition. This conveys whether the extension is a modifier, and what type it has:

@prefix ex: <http://hl7.org/fhir/StructureDefinition/> .

ex:birthplace a fhir:ExtensionDefinition;
   rdfs:range fhir:Address;
   fhir:flag fhir:isModifier.

This definition SHALL be present in any instance of an RDF graph where an extension is used. If the extension is a modifier, it SHALL be labelled as such. Additional information from the extension definition MAY be provided, but this is not required, and often is not possible (the minimum mandatory content is also represented in XML and JSON).

The value of an extension is represented as a predicate:

:resource a fhir:Patient;
  ex:birthPlace [ .. properties of address ... ];

The value of the property is the value of the extension, or a complex object with further extensions.

Concept References

The data type Coding and its container CodeableConcept represent references from a resource to a separate knowledge container. The definitions of the Coding data type are constained by operational considerations around incomplete knowledge, longitudinal version issues, use across multiple contexts, etc., so a mapping process is required to match the information that constitutes the Coding reference to the target RDF concept on which reasoning will be based.

For instance, a reference to a LOINC code in a JSON resource instance takes this form:

{
  "resourceType" : "Observation",
  "code" : {
    "coding" : {
      "system" :  [ fhir:uri.value "http://loinc.org"],
      "code" : [ fhir:code.value "54411-4"],
      "display" : [ fhir:string.value "Rh immune globulin given Qualitative"]
   	},
    "text" : "Rh immune globulin"
  }
}

As an example, in the local LOINC RDF representation, the URI for that LOINC code is http://loinc.org/owl/54411-4. (Note that for many terminologies, including LOINC, there is no standard RDF representation and multiple forms with different addressing schemes are available. Where standard representations exist, implementers SHOULD use the same addressing scheme.)

There is no algorithmic conversion between the system/code and the equivalent RDF concept; instead, a mapping table or process of some kind must be maintained. These mapping tables have variable complexity. In the worst case - codes that have the form of an expression - considerable syntactic and semantic logic is required to perform the mapping. For this reason, the reconciliation process is often performed as a preprocessing step prior to using the RDF for reasoning. Once the reconciliation process is complete, the resolved concepts are stated as rdf:type assertions on the concept:

@prefix loinc: <http://loinc.org/owl#> .

:resource a fhir:Observation;
  fhir:Observation.code [
    a loinc:54411-4;
    fhir:CodeableConcept.coding [
      fhir:Coding.system [ fhir:uri.value <http://loinc.org>] ;
      fhir:Coding.code [ fhir:code.value "54411-4" ];
      fhir:Coding.display [ fhir:string.value "Rh immune globulin given Qualitative"];
      ];
    fhir:CodeableConcept.text [ fhir:string.value "Rh immune globulin" ];
  ].

Typically, these type assertions are only used in the RDF form, but they can be carried as a normal FHIR extension in both the XML and JSON forms:

{
  "resourceType" : "Observation",
  "code" : {
    "extension" : {
      "url" : "http://hl7.org/fhir/StructureDefinition/rdftype",
      "valueUri" : "http://loinc.org/owl/54411-4"
    },
    "coding" : {
      "system" : "http://loinc.org",
      "code" : "54411-4",
      "display" : "Rh immune globulin given Qualitative"
   	},
    "text" : "Rh immune globulin"
  }
}

Implementers should note that these type assertions often reference local ontologies, and the correct URI may be scope dependent or may vary on a different lifecycle due to the coding information itself, and so it is usually not appropriate to persist these references.

These type assertions may be made against either CodeableConcept or Coding data types; when the FHIR resource property has a type of CodeableConcept they should be made at this level rather than on the Coding.

Resource References

The Reference data type represents a reference from one resource to another. The reference may be a relative URL, and resolution is subject to local rules and context (e.g. server API [base], or context in a bundle). For the same reasons as with Concept References, this can be reconciled with the actual concrete resource instance in the RDF. As an example, a reference to a resource would be represented like this in JSON:

{
  "resourceType" : "Observation",
  "subject" : {
    "reference" : "Patient/example"
  }
}

In RDF, this is represented as an anonymous instance of the data type reference:

:resource a fhir:Observation;
  fhir:Observation.subject [
    fhir:Reference.reference [ fhir:string.value "Patient/example" ];
  	a pat:example
  ].

If this has been resolved to a specific instance, then the subject is directly assigned to the instance:

:resource a fhir:Observation;
  fhir:Observation.subject :patient-example.
  
:patient-example fhir:Reference.reference [ fhir:string.value "Patient/example" ];

The details of the reference are added to the target resource. TODO: this means that traceability of the reference is lost, and it's not round-trippable if the reconciliation includes resources that have more than one literal value to reference in the target resource

@prefix pat: <http://acme.com/services/fhir/Patient/#> 

:resource a fhir:Observation;
  fhir:Observation.subject [
    fhir:Reference.reference [ fhir:string.value "Patient/example" ];
  	a pat:example
  ].

Other Stuff

Todo: implement a template for RDF? (turtle? RDF XML - yuck) Todo: note that there's no canonical form for RDF, nor any defined support for signatures.

Using RDF with the REST API

When using RDF on the REST API, the following media types apply:

Implementations are encouraged to support this list. However servers are not required to support all these, and may support additional syntaxes.

Default Mapping

FHIR Logical Models define the content model of FHIR Resources. Most of FHIR/RDF is defined by interpreting Logical Models as constraints on RDF graphs. Logical Models include a sequence of attribute definitions or choice between attributes. Attribute definitions include a name name and a set of permissible values, which are defined by one of:

NameType
✉ Observation DomainResource
├⧆ identifier Identifier*
├▭ status code1
├⧆ code CodeableConcept1
├☞ subject Reference(Patient | Group | Device | Location)?
├? effective[x] ?
│├▭ effectiveDateTime dateTime
│└⧆ effectivePeriod Period
Turtle Template

[ a fhir:Observation; fhir:nodeRole fhir:treeRoot;
  # from Resource: id; meta; implicitRules; and language
  # from DomainResource: text; contained; extension; and modifierExtension
  fhir:Obervation.identifier [ Identifier ]; # 0..* Unique Id for this particular observation
  fhir:Obervation.status [ fhir:value "<code>" ]; # R!  registered | preliminary | final | amended +
  fhir:Obervation.code [ CodeableConcept ]; # 1..1 R!  Type of observation (code / type)
  fhir:Obervation.subject [ fhir:reference [ Patient|Group|Device|Location ] ]; # 0..1 Who and/or what this is about
  fhir:Obervation.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 2:
    fhir:Obervation.effectiveDateTime [ fhir:value "<dateTime>" ];
    fhir:Obervation.effectivePeriod [ Period ];
]

Resource Root

Each FHIR Resource is represented by an RDF node called the resource root. A function add(subject, predicate object) defines triples to compose an RDF graph. A current node identifies the current subject corresponding to attributes in the hierarchy of the Structure Definition. The current node is initially the resource root. For a FHIR Resource of type R, we begin by adding a type triple and a root flag to the current node.

Is the resource root ever a named node? If so, is it the HTTP name of the entity?

Property Label

Each attribute in the structure definition identifies an RDF predicate composed of the property name.

Nested Elements

An XML tag is unique within the namespace that it is declared in. FHIR does not use global declarations. The XML tag is mapped to an Object Property where the name is prefixed with the Class name in which it was declared. A tag “bar” declared in a complex type “Foo” would become an Object Property “Foo.bar”. This is aligned with the structural definition mechanism in FHIR.

Datatypes

In RDF the value attribute of a datatype is a Data Property named “value” with undefined range. Each FHIR data type has a restriction on the range of the Data Property (see section on Datatypes).

stuff to move elsewhere

Turtle Template

[ a fhir:Observation; fhir:nodeRole fhir:treeRoot;
  # from Resource: id; meta; implicitRules; and language
  # from DomainResource: text; contained; extension; and modifierExtension
  fhir:Obervation.identifier [ Identifier ]; # 0..* Unique Id for this particular observation
  fhir:Obervation.status [ fhir:value "<code>" ]; # R!  registered | preliminary | final | amended +
  fhir:Obervation.category [ CodeableConcept ]; # 0..1 Classification of  type of observation
  fhir:Obervation.code [ CodeableConcept ]; # 1..1 R!  Type of observation (code / type)
  fhir:Obervation.subject [ fhir:reference [ Patient|Group|Device|Location ] ]; # 0..1 Who and/or what this is about
  fhir:Obervation.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 2:
    fhir:Obervation.effectiveDateTime [ fhir:value "<dateTime>" ];
    fhir:Obervation.effectivePeriod [ Period ];
  fhir:Obervation.issued [ fhir:value "<instant>" ]; # 0..1 Date/Time this was made available
  fhir:Obervation.performer [ fhir:reference [ Practitioner|Organization|Patient|RelatedPerson ] ]; # 0..* Reference Who is responsible for the observation
  # value[x]: 0..1 Actual result. One of these 10:
    fhir:Obervation.valueQuantity [ Quantity ];
    fhir:Obervation.valueCodeableConcept [ CodeableConcept ];
    fhir:Obervation.valueString [ fhir:value "<string>" ];
    fhir:Obervation.valueRange [ Range ];
    fhir:Obervation.valueRatio [ Ratio ];
    fhir:Obervation.valueSampledData [ SampledData ];
    fhir:Obervation.valueAttachment [ Attachment ];
    fhir:Obervation.valueTime [ fhir:value "<time>" ];
    fhir:Obervation.valueDateTime [ fhir:value "<dateTime>" ];
    fhir:Obervation.valuePeriod [ Period ];
  fhir:Obervation.dataAbsentReason [ CodeableConcept ]; # 0..1 C? Why the result is missing
  fhir:Obervation.interpretation [ CodeableConcept ]; # 0..1 High; low; normal; etc.
  fhir:Obervation.comment [ fhir:value "<string>" ]; # 0..1 Comments about result
  fhir:Obervation.bodySite [ CodeableConcept ]; # 0..1 Observed body part
  fhir:Obervation.method [ CodeableConcept ]; # 0..1 How it was done
  fhir:Obervation.specimen [ fhir:reference [ Specimen ] ]; # 0..1 Specimen used for this observation
  fhir:Obervation.device [ fhir:reference [ Device|DeviceMetric ] ]; # 0..1 (Measurement) Device
  fhir:Obervation.referenceRange [ # 0..* Provides Provides guide for interpretation
    fhir:Obervation.referenceRange.low  [ fhir:reference [ SimpleQuantity ] ]; # 0..1 C? Low Range; if relevant
    fhir:Obervation.referenceRange.high [ fhir:reference [ SimpleQuantity ] ]; # 0..1 C? High Range; if relevant
    fhir:Obervation.referenceRange.meaning [ CodeableConcept ]; # 0..1 Indicates the meaning/use of this range of this range
    fhir:Obervation.referenceRange.age [ Range ]; # 0..1 Applicable age range; if relevant
    fhir:Obervation.referenceRange.text [ fhir:value "<string>" ] # 0..1 Text based reference range in an observation
  ];
  fhir:Obervation.related [ # 0..* Resource Resource related to this observation
    fhir:Obervation.related.type [ fhir:value "<code>" ]; # 0..1 has-member | derived-from | sequel-to | replaces | qualified-by | interfered-by
    fhir:Obervation.related.target [ fhir:reference [ Observation|QuestionnaireResponse ] ] # 1..1 R!  Resource that is related to this one
  ];
  fhir:Obervation.component [ # 0..* Component Component results
    fhir:Obervation.component.code [ CodeableConcept ]; # 1..1 C? R!  Type of component observation (code / type)
    # value[x]: 0..1 Actual component result. One of these 10:
    fhir:Obervation.related.valueQuantity [ Quantity ];
    fhir:Obervation.related.valueCodeableConcept [ CodeableConcept ];
    fhir:Obervation.related.valueString [ fhir:value "<string>" ];
    fhir:Obervation.related.valueRange [ Range ];
    fhir:Obervation.related.valueRatio [ Ratio ];
    fhir:Obervation.related.valueSampledData [ SampledData ];
    fhir:Obervation.related.valueAttachment [ Attachment ];
    fhir:Obervation.related.valueTime [ fhir:value "<time>" ];
    fhir:Obervation.related.valueDateTime [ fhir:value "<dateTime>" ];
    fhir:Obervation.related.valuePeriod [ Period ];
    fhir:Obervation.related.dataAbsentReason [ CodeableConcept ]; # C? Why the component result is missing
    fhir:Obervation.related.referenceRange [ Content as for Observation.referenceRange ] # 0..* Content Provides guide for interpretation of component result
  ]
]