FHIR CI-Build

This is the Continuous Integration Build of FHIR (will be incorrect/inconsistent at times).
See the Directory of published versions icon

Note to Balloters: Key changes made since FHIR 6.0.0-ballot4:

Responsible Owner: FHIR Infrastructure icon Work GroupStandards Status: Normative

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

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

FHIRPath is used and extended in many other contexts beyond those listed above. For additional examples and information about other usage patterns and extensions, refer to the FHIRPath Usage and Extensions page icon on HL7's confluence.

FHIR inter-version compatibility rules allow for non-repeating elements to be made repeating in future FHIR versions. For this reason, FHIRPath expressions SHOULD be written presuming all elements will repeat, even if the current version of the model has a maximum cardinality of '1'.

 

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 ofType function:

(Observation.value.ofType(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.where(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() function 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 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.markdown, FHIR.base64Binary System.String
FHIR.integer, FHIR.unsignedInt, FHIR.positiveInt System.Integer
FHIR.integer64 System.Long
FHIR.decimal System.Decimal
FHIR.dateTime, FHIR.instant System.DateTime
FHIR.date System.Date
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
!Patient.active.hasValue() and !Patient.active.empty() // can both be true, if there are extensions but no value for Patient.active

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() function, 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)

This also applies to e.g. Resource.id:

Patient.id is System.String
(Patient.id is FHIR.id).not

As shown, all FHIR primitives have the function getValue() defined (see below) for the few edge cases where the automatic conversion is not 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 icon defined in FHIRPath, according to the following map:

a year
mo month
d day
h hour
min minute
s second

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 icon 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
%profile      // the canonical URL of a profile that contains the invariant's fhirpath expression (only defined in profile invariants)
              // Note: not all fhirpath engines support this profile variable, or the slice() function that usually uses it.

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.

In addition to the general purpose variables above, additional variables and/or guidance about variable use are defined when working with specific resources. Refer to the following for additional FHIRPath guidance defined for:

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

In addition to the general purpose functions below, additional functions function use are defined when working with specific resources. Refer to the following for additional FHIRPath guidance defined for:

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. If the input collection is empty or the url is empty, the return value will be an empty collection.

Patient.extension('http://hl7.org/fhir/StructureDefinition/patient-mothersMaidenName').value

If the input collection contains a single value which is a FHIR primitive, then will return true if the single value is a primitive value (e.g., as opposed to not having a value and just having extensions) and false if not. If the input collection is not a single FHIR primitive, 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().

Patient.active.hasValue()

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.

Patient.birthDate.getValue() // returns just the primitive, does not include extensions (such as the birthTime extension)

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 return value will be an empty collection.

Patient.managingOrganization.resolve().name
Observation.subject.where(resolve() is Patient)

When implementing resolve(), it is at the discretion of the engine what protocols, FHIR formats and versions are supported and whether and which logical models are handled.

DocumentReference.content.attachment.url.resolve() // When using DocumentReference as an index entry to resources stored elsewhere

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


Returns the input collection filtered to items that conform to the specified profile slice.

The structure argument is the (possibly versioned) canonical uri of the structure definition that contains the specified slice.
The name argument is either the ElementDefinition.sliceName for the element slice (if the sliceName is unique in the snapshot), or the ElementDefinition.id of the element slice.

The structure argument can also be the special variable %profile which refers to the profile in which the ElementDefinition.constraint containing the FHIRPath is defined. (This variable can only be used for FHIRPath appearing in constraints)

If the structure cannot be resolved, or the name of the slice is not present in the profile, or those parameters are empty, the return value will be an empty collection.

If the slice does not match any element in the input collection, or if the input collection is empty, the return value will be an empty collection.

For example, this invariant could appear in a Patient profile:

// ensure that a patient has at least one home phone and one home email (based on the slicing defined in the profile)
Patient.telecom.slice(%profile, 'homephone').exists() and Patient.telecom.slice(%profile, 'homeemail').exists()
NOTE: not all FHIRPath engines are in a position to implement slice() as implementation requires implementation of a FHIR validation engine, which is not a small undertaking.

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


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 return value is empty.

Patient.conformsTo('http://hl7.org/fhir/StructureDefinition/Patient')

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.


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 empty.

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.

%terminologies.subsumes(Procedure.category, Procedure.code) = 'subsumes'

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.


When invoked on a single xhtml element, the function returns true if the rules around HTML usage are met, and false if they are not. If invoked on items of type 'string', the contents of the string are parsed as the content of a div and the function returns false if the string does not parse as valid HTML or fails the rules around HTML usage. The return value is empty on any other kind of element or if invoked on a collection of elements.


This functions returns the ordinal value for an element. This may be based on an itemWeight extension defined on an element such as QuestionnaireResponse answer, or it may be based on the weight property defined on a code. In some cases, this may require looking across resources. For example, QuestionnaireResponse.item.where(linkId='123').answer.first().weight() may need to find the corresponding item in the Questionnaire and then look up the coding specified in 'answer' with the corresponding answerOption in Questionnaire.item with the same linkId. If no weight is defined for the context element, the return value is empty. If the FHIRPath engine is unable to resolve the corresponding value set, code system or questionnaire options, it SHOULD cause the expression to fail. This function will typically be used to support scoring of Questionnaires, but it can be used with observations or potentially other elements as well.

FHIR also includes overrides to some functions providing details on how the function will work with FHIR specific types.

If the input collection contains a single item, this function will return a single String if the type is a FHIR primitive, and it has a value (e.g. if hasValue() = true), and the primitive type has a System type for which toString() is defined icon. Otherwise the result is an empty collection.

Patient.birthDate.toString()

Returns a collection that contains all items in the input collection that are of the given type or a subclass thereof. This is as defined 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.

Observation.value.ofType(canonical)
Observation.value.ofType(dateTime) | Observation.value.ofType(Period).start // selects either dateTime or Period starts (both of type dateTime)

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 icon 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: