Release 5 Ballot

This page is part of the FHIR Specification (v5.0.0-ballot: FHIR R5 Ballot Preview). 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

FHIR Infrastructure Work GroupMaturity Level: NormativeStandards Status: Normative

The FHIR Specification uses FHIRPath (release 2) for path-based navigation and extraction. FHIRPath is a separate specification published at http://hl7.org/fhirpath in order to support wider re-use across multiple specifications.

FHIRPath is used in several places in the FHIR and related specifications:

In addition, FHIRPath is used in pre-fetch templates in Smart on FHIR's CDS-Hooks .

In FHIRPath, like XPath, operations are expressed in terms of the logical content of hierarchical data models, and support traversal, selection and filtering of data.

FHIRPath uses a tree model that abstracts away the actual underlying data model of the data being queried. For FHIR, this means that the contents of the resources and data types as described in the Logical views (or the UML diagrams) are used as the model, rather than the JSON and XML formats, so specific xml or json features are not visible to the FHIRPath language (such as comments and the split representation of primitives).

More specifically:

  • A FHIRPath may optionally start with a full resource name
  • Elements of datatypes and resources are used as the name of the nodes which can be navigated over, except for choice elements (ending with '[x]'), see below.
  • The contained element node does not have the name of the Resource as its first and only child (instead it directly contains the contained resource’s children)
  • There is no difference between an attribute and an element
  • Repeating elements turn into multiple nodes with the same name

For choice elements, where elements can be one of multiple types, e.g. Patient.deceased[x]. In actual instances these will be present as either Patient.deceasedBoolean or Patient.deceasedDateTime. In FHIRPath, choice elements are labeled according to the name without the '[x]' suffix, and children can be explicitly treated as a specific type using the as operation:

(Observation.value as Quantity).unit

FHIRPath statements can start with a full resource name:

Patient.name.given

The name can also include super types such as DomainResource:

DomainResource.contained(id = 23).exists()

These statements apply to any resource that specializes DomainResource.

The namespace for the types defined in FHIR (primitive datatypes, datatypes, resources) is FHIR. So, for example:

Patient.is(FHIR.Patient)

The first element - the type name - is not namespaced, but the parameter to the is() operation is.

Understanding the primitive types is critical: FHIR.string is a different type to System.String. The FHIR.string type specializes FHIR.Element, and has the properties id, extension, and also the implicit value property that is actually of type of System.String.

The evaluation engine will automatically convert the value of FHIR types representing primitives to FHIRPath types when they are used in expressions according to the following mapping:

FHIR primitive type FHIRPath type
FHIR.boolean System.Boolean
FHIR.string, FHIR.uri, FHIR.code, FHIR.oid, FHIR.id, FHIR.uuid, FHIR.sid, FHIR.markdown, FHIR.base64Binary System.String
FHIR.integer, FHIR.unsignedInt, FHIR.positiveInt System.Integer
FHIR.integer64 System.Long
FHIR.decimal System.Decimal
FHIR.date, FHIR.dateTime, FHIR.instant System.DateTime
FHIR.time System.Time
FHIR.Quantity System.Quantity (see below)

Since FHIR primitives may contain extensions, the following expressions are not mutually exclusive:

Patient.name.given = 'Ewout'         // value of Patient.name.given as a string
Patient.name.given.extension.first().value = true   // extension of the primitive value

The automatic conversion means that in most respects, a FHIR primitive can generally be treated as if it was the equivalent FHIRPath system type. The primary exception is the is() operation, where the difference is explicit:

Patient.name.given.is(FHIR.string);
Patient.name.given.is(System.string).not();
Patient.name.given.getValue().is(System.string);

As shown, all FHIR primitives have the operation getValue() defined (see below) for the few edge cases where the automatic conversion isn't appropriate. Note that ofType() does not have such restrictions - both of the following are valid:

Patient.name.given.ofType(FHIR.string);
Patient.name.given.ofType(System.string);

The Mapping from FHIR Quantity to FHIRPath System.Quantity can only be applied if the FHIR Quantity has a UCUM code - i.e. a system of http://unitsofmeasure.org, and a code is present.

