From Arrays to Sub-Arrays – FHIR Slicing Can Be Easy!

By: Amos (Kippi) Bordowitz

Slicing in FHIR - The power of profiling in FHIR® is the ability to constrain or extend any element in the base Resource. One of the ways we may constrain an element in FHIR® is known as slicing.

Slicing is the act of taking a list element and splitting it into sub-lists. Each sub-list can be given clear rules on how elements within it are treated and tested, what the cardinality is, etc.
But why would we need this kind of functionality? A classic place for this is the “identifier” element found in almost all Resources. Let's make sure we are “speaking the same language”. The identifier is not the logical id of the resource, but the business identifier. This number represents the actual entity that the resource is describing. For example, a patient has some form of identification – every Israeli national has an Israeli ID number; tourists on vacation in Israel will have a passport, etc.

Imagine your organization needs to be able to handle patients with different types of identification. Each type of identification has different rules: Israeli IDs, for example, are 9 digits long, can be validated according to a mathematical formula, and are part of a dedicated namespace. Passports, obviously, follow different rules. Now, if we look at the Patient base resource, we can see that there is only a single element “identifier” and that it’s a list (we can tell it’s a list by looking at the cardinality, which has an asterisk - * - as the maximum). This element can accept any identifier we wish to pass but as it stands, we have no way of validating the data for each identifier type we are willing to accept.

Slicing in FHIR

Enter Slicing

Slicing allows us to set specific rules for sub-lists. If we go back to our identifier – say we want to allow 2 identifier types: Social security number (SSN) and US passport number (PPN). Now, as we mentioned, each identifier type follows different rules. By slicing the element, we can set the rules for each slice such that when a validator checks the information, it can distinguish between items of the list and then know what rules apply to each item.

Let’s take a hospital in say NYC. Assuming that a patient must have a SSN and may also supply a US passport number (both should be entered into the “identifier” element), in the corresponding Patient profile the cardinality of the SSN slice will be set to 1..1 (i.e., only one but there MUST be one. An American cannot have more than one) and of the PPN slice to 0..1 (at most one, but not mandatory).

Now, when the hospital creates a new Patient resource, if it is to adhere to the rules set in the slicing, it will only be valid if “Patient.identifier” has at least 1 item – a SSN, and if it also has a PPN – not more than one.

But how can we tell that we only have one of each?

Discriminators

To allow a validator to figure this out, we must supply it with a Discriminator. This is a rule allowing it to distinguish between different items of the array. In this case, as we are dealing with identifiers, we can use the fact that no identifier is reliable without its namespace (or – system). An identifier without a system is not a unique identifier at all!So, each identifier is built from two pieces of information: the system and the value (passport number in our case).

So, armed with this information, we can set a discriminator for our slicing. A discriminator is basically the element of information that allows us to tell which slice the item belongs to. We want to set the discriminator such that it would guarantee that any item of the list can be unequivocally assigned to the right slice.

A discriminator is actually two values: path and type. The path is the nominated element – the element which will be used for distinguishing the items (using a simple subset of FHIRPath), and the type indicates how the field is processed when evaluating the discriminator.

There are 5 types: value, exists, pattern, type, profile.  According to the FHIR® website:

value: The slices have different values in the nominated element.
exists: The slices are differentiated by the presence or absence of the nominated element.
pattern: The slices have different values in the nominated element, as determined by testing them against the applicable ElementDefinition.pattern[x]. The pattern therefore sets minimum expectations on the content of the element, without confining any other child elements that may exist but are not addressed by the pattern. The use of pattern may be the obvious choice for complex datatypes, but it is also relevant for primitives – if you don’t want to prevent the use of extensions on the primitive element.
type: the slices are differentiated by the type of the nominated element. This is only relevant for elements that allow a choice of datatype.
profile: The slices are differentiated by conformance of the nominated element to a specified profile. Read more about this in the FHIR® specs.

Going back to the hospital’s Patient profile. The determining factor for the discriminator is the value of the system element – to what namespace the identifier value belongs. So we would set the path to be ”system”, and the type to “value”.  Thus the value of “system” – the identifier's namespace - will be the information we need to differentiate by.

The notation of such a discriminator is “system(value)” or “system:value”, i.e., the value in the element system.

Let’s see what it would look like in the StructureDefinition JSON:

Note: “rules”: “open” – denotes that additional content is allowed anywhere in the list.

Rules

Now we can set different rules for each slice, starting with the information in the nominated element. In the SSN slice we will set the cardinality to 1..1. Then we populate system with the fixed value of the URI identifying the social security numbers namespace. Finally, we may add an invariant that checks the validity of the number. This might include making sure the number is 9 digits long and possibly enforcing any other rules for validating SSNs.

We do the same for the second slice, PPN; we set system to the URI of American passport numbers. Next, cardinality set to 0..1. Finally, any additional rules that apply to US passport numbers (maybe a regex) may also be added.

Thus, if the validator sees that the value of system is the URI of the SSN database, it will know that it belongs to the SSN and will then go ahead and validate the data against the specific rules set for the slice. The validator will also make sure that we have one (and only one) item with the SSN URI and at most one item with the US PPN URI. Any other items passed into the identifier array will not be affected by the rules set in the different slices and will be validated only according to the basic rules of FHIR®.

Slices may also contain their own extensions when needed, and one slice having an extension has no effect on other slices that might not require it.

In special cases we might want to use a default slice in cases of data that doesn’t conform to other slices. There are strict guidelines regarding this slice, which can be found here. We will just mention that default slices may only be used if the discriminator rules are set to “rules”: “closed”, and that the way to denote a default slice is to name it “@default”.

Binding

It is also possible to distinguish between slices by binding a slice to a required ValueSet. Imagine the following scenario: say we want to have 2 slices on an element, which is an array of CodeableConcepts. Each slice is distinguished by what codes it can accept, which are regulated by what ValueSet each code comes from. Determining the correct slice for a code is possible if the codes in the two ValueSets do not overlap. We can find an example of this in the IL-Core immunization profile under vaccineCode.

This is also useful in cases where the system itself can change.

For example, in our hospital example, the hospital would take any passport instead of just a US passport. In such a case we couldn’t put the URI of US passport numbers as a fixed system. Instead, we would need to bind the system to a ValueSet containing the URIs of all different passport systems. We can see an example of this in the IL-Core Patient Profile.

Best practices

We might not actually want to extend or constrict the use of the element we are slicing. We might simply want to make sure the implementer knows about special considerations, via comments or other available tools. One should practice Care to make these cases as clear as possible.

FHIR® Shorthand

We at Outburn are big fans of FSH, and here is another great reason. Normally, when creating an instance in FHIR®, one cannot specify to what slice the data we are entering belongs. FSH, on the other hand, allows us to do just that. The compiler that turns FSH files into FHIR® JSON artifacts is named SUSHI. It automatically populates any fixed values specified in the slice definition on the profile level.

A nice and simple example of this is when we use the HL7 blood-pressure profile. It is enough to fill the value (i.e., the number) of the systolic/diastolic slices using the slice name. SUSHI will automatically populate the corresponding LOINC code and the coded UCUM unit of measure, saving us time and effort.

Go FSH!

------

In conclusion, slicing allows us to take any array and divide it into sub-arrays with specific rules, extensions and considerations. Understanding slicing is imperative for any profiling.  Slicing, and profiling in general can easily be handled while using FHIR® Shorthand (FSH). Want to know more about FSH and how to use it? Here at Outburn, we teach profiling with FSH. Check out our academy page for more information.

Follow us on LinkedIn

More To Explore

Dosage and Timing

Dosage and Timing: A guide

by: Sima Morgenstern Dosage and Timing If you’ve had the chance to implement any of the following resources: ActivityDefinition, Dosage and Timing If you’ve had

The word "Resources" in flames with a black backdrop

FHIR Resources – Everything you need to know

By: Amos (kippi) Bordowitz FHIR® (Fast Healthcare Interoperability Resources) is HL7’s modern standard for the electronic exchange of information in the healthcare ecosystem. The main