Skip to main content

FHIRPath

FHIRPath is a language, similar to XPath, that allows you to navigate a FHIR® resource to evaluate and extract data from its fields using a straightforward syntax that includes paths, functions, and operations. For example, you could evaluate whether the given name of a Patient contained a value: Patient.name.given.empty(). Or you could extract the value of the Patient resource’s telecom field, but only if offical is the value of its use field: Patient.telecom.where(use = 'official').

In FHIRPath, expressions are collection-based. Each function works on one input collection and each binary operator operates on two input collections, and the values returned by the expression are gathered into an output collection. Some functions and operations place constraints on the size of their input collections.

For complete details about FHIRPath including how to build an expression, see the HL7 FHIRPath specification. InterSystems supports a subset of the functions and operations that are defined in the specification.

Workflow

With InterSystems technology, the process of using FHIRPath to evaluate and extract data from a resource is straightforward:

Instantiate FHIRPath object, parse FHIRpath expression, evaluate a resource, and work with collection of results

The following sections provide details about each step in the workflow.

Instantiate HS.FHIRPath.API

The process of using FHIRPath to evaluate and extract data from a resource begins with calling HS.FHIRPath.API.getInstance(). When you call this method, you must specify the FHIR package that corresponds to a version of FHIR. For example, if the resources you are evaluating conform to FHIR R4, the corresponding package ID is currently hl7.fhir.r4.core@4.0.1. In this case, instantiating HS.FHIRPath.API would look like:

 set fhirPathAPI = ##class(HS.FHIRPath.API).getInstance($lb("hl7.fhir.r4.core@4.0.1"))

You can obtain the IDs of the currently loaded packages using the Management Portal or ObjectScript:

  • Management Portal — Navigate to Home > Health > MyFHIRNamespace > FHIR Configuration, and select the Package Configuration card. The package ID is obtained by appending the @ symbol and version number to the name of the package. For example, the ID of the following package is hl7.fhir.r4.core@4.0.1:

    name of FHIR package: hl7.fhir.r4.core

  • ObjectScript — To list package IDs programmatically, see Listing Available Packages.

The HS.FHIRPath.API object includes the methods used to parse FHIRPath expressions and evaluate resources. This object is also included as a property on the HS.FHIRMeta.API object under the FHIRPathAPI property.

Parse the FHIRPath Expression

Once you have instantiated the HS.FHIRPath.API object, you are ready to parse the FHIRPath expression. The method that parses the expression, HS.FHIRPath.API.parse(), returns a tree structure that is used by the methods that evaluate a resource. For example, assuming you have an object named fhirPathAPI instantiated as shown in the previous section:

 set tree = fhirPathAPI.parse("name.given.empty()")

Evaluate the Resource

Once you have parsed the FHIRPath expression, you can use its tree structure to evaluate or extract data from a resource. Two evaluation methods are available:

In both cases, the resource being evaluated is passed into the method as a dynamic object. The tree that was returned by the parse() method is also passed as an argument. For example:

 set tree = fhirPathAPI.parse("name.given.empty()")
 // myResource is a dynamic object
 do fhirPathAPI.evaluate(myResource, tree, .OUTPUT)
 set DynArray = fhirPathAPI.evaluateToJson(myResource, tree)

An additional method, HS.FHIRPath.API.evaluateArray(), can be used to parse the multidimensional array returned by the evalaute() method.

Work with the Results

While working with results in a dynamic array that is produced by evaluateToJson() has its benefits, the multidimensional array produced by evaluate() contains additional information that is not otherwise available. The following provides a guide to the data in the multidimensional array, assuming that your response to evaluate() was returned in a variable named OUTPUT.

Node Description
OUTPUT Number of nodes in the array that contain values.
OUTPUT(n) Value of the nth element of the array.
OUTPUT(n,"t") Data type of the nth element in the array, including identifying FHIR data types.

You can further parse the returned multidimensional array using the evaluateArray() method.

By contrast. when using the evaluateToJson() method to produce a dynamic array, you can determine whether the data type is a string, boolean, number, or object from looking at the values in the array, but you cannot determine the FHIR data type.

Workflow Example: evaluate() Method

This example includes the resource being evaluated, the ObjectScript needed to evaluate the resource, and a look at the multidimensional array produced by the evaluation.

Sample Resource
 set myResource = {
   "resourceType":"Patient",
   "telecom": [
     {
       "system": "phone",
       "value": "(03) 5555 6473",
       "use": "official"
    },
    {
      "system": "phone",
      "value": "(03) 5555 6473",
      "use": "home"
    },
    {
      "system": "email",
      "value": "myName@email.com",
      "use": "official"
     }
   ]
 }
