Skip to main content

FHIRPath

FHIRPath is a language, similar to XPath, that allows you to navigate an HL7® 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 specificationOpens in a new tab. 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()Opens in a new tab. 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.APIOpens in a new tab 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.APIOpens in a new tab object includes the methods used to parse FHIRPath expressions and evaluate resources. This object is also included as a property on the HS.FHIRMeta.APIOpens in a new tab object under the FHIRPathAPI property.

Parse the FHIRPath Expression

Once you have instantiated the HS.FHIRPath.APIOpens in a new tab object, you are ready to parse the FHIRPath expression. The method that parses the expression, HS.FHIRPath.API.parse()Opens in a new tab, 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()Opens in a new tab, 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)Opens in a new tab Practitioner.name[1]
aggregateOpens in a new tab item.factor.aggregate($total+$this,0)
asOpens in a new tab Condition.abatement.as(string)
childrenOpens in a new tab Encounter.participant.children().ofType(Reference)
descendantsOpens in a new tab Bundle.descendants().ofType(Patient)
emptyOpens in a new tab Patient.contact.where(relationship = 'N').name.empty()
endsWithOpens in a new tab 'abcdefg'.endsWith('efg')
existsOpens in a new tab Patient.telecom.exists(system = 'phone')
extensionOpens in a new tab extension('http://intersystems.com/fhir/extn/sda3/lib/code-table-detail-care-provider-description').value as string
firstOpens in a new tab Patient.telecom.where(system = 'phone').first()
hasExtensionOpens in a new tab Returns true if any of the input collection have an extension with the specified URL. (This function is not in the FHIRPath v2.0.0 specification.)
iifOpens in a new tab iif(1=1,2,3)
indexOfOpens in a new tab 'abcdefg'.indexOf('cd')
isOpens in a new tab Condition.abatement.is(dateTime)
lastOpens in a new tab Patient.name.first().given.last()
notOpens in a new tab Bundle.entry.resource.ofType(Patient).gender.not()
ofTypeOpens in a new tab Bundle.entry.resource.ofType(Patient)
resolveOpens in a new tab Organization.partOf.resolve()
skipOpens in a new tab Bundle.entry.resource.ofType(Encounter).skip(5)
startsWithOpens in a new tab 'abcdefg'.startsWith('abc')
substringOpens in a new tab 'abcdefg'.substring(1, 2)
tailOpens in a new tab Bundle.entry.resource.ofType(Observation).tail()
takeOpens in a new tab Patient.name.take(1)
unionOpens in a new tab Practitioner.name.family.union(Practitioner.id)
whereOpens in a new tab 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)Opens in a new tab

8 + 3

5 seconds + 3 seconds

'string1' + ' and ' + 'string2'

& (string concatenation)Opens in a new tab 'string1' & ' and ' & 'string2'
= (equals)Opens in a new tab

Practitioner.name[0].family = 'Cooper'

Practitioner.meta.versionId = 10

!= (not equals)Opens in a new tab Practitioner.name[1].family != 'Smith'
| (union collections)Opens in a new tab Practitioner.name.family | Practitioner.id
andOpens in a new tab true and false
asOpens in a new tab See implementation notes.
impliesOpens in a new tab Patient.name.given.exists() implies Patient.name.family.exists()
isOpens in a new tab Practitioner.name[0] is HumanName
orOpens in a new tab true or false
xorOpens in a new tab true xor false
Implementation Notes for as

According to the FHIRPath specification, the left operand of the asOpens in a new tab 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)
FeedbackOpens in a new tab