As part of the mapping, time-valued UCUM units are mapped to the calendar duration units defined in FHIRPath, according to the following map:

ayear
momonth
dday
hhour
minminute
ssecond

i.e. The FHIR Quantity 1 'a' would be implicitly converted to the FHIRPath System.Quantity 1 'year'. Note that there's a subtle difference between the UCUM definitions for a and mo, which are definition durations of 365.25 and 30 days respectively, while year and month are calendar based durations, and their length of time varies. See Time-valued Quantities for further discussion. Implementers should be aware of these subtle differences, but in general, this approach matches what users expect most closely.

 

FHIR defines two specific variables that are always in scope when FHIRPath is used in any of the contexts above:

%resource // the resource that contains the original node that is in %context
%rootResource // the container resource for the resource identified by %resource

The resource is very often the context, such that %resource = %context. When a DomainResource contains another resource, and that contained resource is the focus (%resource) then %rootResource refers to the container resource. Note that in most cases, the resource is not contained by another resource, and then %rootResource is the same as %resource.

FHIR adds (compatible) functionality to the set of common FHIRPath functions:

extension(url : string) : collection

Will filter the input collection for items named "extension" with the given url. This is a syntactical shortcut for .extension.where(url = string), but is simpler to write. Will return an empty collection if the input collection is empty or the url is empty.

hasValue() : Boolean

Returns true if the input collection contains a single value which is a FHIR primitive, and it has a primitive value (e.g. as opposed to not having a value and just having extensions). Otherwise, the return value is empty.

Note to implementers: The FHIR conceptual model talks about "primitives" as subclasses of the type Element that also have id and extensions. What this actually means is that a FHIR primitive is not a primitive in an implementation language. The introduction (section 2 above) describes the navigation tree as if the FHIR model applies - primitives are both primitives and elements with children.

In FHIRPath, this means that FHIR primitives have a value child, but, as described above, they are automatically cast to FHIRPath primitives when comparisons are made, and that the primitive value will be included in the set returned by children() or descendants().

getValue() : System.[type]

Return the underlying system value for the FHIR primitive if the input collection contains a single value which is a FHIR primitive, and it has a primitive value (see discussion for hasValue()). Otherwise the return value is empty.

resolve() : collection

For each item in the collection, if it is a string that is a uri (or canonical or url), locate the target of the reference, and add it to the resulting collection. If the item does not resolve to a resource, the item is ignored and nothing is added to the output collection.

The items in the collection may also represent a Reference, in which case the Reference.reference is resolved. If the input is empty, the output will be empty.

as(type : identifier) : collection

An alias for ofType() maintained purely for backwards compatibility.

ofType(type : identifier) : collection

Returns a collection that contains all items in the input collection that are of the given type or a subclass thereof. This works the same as in the base FHIRPath specification, but implementers should be aware that in FHIR, only concrete core types are allowed as an argument. All primitives are considered to be independent types (so markdown is not a subclass of string). Profiled types are not allowed, so to select SimpleQuantity one would pass Quantity as an argument.

elementDefinition() : collection

Returns the FHIR element definition information for each element in the input collection. If the input collection is empty, the return value will be empty.

slice(structure : string, name : string) : collection

Returns the given slice as defined in the given structure definition. The structure argument is a uri that resolves to the structure definition, and the name must be the name of a slice within that structure definition. If the structure cannot be resolved, or the name of the slice within the resolved structure is not present, or those parameters are empty, and empty value is returned.

For every element in the input collection, if the resolved slice is present on the element, it will be returned. If the slice does not match any element in the input collection, or if the input collection is empty, the result is an empty collection ({ }).

checkModifiers(modifier : string) : collection

For each element in the input collection, verifies that there are no modifying extensions defined other than the ones given by the modifier argument. If the check passes, the input collection is returned. Otherwise, an error is thrown, including if modifier is empty.

conformsTo(structure : string) : Boolean

Returns true if the single input element conforms to the profile specified by the structure argument, and false otherwise. If the input is not a single item, the structure is empty, or the structure cannot be resolved to a valid profile, the result is empty.

memberOf(valueset : string) : Boolean

When invoked on a single code-valued element, returns true if the code is a member of the given valueset. When invoked on a single concept-valued element, returns true if any code in the concept is a member of the given valueset. When invoked on a single string, returns true if the string is equal to a code in the valueset, so long as the valueset only contains one codesystem. If the valueset in this case contains more than one codesystem, the return value is empty.

If the valueset cannot be resolved as a uri to a value set, or the input is empty or has more than one value, the return value is empty.

Note that implementations are encouraged to make use of a terminology service to provide this functionality.

For example:

Observation.component.where(code.memberOf('http://hl7.org/fhir/ValueSet/observation-vitalsignresult'))

This expression returns components that have a code that is a member of the observation-vitalsignresult valueset.

subsumes(code : Coding | CodeableConcept) : Boolean

When invoked on a Coding-valued element and the given code is Coding-valued, returns true if the source code is equivalent to the given code, or if the source code subsumes the given code (i.e. the source code is an ancestor of the given code in a subsumption hierarchy), and false otherwise.

If the Codings are from different code systems, the relationships between the code systems must be well-defined or the return value is an empty value.

When the source or given elements are CodeableConcepts, returns true if any Coding in the source or given elements is equivalent to or subsumes the given code.

If either the input or the code parameter are not single value collections, the return value is empty.

Note that implementations are encouraged to make use of a terminology service to provide this functionality.

subsumedBy(code: Coding | CodeableConcept) : Boolean

When invoked on a Coding-valued element and the given code is Coding-valued, returns true if the source code is equivalent to the given code, or if the source code is subsumed by the given code (i.e. the given code is an ancestor of the source code in a subsumption hierarchy), and false otherwise.

If the Codings are from different code systems, the relationships between the code systems must be well-defined or a run-time error is thrown.

When the source or given elements are CodeableConcepts, returns true if any Coding in the source or given elements is equivalent to or subsumed by the given code.

If either the input or the code parameter are not single value collections, the return value is empty.

Note that implementations are encouraged to make use of a terminology service to provide this functionality.

htmlChecks : Boolean

When invoked on a single xhtml element returns true if the rules around HTML usage are met, and false if they are not. The return value is empty on any other kind of element, or a collection of xhtml elements.

~ (Equivalence)

Equivalence works in exactly the same manner, but with the addition that for complex types, equality requires all child properties to be equal, except for "id" elements.

In addition, for Coding values, equivalence is defined based on the code and system elements only. The version, display, and userSelected elements are ignored for the purposes of determining Coding equivalence.

For CodeableConcept values, equivalence is defined as a non-empty intersection of Coding elements, using equivalence. In other words, two CodeableConcepts are considered equivalent if any Coding in one is equivalent to any Coding in the other.

The FHIR specification adds support for additional environment variables:

The following environmental values are set for all contexts:

%sct        // (string) url for snomed ct
%loinc      // (string) url for loinc
%"vs-[name]" // (string) full url for the provided HL7 value set with id [name]
%"ext-[name]" // (string) full url for the provided HL7 extension with id [name]
%resource	// The original resource current context is part of. When evaluating a datatype, this would be the resource the element is part of. Do not go past a root resource into a bundle, if it is contained in a bundle.

// Note that the names of the `vs-` and `ext-` constants are quoted (just like paths) to allow "-" in the name.

For example:

Observation.component.where(code.memberOf(%"vs-observation-vitalsignresult"))

This expression returns components that have a code that is a member of the observation-vitalsignresult valueset.

Implementation Note: Implementation Guides are allowed to define their own externals, and implementers should provide some appropriate configuration framework to allow these constants to be provided to the evaluation engine at run-time. E.g.:

%"us-zip" = '[0-9]{5}(-[0-9]{4}){0,1}'

Authors of Implementation Guides should be aware that adding specific environment variables restricts the use of the FHIRPath to their particular context.

Note that these tokens are not restricted to simple types, and they may have fixed values that are not known before evaluation at run-time, though there is no way to define these kinds of values in implementation guides.