Extracting Data from the Resource
 set fhirVersion = $lb("hl7.fhir.r4.core@4.0.1")
 set fhirPathAPI = ##class(HS.FHIRPath.API).getInstance(fhirVersion)
 set tree = fhirPathAPI.parse("telecom.where(use = 'official')")
 do fhirPathAPI.evaluate(myResource, tree, .OUTPUT)
Viewing the Multidimensional Array

If you used the zw OUTPUT command in the InterSystems Terminal to view the multidimensional array returned by evaluate(), the result would be:

OUTPUT=2
OUTPUT(1)={"system":"phone","value":"(03) 5555 6473","use":"official"}
OUTPUT(1,"t")="ContactPoint"
OUTPUT(2)={"system":"email","value":"myName@email.com","use":"official"}
OUTPUT(2,"t")="ContactPoint"

Notice that the values are identified as a ContactPoint FHIR data type.

Workflow Example: evaluateArray() Method

This example takes the multidimensional array produced by the evaluation in the evaluate() example above as input and demonstrates the ObjectScript needed to evaluate the resulting array, and looks at the multidimensional array produced by the evaluation.

Extracting Data from the Output Array
 Merge INPUT = OUTPUT
 Kill OUTPUT

 Set tree = fhirPathAPI.parse("ContactPoint.value")

 do fhirPathAPI.evaluateArray(.INPUT, tree, .OUTPUT)
Viewing the Multidimensional Array

If you used the zw OUTPUT command in the InterSystems Terminal to view the multidimensional array returned by evaluateArray(), the result would be:

OUTPUT=2
OUTPUT(1)="(03) 5555 6473"
OUTPUT(1,"t")="string"
OUTPUT(2)=”myName@email.com"
OUTPUT(2,"t")="string"

Notice that the values are identified by their ObjectScript data type (string, boolean, number, or object).

Workflow Example: evaluateToJson() Method

This example includes the resource being evaluated, the ObjectScript needed to evaluate the resource, and a look at the dynamic array produced by the evaluation.

Sample Resource
 set myResource = {
   "resourceType":"Patient",
   "name": [
     {
       "family": "Cooper",
       "given": [
         "James",
         "Fenimore"
       ]
     }]
 }
Evaluating the Resource
 set fhirVersion = $lb("hl7.fhir.r4.core@4.0.1")
 set fhirPathAPI = ##class(HS.FHIRPath.API).getInstance(fhirVersion)
 set tree = fhirPathAPI.parse("name.given.empty()")
 set dynArray = fhirPathAPI.evaluateToJson(myResource, tree)
Viewing the Dynamic Array

If you used the zw dynArray command in the InterSystems Terminal to view the dynamic array, the result would be:

dynArray=[false]

Functions

The FHIRPath specification defines a wide range of functions that can be used in an expression. InterSystems supports a subset of those functions.

Supported FHIRPath Functions
Function Example
[ ] (index) Practitioner.name[1]
aggregate item.factor.aggregate($total+$this,0)
as Condition.abatement.as(string)
empty name.empty()
exists Patient.telecom.exists(system = 'phone')
extension extension('http://intersystems.com/fhir/extn/sda3/lib/code-table-detail-care-provider-description').value as string
iif iif(1=1,2,3)
is Condition.abatement.is(dateTime)
not gender.not()
resolve Organization.partOf.resolve()
union Practitioner.name.family.union(Practitioner.id)
where Patient.telecom.where(use = 'official')

Operations

The FHIRPath specification defines a wide range of operations that can be used in an expression. InterSystems supports a subset of those operations.

Supported FHIRPath Operations
Operation Example
+ (addition)
8 + 3
5 seconds + 3 seconds
'string1' + ' and ' + 'string2'
& (string concatenation) 'string1' & ' and ' & 'string2'
= (equals)
Practitioner.name[0].family = 'Cooper'
Practitioner.meta.versionId = 10
!= (not equals) Practitioner.name[1].family != 'Smith'
| (union collections) Practitioner.name.family | Practitioner.id
and true and false
as See implementation notes.
implies Patient.name.given.exists() implies Patient.name.family.exists()
is Practitioner.name[0] is HumanName
or true or false
xor true xor false
Implementation Notes for as

According to the FHIRPath specification, the left operand of the as operation must be a collection with a single item. However, the InterSystems implementation of FHIRPath allows this collection to have multiple values. For example, suppose you have an Observation with multiple extensions that reference a Patient. With the InterSystems implementation of FHIRPath, the following expression would still be valid: extension.value as Reference.

Improving Performance

InterSystems provides an in-memory cache that can store parsed FHIRPath expressions, improving performance when you have a set of expressions that are repeated frequently. Once the cache is enabled, tree structures produced by the parse() method are stored until the cache is cleared.

To enable the in-memory cache, call:

do fhirPathAPI.enableCache(1)

To disable the cache, call:

do fhirPathAPI.enableCache(0)
Feedback