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 Group | Maturity Level: Normative | Standards 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:
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)
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:
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
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 bychildren()
ordescendants()
.
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:
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:
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:
Return Value:
validateVS
%terminologies.validateVS(valueSet, coded, params) : Parameters
This calls the Terminology Service $validate-code operation on a value set (formal definition).
Parameters:
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:
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:
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:
Return Value: A Parameters resource with the results of the translation operation.