This page documents a restricted subset of the FHIRPath language that is used in a few contexts in this specification. When the restricted FHIRPath language subset is in use, the following rules apply:

  • All statements SHALL start with the name of the context element (e.g. on a Patient resource, Patient.contact.name.), or SHALL be simply "$this" to refer to the element that has focus
  • Operators SHALL NOT be used
  • Only the following functions may be used:
    • .resolve()
    • .extension("url")
    • .ofType(type)
    All other functions SHALL NOT be used

These rules exist to keep processing the path simple to support use of the path by processors that are not backed by a full FHIRPath implementation.

The following locations use this restricted FHIRPath language:

Unlike this rest of this page, the FHIR Terminology service API is only draft (Maturity = 0). It will be advanced to a more mature status following the usual Maturity Model for FHIR.

In order to support terminological reasoning in FHIRPath statements, FHIR defines a general %terminologies object that FHIRPath implementations should make available. Calls to this object are passed through a standard FHIR terminology service.

Summary:

%terminologies.expand(valueSet, params) : ValueSet
%terminologies.lookup(coded, params) : Parameters
%terminologies.validateVS(valueSet, coded, params) : Parameters
%terminologies.validateCS(codeSystem, coded, params) : Parameters
%terminologies.subsumes(system, coded1, coded2, params) : code
%terminologies.translate(conceptMap, code, params) : Parameters

All these functions return an empty value if any of the parameters are empty, or a collection with more than one value, or one or more of the parameters are not valid.

expand

%terminologes.expand(valueSet, params) : ValueSet

This calls the Terminology Service $expand operation (formal definition).

Parameters:

  • valueSet: either an actual ValueSet, or a canonical URL reference to a value set.
  • params: a URL encoded string with other parameters for the expand operation (e.g. 'displayLanguage=en&activeOnly=true')

Return Value: a ValueSet with an expansion, or an empty value if an error occurs.

lookup

%terminologies.lookup(coded, params) : Parameters

This calls the Terminology Service $lookup operation (formal definition).

Parameters:

  • coded: either a Coding, a CodeableConcept, or a resource element that is a code
  • params: a URL encoded string with other parameters for the lookup operation (e.g. 'date=2011-03-04&displayLanguage=en')

Return Value:

validateVS

%terminologies.validateVS(valueSet, coded, params) : Parameters

This calls the Terminology Service $validate-code operation on a value set (formal definition).

Parameters:

  • valueSet: either an actual ValueSet, or a canonical URL reference to a value set.
  • coded: either a Coding, a CodeableConcept, or a resource element that is a code
  • params: a URL encoded string with other parameters for the validate-code operation (e.g. 'date=2011-03-04&displayLanguage=en')

Return Value: A Parameters resource with the results of the validation operation.

validateCS

%terminologies.validateCS(codeSystem, coded, params) : Parameters

This calls the Terminology Service $validate-code operation on a code system (formal definition).

Parameters:

  • codeSystem: either an actual CodeSystem, or a canonical URL reference to a code system.
  • coded: either a Coding, a CodeableConcept, or a resource element that is a code
  • params: a URL encoded string with other parameters for the validate-code operation (e.g. 'date=2011-03-04&displayLanguage=en')

Return Value: A Parameters resource with the results of the validation operation.

subsumes

%terminologies.subsumes(system, coded1, coded2, params) : code

This calls the Terminology Service $subsumes operation (formal definition).

Parameters:

  • system: the URI of a code system within which the subsumption testing occurs
  • coded1: A Coding or a resource element that is a code
  • coded2: A Coding or a resource element that is a code
  • params: a URL encoded string with other parameters for the validate-code operation (e.g. 'version=2014-05-06')

Return Value: a code as specified for the subsumes operation.

translate

%terminologies.translate(conceptMap, coded, params) : Parameters

This calls the Terminology Service $translate operation (formal definition).

Parameters:

  • conceptMap: either an actual ConceptMap, or a canonical URL reference to a value set.
  • coded: The source to translate: a Coding or a resource element that is a code
  • params: a URL encoded string with other parameters for the validate-code operation (e.g. 'source=http://acme.org/valueset/23&target=http://acme.org/valueset/23')

Return Value: A Parameters resource with the results of the translation operation.