FHIR Shorthand, published by HL7 International / FHIR Infrastructure. This guide is not an authorized publication; it is the continuous build for version 3.0.0 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/HL7/fhir-shorthand/ and changes regularly. See the Directory of published versions
NOTE: Information on this page is normative content except where noted.
This chapter contains the formal specification of the FHIR Shorthand (FSH) language. It is intended primarily as a reference, not a tutorial. For tutorials and additional documentation please consult the Overview or go to fshschool.org.
In this specification, the case-sensitive key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in RFC2119.
Portions of the specification designated as Trial Use are indicated by TU and background shading. All examples in the specification are informative content. Remaining unmarked sections contain normative content.
The FSH specification uses syntax expressions to illustrate the FSH language. While FSH has a formal grammar (see Appendix: FSH Grammar), most readers will find the syntax expressions more instructive.
Syntax expressions use the following conventions:
Style | Explanation | Example |
---|---|---|
this is FSH |
Font used for FSH fragments, such as keywords, statements, and syntax expressions* | * status = #open |
{ } |
Substitution: If a datatype, replace with a value; if an item, replace with a name, id, or URL | {decimal} |
< > |
Indicates an element or path to an element with the given datatype MUST be substituted | <CodeableConcept> |
orange color | An OPTIONAL item in a syntax expression | {flag} |
... |
Indicates a pattern that MAY be repeated | {flag1} {flag2} {flag3} ... |
/ |
A choice of items | Resource/Profile |
bold | A directory path or file name | example-1.fsh |
* NOTE: This specification also uses code styling
for a selected set of non-FSH expressions, such as FHIR paths and element names (e.g., Patient.name.given
, the Observation value[x]
element).
Syntax Expression Examples:
A FSH rule to assign the value of a Quantity:
* <Quantity> = {decimal or integer} '{UCUM unit}'
A FSH statement following this pattern would be written as:
A rule to constrain an element to a certain datatype or types:
* <element> only {datatype(s)}
A FSH statement following this pattern would be written as:
only
, followed byor
(see Table 3).The following tables contain additional examples of angle brackets and curly braces used in this IG:
Syntax term | Substitute… | Example(s) |
---|---|---|
<bindable> |
An element or path to an element whose datatype allows it to be bound to a value set | code |
<CodeableConcept> |
An element or path to an element whose datatype is CodeableConcept | category |
<element> |
Any element or path to any element | method.type |
<element(s)> |
One or more elements or paths, separated by and |
category and method and method.type |
<Extension> |
An element or path to an element whose datatype is Extension | extension modifierExtension bodySite.extension |
Syntax term | Substitute… | Example(s) |
---|---|---|
{card} |
A cardinality expression | 0..1 |
{code} |
A code | #active |
{CodeSystem} |
The name, id, or URL of a code system | http://terminology.hl7.org/CodeSystem/v2-0776 v2-0776 // id ItemStatus // name |
{decimal} |
A decimal number, optionally including an exponent | 124.0 58.3E-5 |
{datatype} |
A FHIR datatype or FHIR resource type defined in the project's FHIR version | decimal ContactPoint Reference(Patient) |
{datatype(s)} |
One or more FHIR datatypes or FHIR resource types defined in the project's FHIR version, separated by or |
Quantity or CodeableConcept Reference(Patient or Practitioner) Canonical(ActivityDefinition) |
{Extension} |
The name, id, or canonical URL (or alias) of an Extension | duration allergyintolerance-duration http://hl7.org/fhir/StructureDefinition/allergyintolerance-duration |
{flag} |
One of the FSH flags | MS |
{flag(s)} |
One or more flags, separated by whitespace | MS SU ?! |
{Invariant} |
The id of an Invariant | us-core-6 |
{Resource} |
The name, id, or canonical URL (or alias) of any Resource defined in the project's FHIR version | Condition |
{Resource/Profile} |
The name, id, or canonical URL (or alias) of any Resource or Profile | Condition http://hl7.org/fhir/us/core/StructureDefinition/us-core-location |
{RuleSet} |
The name of a RuleSet | MyRuleSet |
{ValueSet} |
The name, id, or canonical URL (or alias) of a ValueSet | http://hl7.org/fhir/ValueSet/address-type |
Note: When listing multiple items, consecutive elements and paths are always separated by
and
, consecutive flags are always separated by white spaces, and consecutive datatypes are always separated byor
. When listing multiple References, theor
is placed inside the Reference, e.g.Reference(Patient or Practitioner)
, notReference(Patient) or Reference(Practitioner)
A fundamental organizing construct is the FSH project, which defines the set of FSH items to be considered together. Typically, one FSH project equates to one FHIR Implementation Guide (IG). The parts of a FSH project are as follows:
Each project MUST have an associated canonical URL, used for constructing canonical URLs for items created in the project. It is up to implementations to decide how this association is made.
A FSH project SHALL contain one or more FSH items used to represent and create FHIR artifacts. FSH items can exist in various formats, for example, in text files, databases, or web forms. It is up to implementations to define the association between FSH items and FSH projects. The order of items, regardless of format, SHALL NOT affect the interpretation of those items.
Text files containing FSH items MUST use the .fsh extension. Items from all files in one project SHALL be considered globally pooled for the purposes of FSH. Changing the order of items within a .fsh file or moving FSH items between files SHALL NOT affect the interpretation of the content.
Each FSH project MUST specify the version of FHIR it depends upon. It is up to implementations to decide how projects declare their FHIR version. Implementations MAY support only a specific version or versions of FHIR.
The FSH language specification has been designed around FHIR R4 and later. The core language constructs of FSH depend primarily on a small subset of normative definitions within the FHIR specification (e.g., StructureDefinition, ValueSet, CodeSystem, and datatypes). As a result, most differences in FHIR versions do not affect FSH features or syntax. FSH provides several points of flexibility, such as FSH paths, to support authoring within the context of any FHIR version. Because the FSH specification refers to FHIR data types and definitional artifacts, however, there is no way to absolutely divorce FSH from specific FHIR versions.
TU
FSH supports new FHIR R5 datatypes integer64 and CodeableReference on a trial use basis.
Dependencies between a FSH project and other IGs MUST be declared. The form of this declaration is outside the scope of the FSH language and SHOULD be managed by implementations. In this Guide, these are referred to as "external" IGs.
Projects MAY contain other content involved in creating FHIR IGs, such as narrative text, pictures, and configuration information. This additional content is not defined in this specification, but MAY be specified by implementations.
The grammar of FSH has been described using ANTLR (see Appendix: FSH Grammar). The ANTLR grammar captures the syntax of FSH, but is not a complete specification of the language, since FSH defines the additional validation criteria for rules and items, and the behavior of rules in terms of FHIR artifacts.
If there is discrepancy between the grammar and the FSH language description, the language description takes precedence.
FSH has a number of reserved words, symbols, and patterns. Reserved words and symbols with special meaning in FSH are: contains
, named
, and
, only
, or
, obeys
, true
, false
, include
, exclude
, codes
, where
, valueset
, system
, from
, insert
, TUcontentReference
, !?
, MS
, SU
, N
, TU
, D
, =
, *
, :
, ->
, .
,[
, ]
.
The following words are reserved, with or without white spaces prior to the colon: Alias:
, TUCharacteristics:
, CodeSystem:
, TUContext:
, Extension:
, Instance:
, Invariant:
, Logical:
, Mapping:
, Profile:
, Resource:
, RuleSet:
, ValueSet:
, Description:
, Expression:
, Id:
, InstanceOf:
, Parent:
, Severity:
, Source:
, Target:
, Title:
, Usage:
, XPath:
.
The following words are reserved, with or without white spaces inside the parentheses: (example)
, (preferred)
, (extensible)
, (required)
, (exactly)
.
The following words are reserved when followed by an opening parenthesis (
with or without whitespace preceding it, a sequence of text, and then a closing parenthesis )
: Canonical
, TUCodeableReference
, Reference
.
Reserved words SHOULD NOT be used as item names or slice names in FSH projects. Implementations MAY choose to support reserved word item or slice names, but they are not required to do so.
Repeated whitespace SHALL NOT have meaning in FSH except within string literals and when used for indenting rules. Whitespace insensitivity MAY be used to improve readability. For example:
* component contains appearanceScore 0..3 and pulseScore 0..3 and grimaceScore 0..3 and activityScore 0..3 and respirationScore 0..3
MAY be reformatted as:
* component contains
appearanceScore 0..3 and
pulseScore 0..3 and
grimaceScore 0..3 and
activityScore 0..3 and
respirationScore 0..3
FSH syntax is agnostic regarding the type of whitespace used (e.g., spaces, tabs, non-breaking spaces, etc.), with the following exceptions:
FSH follows JavaScript syntax for code comments:
// Use a double-slash for comments on a single line
/*
Use slash-asterisk and asterisk-slash for larger block comments.
These comments MAY take up multiple lines.
*/
The ANTLR implementation referenced in the Appendix discards comments, however, implementations MAY use approaches that process comments.
The primitive datatypes and value formats in FSH are those defined in the version of FHIR associated with the FSH project. References in this document to code, id, oid, etc. refer to the primitive datatypes in the referred FHIR version.
FSH strings follow the same rules and support the same content as the FHIR string datatype, including the following special escape sequences: \r (unicode U+000D), \n (U+000A), and \t (U+0009). Strings MUST be delimited by non-directional (neutral) quotes (U+0022). Left and right directional quotes (U+201C and U+201D) sometimes automatically inserted by "smart" text editors SHALL NOT be accepted. Left and right directional single quotes (U+2018 and U+2019) SHALL NOT be accepted in contexts requiring a single quotation mark; the non-directional apostrophe (U+0027) MUST be used instead.
FHIR elements can contain references to other Resources. FSH represents references using the syntax Reference({Resource/Profile})
. A resource or profile SHALL be identifiable by name, id, or URL. For example, Reference(USCorePatientProfile)
, Reference(us-core-patient)
, and Reference(http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient)
all are valid references to the US Core Patient profile. When referring to a Reference element, the Reference()
MUST be included, except in the case of a reference choice path. When syntax allows for a FSH Reference with multiple targets, the items MUST be separated by or
placed inside the parentheses, e.g. Reference(Patient or Practitioner)
, not Reference(Patient) or Reference(Practitioner)
.
In constructing profiles, references typically refer to resource or profile types, for example, the subject of an Observation could be constrained to Reference(Patient or Group)
. Inside instances, references typically refer to other instances, for example, a subject of an Observation could be Reference(JaneDoe)
, assuming JaneDoe is the id of a Patient instance. In this case, since JaneDoe
is a Patient instance, Reference(JaneDoe)
is resolved to Patient/JaneDoe
. If a reference value in an instance does not reference a known instance, implementations MUST use the value directly. For example, if the subject of an Observation is Reference(Alice)
, and Alice is not the name, id, or URL of a known Patient instance, the reference resolves to Alice
.
FHIR elements can reference other resources by their canonical URL. A canonical reference refers to the standard URL associated with a FHIR item. For elements that require a canonical datatype, FSH accepts a URL or an expression in the form Canonical({name or id or url})
. Canonical({name or id or url})
resolves to the canonical URL of the referenced item.
For items defined in the same FSH project, implementations MUST construct the canonical URL using the FSH project's canonical URL. Canonical()
therefore enables a user to change the FSH project’s canonical URL in a single place with no changes to FSH definitions.
When syntax allows for a FSH Canonical with multiple targets, the items MUST be separated by or
placed inside the parentheses, e.g. Canonical(ActivityDefinition or PlanDefinition)
, not Canonical(ActivityDefinition) or Canonical(PlanDefinition)
.
Examples:
The canonical URL for the FHIR Yes/No/Don't Know value set, which evaluates to "http://hl7.org/fhir/ValueSet/yesnodontknow":
Canonical(yesnodontknow)
Assuming the current FSH project has a canonical URL of "http://example.org", and ExampleValueSet
is a defined value set within the FSH project with an id of example-value-set
, the following expression evaluates to "http://example.org/ValueSet/example-value-set":
Canonical(ExampleValueSet)
Adding a specific version to the argument of a Canonical expression results in the stated version appended to the canonical URL. So this:
Canonical(us-core-allergyintolerance|3.1.1)
evaluates to this: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-allergyintolerance|3.1.1"
FSH provides special syntax for expressing codes and Codings. Codes MUST be denoted with the #
sign. The FSH syntax is:
#{code}
or
#"{code}"
In general, the first syntax is sufficient. Quotes MUST be used when a code contains white space, but MAY be used in other circumstances as well.
FSH represents Codings as follows:
{CodeSystem}|{version string}#{code} "{display string}"
As indicated by orange-colored text, the version and display strings are OPTIONAL. CodeSystem
is RECOMMENDED and represents the controlled terminology the code is taken from, either by name, by id, or canonical URL. The vertical bar syntax for the version of the code system is the same approach used in the canonical datatype in FHIR. Assignment rules MAY be used to set the less-common properties of a Coding or to set properties individually.
This syntax is also used with CodeableConcepts (see Assignments with the CodeableConcept Data Type) and TU CodeableReferences (see Assignments with the CodeableReference Data Type).
Examples:
The code postal used in Address.type
:
#postal
The code <= from the Quantity Comparator value set:
#<=
A code containing white space:
#"VL 1-1, 18-65_1.2.2"
A Coding from SNOMED-CT:
http://snomed.info/sct#363346000 "Malignant neoplastic disease (disorder)"
The same Coding, assuming $SCT
has been defined as an alias for http://snomed.info/sct:
$SCT#363346000 "Malignant neoplastic disease (disorder)"
A Coding from ICD10-CM, assuming the alias $ICD
for that code system:
$ICD#C004 "Malignant neoplasm of lower lip, inner aspect"
A Coding with an explicit version specified with bar syntax:
http://hl7.org/fhir/CodeSystem/example-supplement|201801103#chol-mmol
FSH provides a shorthand that allows three aspects of a Quantity to be set simultaneously:
Quantity.value
)Quantity.system
and Quantity.code
)Quantity.unit
)The syntax is either:
{decimal} '{UCUM code}' "{display}"
or
{decimal} {CodeSystem}|{version string}#{code} "{display}"
The first shorthand syntax only applies if the units are expressed in Unified Code for Units of Measure (UCUM). When this syntax is used, implementations MUST set the code system (Quantity.system
) to the UCUM code system (http://unitsofmeasure.org). The second shorthand MAY be used when the units are not UCUM. Alternatively, the value and units MAY be assigned independently (see Assignments with the Quantity Data Type).
Examples:
Express a weight in pounds, using UCUM units, displaying "lb":
155.0 '[lb_av]' "lb"
Express the same weight in pounds, using NCI Thesaurus code for the units:
155.0 http://ncithesaurus-stage.nci.nih.gov#C48531 "Pound"
While line breaks are supported using normal strings, FSH also supports different processing for strings demarcated with three double quotation marks """
. This feature can help authors to maintain consistent indentation in FSH items. As an example, an author might use a triple-quoted string to write markdown so that the markdown is neatly indented:
* ^purpose = """
* This profile is intended to support workflows where:
* this happens; or
* that happens
* This profile is not intended to support workflows where:
* nothing happens
"""
Using a single-quoted string requires the following spacing to accomplish the same markdown formatting:
* ^purpose = "* This profile is intended to support workflows where:
* this happens; or
* that happens
* This profile is not intended to support workflows where:
* nothing happens"
The difference between these two approaches is that the latter obscures the fact that the first and fourth line are at the same indentation level, and makes it appear there are two rules because of the asterisk in the first column. The former approach allows the first line to be empty so the string is defined as a block, and allows the entire block to be indented, so visually, it does not appear a second rule is involved (because of the asterisk in the first column). Using triple-quoted strings is entirely a matter of preference.
When processing triple-quoted strings, implementations MUST follow the approach described below:
Note: To ensure consistent implementation, authors SHOULD use standard spaces or tabs as leading spaces in triple-quoted strings.
Item names SHOULD follow FHIR naming guidance. All item names MUST be between 1 and 255 characters. Item names MUST begin with an uppercase ASCII letter and contain only ASCII letters, numbers, and underscores (_
). By convention, item names SHOULD use PascalCase (also known as UpperCamelCase).
Slice names and local slice names for extensions SHOULD use lower camelCase. Slice names MUST contain only ASCII letters, numbers, underscores (_
), hyphens (-
), at signs (@
), and forward slashes (/
, used only for re-slicing). These conventions are consistent with FHIR slice naming conventions specified in eld-16, aside from disallowing square brackets ([
and ]
) since they are used by sliced array path syntax.
Alias names SHOULD begin with a dollar sign ($
) and MUST otherwise contain only ASCII letters, numbers, underscores (_
), hyphens (-
), and dots (.
). Beginning alias names with $
is a good practice, since this convention allows for additional error checking (see Defining Aliases for details).
Note: Instances have identifiers rather than names, so instance declarations SHALL follow the recommendations for Item Identifiers.
Item identifiers (ids) MUST be unique within the scope of its item type in the FSH project. For example, two Profiles with the same id cannot coexist, but it is possible to have a Profile and a ValueSet with the same id in the same FSH Project. However, to minimize potential confusion, it is best to use a unique id for every item in a FSH project. If no id is provided by a FSH author, implementations MAY create an id.
Ids MUST contain only ASCII letters, numerals, hyphens (-
), and dots (.
), with a length limit of 64 characters (per the requirements of the FHIR id datatype). By convention, ids SHOULD be lowercase with words separated by hyphens. If the item has a name, the id SHOULD be based on the item's name, with _
replaced by -
, changed to lowercase, and truncated if necessary.
FSH allows internal and external items to be referred to by name, id, or canonical URL.
A FSH item within the same project SHOULD be referred to by the name or id given in the item's declaration statement. Core FHIR resources SHOULD be referred to by name, e.g., Patient
or Observation
. Items from external IGs and extensions, profiles, code systems, and value sets in core FHIR SHOULD be referred to by their canonical URLs, since this approach minimizes the chance of name collisions. In cases where an external name or id clashes with an internal name or id, then the internal item SHALL take precedence, and the external item MUST be referred to by its canonical URL.
FSH path grammar allows you to refer to any element of a profile, extension, or instance, regardless of nesting. Here are examples of things paths can refer to:
code
element of an Observationtext
element of the method
element of an Observationname
array of a Patient resourceonsetAge
in onset[x]
systolicBP
component slice in a blood pressure Observationexperimental
and active
elements of a StructureDefinition.maxLength
property of string elementsNote: While FSH paths often resemble other path syntaxes used in FHIR (e.g., FHIRPath,
ElementDefinition.id
,ElementDefinition.path
), they cannot be used in place of these. Attempts to use FSH paths within FHIRPath strings or as Element ids will lead to invalid FHIR output.
In the following, the various types of path references are discussed. Some examples are presented using simple rules. For rule syntax and meaning, see FSH Rules.
The path to a top-level element SHALL be denoted by the element's name. Because paths are used within the context of a FSH definition or instance, the path MUST NOT include the resource name. For example, when defining a profile of Observation, the path to Observation.code
is just code
.
Example:
The path to the status of a MedicationRequest:
status
To refer to nested elements, the path SHALL list the properties in order, separated by a dot (.
). Since the resource can be inferred from the context, the resource name MUST NOT be included in the path.
Examples:
The path to the lot number of a Medication:
batch.lotNumber
The path to the plain text representation of the site of a MedicationAdministration:
dosage.site.text
Elements can offer a choice of reference types. In the FHIR specification, these choices are presented in the style Reference(Procedure | Observation). To address a specific resource or profile among the choices, the target Resource or Profile (represented by a name, id, or url) SHALL be enclosed in square brackets and appended to the end of the path after the reference element (and slice name, if applicable).
Note: It is not permissible to cross reference boundaries in paths. This means that when a path gets to a Reference, that path cannot be extended further. For example, if Procedure has a
subject
element that has datatype Reference(Patient), and Patient has agender
, thensubject
is a valid path, butsubject.gender
is not, because it crosses into the Patient resource.
Examples:
Path to the Reference(Practitioner) option of DiagnosticReport.performer, whose acceptable datatypes are Reference(Practitioner), Reference(PractitionerRole), Reference(Organization) or Reference(CareTeam):
performer[Practitioner]
Path to the Reference(US Core Organization) option of the performer
element in US Core DiagnosticReport Lab, using the canonical URL:
performer[http://hl7.org/fhir/us/core/StructureDefinition/us-core-organization]
The same path, using the id of the US Core Organization profile instead of its canonical URL:
performer[us-core-organization]
FHIR represents an element with a choice of datatypes using the style foo[x]
. For example, Condition.onset[x]
can be a dateTime, Age, Period, Range or string. In FSH, as in FHIR, to refer to one of these datatypes, the [x]
SHALL be replaced by the datatype name, capitalizing the first letter. For Condition.onset[x]
, the individual choices are onsetDateTime
, onsetAge
, onsetPeriod
, onsetRange
, and onsetString
.
Note:
foo[x]
choices are NOT represented asfoo[dateTime]
,foo[Period]
, etc.
Examples:
The path to the string datatype of Observation.value[x]
:
valueString
The path to the Reference datatype choice of Medication.ingredient.item[x]
:
ingredient.itemReference
Given that the itemReference has further choices Reference(Substance) or Reference(Medication), the path to the Reference(Substance) choice:
ingredient.itemReference[Substance]
FSH paths SHALL use square-bracketed integers to address elements in arrays. Arrays SHALL be referenced using 0-based indices, meaning that the first array element is referenced by [0]
, the second element is referenced by [1]
, etc. Arrays with missing elements (gaps in the sequence of indices) SHALL NOT be allowed. If the index is omitted, the first element of the array ([0]
) SHALL be assumed.
Numerical indices apply only to arrays that can be populated with concrete values, e.g., in instances or in metadata elements of StructureDefinitions. For this reason, numerical indices MUST NOT be used in Profiles except when using caret paths to set metadata properties of StructureDefinitions . Authors SHOULD use slicing and sliced array paths to constrain specific array elements in Profiles.
Examples:
Path to first element in Patient.name
field within an instance of Patient:
name[0]
Path to a patient's second given
name in the first name
field within an instance of Patient:
name[0].given[1]
An equivalent path expression, since the zero index is assumed when omitted:
name.given[1]
Numerical array references MAY be replaced with "soft indexing." In soft indexing, [+]
SHALL be used to increment the last referenced index by 1, and [=]
SHALL be used to reference the same index that was last referenced. When an array is empty, [+]
SHALL refer to the first element ([0]
). Authors MAY mix the use of soft and numerical indices.
Similar to numerical indices, soft indices SHALL only be used when populating or referencing arrays in instances and invariants, or when using caret paths.
Soft indexing is useful when populating long arrays, allowing elements to be inserted, deleted, or moved without updating numerical indices. Complex resources such as Bundle and CapabilityStatement have arrays that may contain scores of items. Managing indices can become tedious and error prone when adding or removing items in the middle of a long list.
Another use case for soft indexing involves rule sets. Rule sets provide a way to avoid repeating the same pattern of rules when populating an array (see example).
For nested arrays, several sequences of soft indices MAY run simultaneously. The sequence of indices at different levels of nesting SHALL be independent and SHALL NOT interact with one another. However, when arrays are nested, incrementing the index of the parent (outer) array advances to the next child (inner) array, so the next child element referred to by [+]
SHALL be at index 0. (An analogy is using a keyboard's Enter key to advance to a new line that initially has no characters.)
Examples:
Assign multiple names in an instance of a Patient using soft indices:
* name[+].given = "Robert"
* name[=].family = "Smith"
* name[+].given = "Rob"
* name[=].family = "Smith"
* name[+].given = "Bob"
* name[=].family = "Smith"
is equivalent to:
* name[0].given = "Robert"
* name[0].family = "Smith"
* name[1].given = "Rob"
* name[1].family = "Smith"
* name[2].given = "Bob"
* name[2].family = "Smith"
Add second given name to the example above, using soft indexing:
* name[+].given[+] = "Robert"
* name[=].given[+] = "David"
* name[=].family = "Smith"
* name[+].given[+] = "Rob"
* name[=].given[+] = "Dave"
* name[=].family = "Smith"
* name[+].given[+] = "Bob"
* name[=].given[+] = "Davey"
* name[=].family = "Smith"
is equivalent to:
* name[0].given[0] = "Robert"
* name[0].given[1] = "David"
* name[0].family = "Smith"
* name[1].given[0] = "Rob"
* name[1].given[1] = "Dave"
* name[1].family = "Smith"
* name[2].given[0] = "Bob"
* name[2].given[1] = "Davey"
* name[2].family = "Smith"
FHIR allows lists in profiles and extensions to be compartmentalized into sublists called "slices". To address a specific slice, the slice name SHALL be enclosed in square brackets and appended after the sliced element in the path. Since slices are most often unordered, slice names rather than array indices SHOULD be used in instances. Note that slice names (like other FSH item names) SHALL NOT be purely numerical, so slice names cannot be confused with indices.
To access a slice of a slice (a resliced array), the first pair of brackets containing the base slice name SHALL be followed by a second pair of brackets containing the resliced slice name.
When a list of references is sliced, and a given slice refers to multiple targets, sliced array paths MAY be combined with reference paths by specifying the slice name in brackets first, followed by the target reference type in brackets.
Since slices are sublists, a sliced array path technically points to the first item in the sublist (e.g., index 0 of the slice's sublist). Other items in the sublist MAY be accessed by appending square-bracketed integer indices (e.g., [1]
) or soft indices (e.g., [+]
) to the end of the sliced array path. In this case, indices are relative to the first item in the slice.
Examples:
Path to the coded value of the respirationScore
component slice within an Observation profile representing an Apgar test:
component[respirationScore].code
Paths to the codes representing the one minute and five minute respiration scores, assuming the Apgar respirationScore
component slice has been resliced:
component[respirationScore][oneMinuteScore].code
component[respirationScore][fiveMinuteScore].code
Paths to the MedicationRequest and NutritionOrder reference options in an orders
slice that allows both types:
basedOn[orders][MedicationRequest]
basedOn[orders][NutritionOrder]
Paths to the resources of the second and third entries in the medications
slice of a profiled Bundle:
entry[medications][1].resource
entry[medications][+].resource
Extension arrays are found at the root level of every resource, nested inside every element, and recursively inside each extension. Extensions are elements in these arrays. When an extension is specified in an extension array within a profile or extension definition, a name (technically, a slice name) is assigned. Extensions MAY be identified by slice name or the extension's URL.
The path to an extension SHALL consist of a path to an extension array followed by a pair of square brackets enclosing the extension's slice name or canonical URL:
<Extension>[{name or id or URL}]
Since an extension array in an instance can contain multiple extensions of the same type, additional instances of the extension MAY be accessed using a square-bracketed index:
<Extension>[{name or id or URL}][{index}]
For locally-defined extensions, using the slice name is the simplest choice. For externally-defined extensions, the canonical URL can be easier to find than the slice name.
Note: The same path construction SHALL apply to modifierExtension arrays; simply replace
extension
withmodifierExtension
.
Examples:
Path to the value of the birth sex extension in US Core Patient, whose local slice name is birthsex
:
extension[birthsex].valueCode
Path to an extension on the telecom
element of Patient, assuming the extension has been given the local slice name directMailAddress
:
telecom.extension[directMailAddress]
Same as the previous example, but using the canonical URL for the direct mail extension defined in US Core:
telecom.extension[http://hl7.org/fhir/us/core/StructureDefinition/us-core-direct]
Path to the Coding datatype of the value[x]
in the nested extension ombCategory
under the ethnicity
extension in US Core, using the slice names of the extensions:
extension[ethnicity].extension[ombCategory].valueCoding
Path to the Coding value in second element in the nested extension array named detailed, under the US Core Ethnicity extension:
extension[ethnicity].extension[detailed][1].valueCoding
The FSH syntax provides a level of abstraction over FHIR resources. When authors define a Profile, Extension, Logical, or Resource using FSH, they are creating and modifying an instance of an underlying FHIR StructureDefinition. Similarly, when authors define a CodeSystem or ValueSet, they are creating and modifying an instance of a FHIR CodeSystem or FHIR ValueSet. While the basic FSH syntax maps to the core aspects of each of these FHIR definitional resources, it does not provide a complete mapping to every possible element within them.
In order to address this gap, FSH authors MAY use the caret (^
) symbol to access elements of definitional resources corresponding to the current item in context. Caret paths SHALL be accepted in FSH Profiles, Extensions, Logicals, and Resources to address elements in the underlying FHIR StructureDefinition resource; in FSH Invariants to address elements in the underlying ElementDefinition.constraint
; in FSH ValueSets to address elements in the underlying FHIR ValueSet resource; in FSH CodeSystems to address elements in the underlying FHIR CodeSystem resource; and in FSH RuleSets, as long as the RuleSet is inserted in an item that allows caret paths. Caret paths SHALL NOT be used with any other FSH item definition, including Instances, since Instances already directly manipulate FHIR resources. In addition, caret syntax SHALL NOT be used with the following paths, because the order of elements in these paths MAY vary between implementations:
snapshot.element
and differential.element
in Profile, Extension, Logical, and Resource itemscompose.include
and compose.exclude
in ValueSet itemsExamples of elements that require the caret syntax include StructureDefinition.experimental
, StructureDefinition.abstract
and ValueSet.purpose
. The caret syntax also provides a simple way to set metadata attributes in the ElementDefinitions that comprise the snapshot and differential tables (e.g., short
, meaningWhenMissing
, and various slicing discriminator properties).
For a path to an element of a StructureDefinition, excluding the differential and snapshot, use the following syntax inside a Profile, Extension, Logical, or Resource:
^<element of StructureDefinition>
For a path to an element of an ElementDefinition within a StructureDefinition, use this syntax:
<element in Profile> ^<element of corresponding ElementDefinition>
Note: When using caret paths to access metadata of element definitions, there is a REQUIRED space before the ^
character.
A special case of the ElementDefinition path is setting properties of the first element of the differential (i.e., StructureDefinition.differential.element[0]
). This element always refers to the profile or standalone extension itself. Since this element does not correspond to a named element appearing in an instance, the dot or full stop (.
) SHALL be used to represent it. (The dot symbol is often used to represent "current context" in other languages.) It is important to note that the "self" elements are not the elements of a StructureDefinition directly, but elements of the first ElementDefinition contained in the StructureDefinition. The syntax is:
. ^<element of StructureDefinition.differential[0]>
Examples:
In a profile definition, path to the corresponding StructureDefinition.experimental
attribute:
^experimental
In a profile of Patient, the path to binding.description
in the ElementDefinition corresponding to communication.language
:
communication.language ^binding.description
The path to the short description of an extension (defined in the first ElementDefinition):
. ^short
A central purpose of FSH is to create and define items that represent and can be translated into FHIR artifacts. The general pattern used to define an item in FSH is:
While every FSH item requires a declaration, depending on the item type, keyword statements and rules may not be required, or even permitted.
Declaration statements follow the syntax:
{declaration}: {value}
A declaration is always the first statement in an item definition. The value represents the item's name or identifier (id), depending on the item's type, as shown in the table below:
Declaration | Creates… | Data Type |
---|---|---|
Alias | An alias for a URL or OID | expression |
CodeSystem | A code system | name |
Extension | An extension | name |
Instance | An instance | id |
Invariant | An invariant | id |
Logical | A logical model | name |
Mapping | A mapping | id |
Profile | A profile | name |
Resource | A custom resource | name |
RuleSet | A set of rules that can be reused | name |
ValueSet | A value set | name |
Keyword statements directly follow the declaration and precede any rules. Keyword statements follow the syntax:
{keyword}: {value}
The following keywords (case-sensitive) are defined:
Keyword | Purpose | Data Type |
---|---|---|
Characteristics TU | Specifies characteristics for logical models | codes |
Context TU | Specifies context for extensions | FHIRPath strings and element paths |
Description | Provides a human-readable description | string or markdown |
Expression | Provides a FHIR path expression in an invariant | FHIRPath string |
Id | Provides an identifier for an item | id |
InstanceOf | Names the profile, resource, or logical model* an instance instantiates | name or id or url |
Parent | Names the base definition for a profile or extension | name or id or url |
Severity | Specifies whether violation of an invariant represents an error or a warning | code |
Source | Provides the profile the mapping applies to | name |
Target | Provides the standard being mapped to | uri |
Title | Provides a short human-readable name | string |
Usage | Specifies how an instance is intended to be used in the IG | code |
XPath | Provides the XPath in an invariant | XPath string |
* Defining instances of logical models in FSH is TU.
In the above, "name" refers to a valid item name and "id" to an item identifier.
Depending on the type of item being defined, keywords may be REQUIRED, suggested (SHOULD be used), OPTIONAL, or prohibited (MUST NOT be used). The following table shows the relationship between declarations and keywords:
Keyword → Declaration ↓ |
Id | Description | Title | Parent | InstanceOf | Usage | Source | Target | Severity | Expression | XPath | Context TU | Characteristics TU |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Alias | |||||||||||||
Code System | S | S | S | ||||||||||
Extension | S | S | S | O | S | ||||||||
Instance | S | S | R | O | |||||||||
Invariant | S1 | O2 | O | O | |||||||||
Logical | S | S | S | O | O | ||||||||
Mapping | S | S | S | R | R | ||||||||
Profile | S | S | S | R | |||||||||
Resource | S | S | S | O | |||||||||
Rule Set | |||||||||||||
Value Set | S | S | S |
KEY: R = REQUIRED, S = suggested (SHOULD be used), O = OPTIONAL, blank = prohibited (MUST NOT be used)
TU 1 If the Description
keyword is not specified in an Invariant
definition, then an assignment rule for the human
element MUST be specified instead.
TU 2 If the Severity
keyword is not specified in an Invariant
definition, then an assignment rule for the severity
element MUST be specified instead.
For additional information about the use of these keywords, consult the documentation pertaining to the specific item(s) to which they apply.
A number of rules usually follow the keyword statements. The grammar and meaning of different rule types are discussed in the FSH Rules section. Without defining the rule types here, the following table shows the applicability of rule types to item types:
Item → Rule Type ↓ |
Alias | Code System | Extension | Instance | Invariant | Logical | Mapping | Profile | Resource | Rule Set | Value Set |
---|---|---|---|---|---|---|---|---|---|---|---|
Add Element | Y | Y | Y | ||||||||
Assignment | C | Y | Y | TU Y | TU Y | Y | C | Y | C | ||
Binding | Y | TU Y | Y | A | Y | ||||||
Cardinality | Y | TU Y | Y | A | Y | ||||||
Contains (inline extensions) | Y | Y | |||||||||
Contains (standalone extensions) | Y | Y | Y | ||||||||
Contains (slicing) | Y | Y | Y | ||||||||
Exclude | Y | Y | |||||||||
Flag | Y | L | Y | L | Y | ||||||
Include | Y | Y | |||||||||
Insert | Y | Y | Y | TU Y | Y | Y | Y | Y | Y | Y | |
Local Code | Y | Y | |||||||||
Mapping | Y | Y | |||||||||
Obeys | Y | Y | Y | Y | Y | ||||||
Path | Y | Y | TU Y | Y | Y | Y | Y | Y | |||
Type | Y | TU Y | Y | A | Y |
KEY: Y = Rule type MAY be used, L = All flags except must support (MS
) are supported, C = Assignments apply only to caret paths, A = Rules can only be applied to elements defined by the item (not inherited elements), blank = prohibited.
Aliases MAY be used to replace a lengthy url, oid, or uuid with a short string. Aliases are for readability only, and SHALL NOT change the meaning of rules. Typical uses of aliases are to represent code systems and canonical URLs.
Alias definitions follow this syntax:
Alias: {Alias name} = {url or urn:oid or urn:uuid}
Several things to note about aliases:
urn:oid
or urn:uuid
schemes.In contrast with other names in FSH (for profiles, extensions, etc.), alias names MAY optionally begin with a dollar sign ($
). If you define an alias with a leading $
, implementations can more easily check for misspellings. For example, if you choose the alias name $RaceAndEthnicity
and accidentally type $RaceEthnicity
, implementations can easily detect there is no alias by that name. Without the $
sign, implementations are forced to look through FHIR Core and all external implementation guides for anything with that name or id, or in some contexts, assume it is a new item, with unpredictable results.
Examples:
Alias: $SCT = http://snomed.info/sct
Alias: $RaceAndEthnicityCDC = urn:oid:2.16.840.1.113883.6.238
Alias: obs-cat = http://terminology.hl7.org/CodeSystem/observation-category
It is sometimes necessary to define new codes inside an IG that are not drawn from an external code system (aka local codes). Local codes MUST be defined in the context of a code system.
Note: Defining local codes is not best practice, since those codes will not be part of recognized terminology systems. However, when existing vocabularies do not contain necessary codes, it might be necessary to define them – at least temporarily – as local codes.
Creating a code system uses the REQUIRED declaration CodeSystem
and RECOMMENDED keywords Id
, Title
and Description
. Code system metadata that does not have a dedicated keyword MAY be specified using assignment rules with caret paths (e.g., ^url
, ^status
, ^purpose
). Codes SHOULD then be added, one per rule, using the following syntax:
* #{code} "{display string}" "{definition string}"
Rule types that apply to CodeSystems are: Assignment, Insert, and Local Code. Assignment rules SHALL be applicable to code systems only in the context of caret paths.
Notes:
#
. The code system name is given by the CodeSystem
declaration.include
in a code system rule. The rule is creating a brand new code, not including an existing code defined elsewhere.designation
, MAY be defined using caret paths.Example:
Define a code system for yoga poses:
CodeSystem: YogaCS
Id: yoga-code-system
Title: "Yoga Code System"
Description: "A brief vocabulary of yoga-related terms."
// url, status, purpose, and other metadata could be defined here using caret syntax (omitted)
* #Sirsasana "Headstand"
"An pose that involves standing on one's head."
* #Halasana "Plough Pose"
"A pose from supine position, bringing legs up and over until the toes touch the ground behind the head."
* #Matsyasana "Fish Pose"
"A pose from supine position, arching the back and pressing the chest upwards."
* #Bhujangasana "Cobra Pose"
"A pose starting from prone position with hands pushing the shoulders upward, with legs and hips remaining on the ground."
Child codes MAY also be defined, resulting in a hierarchical structure of codes within a code system. To define such codes, authors MUST list all of the preceding codes in the hierarchy before the new code or use indented child codes. To list the preceding codes in the hierarchy, use the following syntax:
* #{parent code} "{display string}" "{definition string}"
* #{parent code} #{child code} "{display string}" "{definition string}"
To specify hierarchy using indentation, indent (by two spaces per level) child code definitions after their parent's code definition:
* #{parent code} "{display string}" "{definition string}"
* #{child code} "{display string}" "{definition string}"
Additional levels to any depth SHALL be added in the same manner.
Note: When defining hierarchical codes, parent codes MUST be defined before their children.
Examples:
CodeSystem: AnteaterCS
Id: anteater-code-system
Title: "Anteater Code System"
Description: "A code system for anteater taxonomy with hierarchical codes"
* #Anteater "Anteater" "Members of suborder Vermilingua, distinguished by its propensity to eat ants"
* #Anteater #Tamandua "Members of genus Tamandua" "The Tamandua genus of anteaters, mainly found in forests and grasslands"
* #Anteater #Tamandua #NorthernTamandua "Northern Tamandua" "The northern species of Tamandua anteaters"
* #Anteater #Tamandua #SouthernTamandua "Southern Tamandua" "The southern species of Tamandua anteaters"
* #Anteater #GiantAnteater "Giant Anteater" "The Giant Anteater, typically 6 - 7 feet in length"
CodeSystem: AnteaterCS
Id: anteater-code-system
Title: "Anteater Code System"
Description: "A code system for anteater taxonomy with hierarchical codes"
* #Anteater "Anteater" "Members of suborder Vermilingua, distinguished by its propensity to eat ants"
* #Tamandua "Members of genus Tamandua" "The Tamandua genus of anteaters, mainly found in forests and grasslands"
* #NorthernTamandua "Northern Tamandua" "The northern species of Tamandua anteaters"
* #SouthernTamandua "Southern Tamandua" "The southern species of Tamandua anteaters"
* #GiantAnteater "Giant Anteater" "The Giant Anteater, typically 6 - 7 feet in length"
Within a CodeSystem definition, the caret syntax MAY be used to set metadata attributes for individual concepts (e.g., elements of CodeSystem.concept.designation
and CodeSystem.concept.property
).
For a path to a code within a code system, use this syntax:
#{code} ^<element of corresponding concept>
Examples:
To set the designation.use
of the code #active
:
* #active ^designation[0].use = $SCT#900000000000003001 "Fully specified name"
The path to the property code of #recurrence
code, a child of the #active
code:
#active #recurrence ^property[0].code
To define an extension, the declaration Extension
is REQUIRED, the keywords Id
, Title
, and Description
are RECOMMENDED, and Parent
is OPTIONAL. Extensions MAY also inherit from other extensions, but if the Parent
keyword is omitted, the parent SHALL be assumed to be FHIR's Extension element. Extension metadata that does not have a dedicated keyword MAY be specified using assignment rules with caret paths (e.g., ^url
, ^status
, ^purpose
).
An extension MAY have either a value (i.e. a value[x]
element) or sub-extensions, but MUST NOT have both. To create a simple extension, the value[x]
element SHOULD be constrained. To create a complex extension, the extension
array of the extension MUST be sliced (see Contains Rules for Extensions).
Since simple and complex extensions are mutually-exclusive, FSH implementations SHOULD set the value[x]
cardinality to 0..0 if sub-extensions are specified, set extension
cardinality to 0..0 if constraints are applied to value[x]
, and signal an error if value[x]
and sub-extensions are simultaneously specified.
To indicate that an extension is a modifier extension, authors MUST set the isModifier flag to true
on the extension's root element. In addition, the root element's isModifierReason MUST also be provided. This is in accordance with FHIR's modifier extension requirements and eld-18 invariant. FSH authors can achieve this via rules like the following:
* . ?! // alternate syntax: . ^isModifier = true
* . ^isModifierReason = "Reason for flagging as a modifier"
Rules types that apply to Extensions are: Assignment, Binding, Cardinality, Contains (standalone extensions), Contains (inline extensions), Contains (slicing), Flag, Insert, Obeys, Path, and Type.
Examples:
How the US Core BirthSex extension (a simple extension) would be defined in FSH:
Extension: USCoreBirthSexExtension
Id: us-core-birthsex
Title: "US Core Birth Sex Extension"
Description: "A code classifying the person's sex assigned at birth as specified by the [Office of the National Coordinator for Health IT (ONC)](https://www.healthit.gov/newsroom/about-onc). This extension aligns with the C-CDA Birth Sex Observation (LOINC 76689-9)."
Context: Patient
// url, status, purpose, and other metadata could be defined here using caret syntax (omitted)
* value[x] only code
* value[x] from http://hl7.org/fhir/us/core/ValueSet/birthsex (required)
Note: The use of the
Context
keyword in the example above is TU.
How the FHIR Do Not Perform modifier extension would be defined in FSH:
Extension: DoNotPerform
Id: request-doNotPerform
Title: "Do not perform"
Description: "If true indicates that the request is asking for the specified action to not occur."
Context: NutritionOrder
// url, status, purpose, and other metadata could be defined here using caret syntax (omitted)
* . 0..1 ?!
* . ^isModifierReason = "If true this element negates the specified action. For Example, instead of a request for a procedure, it is a request for the procedure to not occur."
* value[x] 1..
* value[x] only boolean
Note: The use of the
Context
keyword in the example above is TU.
How US Core Ethnicity extension (a complex extension with inline sub-extensions) would be defined in FSH:
Extension: USCoreEthnicityExtension
Id: us-core-ethnicity
Title: "US Core Ethnicity Extension"
Description: "Concepts classifying the person into a named category of humans sharing common history, traits, geographical origin or nationality. The ethnicity codes used to represent these concepts are based upon the [CDC ethnicity and Ethnicity Code Set Version 1.0](http://www.cdc.gov/phin/resources/vocabulary/index.html) which includes over 900 concepts for representing race and ethnicity of which 43 reference ethnicity. The ethnicity concepts are grouped by and pre-mapped to the 2 OMB ethnicity categories: - Hispanic or Latino - Not Hispanic or Latino."
Context: Patient, RelatedPerson, Person, Practitioner, FamilyMemberHistory
// url, status, purpose, and other metadata could be defined here using caret syntax (omitted)
* extension contains
ombCategory 0..1 MS and
detailed 0..* and
text 1..1 MS
* extension[ombCategory] ^short = "Hispanic or Latino|Not Hispanic or Latino"
* extension[ombCategory].value[x] only Coding
* extension[ombCategory].value[x] from OmbEthnicityCategories (required) // OmbEthnicityCategories is a value set defined by US Core
* extension[detailed] ^short = "Extended ethnicity codes"
* extension[detailed].value[x] only Coding
* extension[detailed].value[x] from DetailedEthnicity (required) // DetailedEthnicity is defined in US Core
* extension[text] ^short = "Ethnicity text"
* extension[text].value[x] only string
Note: The use of the
Context
keyword in the example above is TU.
Define an extension with an explicit parent, constraining the US Core Birth Sex extension for US states that do not recognize non-binary birth sex:
Extension: BinaryBirthSexExtension
Parent: USCoreBirthSexExtension
Id: binary-birthsex
Title: "Binary Birth Sex Extension"
Description: "As of 2019, certain US states only allow M or F on birth certificates."
* value[x] from BinaryBirthSexValueSet (required)
TU
The keyword Context
SHOULD be used to specify the context of an Extension. When specifying a fhirpath
context, the value MUST be a quoted string. When specifying an element
or extension
context, the value MUST start with the name, id, or URL of the context item. A name or id MAY be followed by a dot (.
) and a valid FSH path. A URL MAY be followed by a hash sign (#
) and a valid FSH path.
Multiple contexts MAY be specified by using a comma-separated list. Using the Context
keyword instead of using caret rules to assign directly to the context
list on the Extension is RECOMMENDED. The following is a list of allowed formats for contexts:
Specifying a fhirpath
context:
Context: "{fhirpath expression}"
Specifying an element
or extension
context using a StructureDefinition's name or id:
Context: {StructureDefinition name or id}.{FSH path}
Specifying an element
or extension
context for using a StructureDefinition's URL:
Context: {StructureDefinition url}#{FSH path}
An alias MAY be used in place of the URL.
Specifying multiple contexts as a comma-separated list:
Context: {context 1}, {context 2}, {context 3}...
Examples:
Defining an extension with a fhirpath
context
Extension: MyExtension
Context: "(Condition | Observation).code"
Defining an extension with an element
context on a core FHIR resource
Extension: MyExtension
Context: Patient
Defining an extension with an element
context on a specific element in a core FHIR resource
Extension: MyExtension
Context: Patient.contact.telecom
Defining an extension with an element
context on a specific element in a Profile defined in FSH
Profile: MyPatient
Parent: Patient
// rules on the Profile omitted
Extension: MyExtension
Context: MyPatient.contact.telecom
Defining an extension with an element
context that references an element whose path includes a slice. Note that the path uses square brackets to refer to a slice.
Extension: MyExtension
Context: USCoreCarePlanProfile.category[AssessPlan].coding
// You can also use the id or the URL
// Context: us-core-careplan.category[AssessPlan].coding
// Context: http://hl7.org/fhir/us/core/StructureDefinition/us-core-careplan#category[AssessPlan].coding
Defining an extension with an extension
context
Extension: MyExtension
Context: http://hl7.org/fhir/StructureDefinition/capabilitystatement-search-parameter-combination
// The extension could also be referenced by name or id:
// Context: CSSearchParameterCombination
// Context: capabilitystatement-search-parameter-combination
Defining an extension with an extension
context that is part of a complex extension, referencing the extension by name or id
Extension: MyExtension
Context: CSSearchParameterCombination.extension[required]
// Using the id also works:
// Context: capabilitystatement-search-parameter-combination.extension[required]
Defining an extension with an extension
context that is part of a complex extension, referencing the extension by url
Extension: MyExtension
Context: http://hl7.org/fhir/StructureDefinition/capabilitystatement-search-parameter-combination#extension[required]
Defining an extension with an extension
context by using an alias:
Alias: $COMBINATION = http://hl7.org/fhir/StructureDefinition/capabilitystatement-search-parameter-combination
Extension: MyExtension
Context: $COMBINATION#extension[required]
Defining multiple contexts and using an alias:
Alias: $COMBINATION = http://hl7.org/fhir/StructureDefinition/capabilitystatement-search-parameter-combination
Extension: MyExtension
Context: $COMBINATION#extension[required], $COMBINATION#extension[optional], "(Condition | Observation).code"
Instances are defined using the REQUIRED declaration Instance
, with the REQUIRED keyword InstanceOf
, RECOMMENDED keywords Title
and Description
, and OPTIONAL keyword Usage
. InstanceOf
plays a role analogous to the Parent
of a profile. The value of InstanceOf
MUST be the name, id, or url for any profile, resource, TU logical model, or complex datatype defined internally or externally.
The Usage
keyword specifies how the instance should be presented in the IG:
Usage: #example
(default) means the instance is intended as an illustration of a profile or TU logical model, and SHOULD be presented as an example for the corresponding entity.Usage: #definition
means the instance is a formal item (i.e., not an example) in the IG, such as an instance of a search parameter, operation definition, or questionnaire. These items SHOULD be presented on their own IG page.Usage: #inline
means the instance MUST NOT be instantiated as an independent resource, but MAY appear as part of another instance (for example, in any DomainResource in the contained
array, or in a Bundle in the entry.resource
array).Instances inherit assigned values from their StructureDefinition (i.e. assigned codes, assigned booleans) if those values are required. Assignment rules are used to set additional values.
Rule types that apply to Instances are: Assignment, Insert, and Path. No other rule types are allowed.
Examples:
Define an example instance of US Core Patient, with name, date of birth, race, and ethnicity:
Instance: EveAnyperson
InstanceOf: http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient
Title: "Eve Anyperson"
Usage: #example
* name.given = "Eve"
* name.family = "Anyperson"
* birthDate = 1960-04-25
* extension[us-core-race].extension[ombCategory].valueCoding = RaceAndEthnicityCDC#2106-3 "White"
* extension[us-core-ethnicity].extension[ombCategory].valueCoding = RaceAndEthnicityCDC#2186-5 "Non Hispanic or Latino"
Define an instance of US Core Practitioner, with name and NPI, meant to be inlined in a composition:
Instance: DrDavidAnydoc
InstanceOf: http://hl7.org/fhir/us/core/StructureDefinition/us-core-practitioner
Usage: #inline
* name.family = "Anydoc"
* name.given = "David"
* name.suffix = "MD"
* identifier[NPI].value = "8274017284"
This instance would be incorporated into a DomainResource with a statement such as:
* contained[0] = DrDavidAnydoc
Define an #inline
Patient instance, and then use that instance in a Condition resource, inlining it as a contained resource:
Instance: EveAnyperson
InstanceOf: Patient
Usage: #inline // #inline means this instance MUST NOT be exported as a separate example
* name.given[0] = "Eve"
* name.family = "Anyperson"
Instance: EvesCondition
InstanceOf: Condition
Usage: #example
Description: "An example that uses contained"
* contained[0] = EveAnyperson // this inlines EveAnyperson definition here
* code = http://foo.org#bar
* subject = Reference(EveAnyperson) // this automatically creates the relative reference correctly
This results in:
{
"resourceType": "Condition",
"id": "EvesCondition",
"contained": [
{
"resourceType": "Patient",
"id": "EveAnyperson",
"name": [
{
"given": [
"Eve"
],
"family": "Anyperson"
}
]
}
],
"code": {
"coding": [
{
"code": "bar",
"system": "http://foo.org"
}
]
},
"subject": {
"reference": "#EveAnyperson"
}
}
Define an instance of PrimaryCancerCondition, using many available features:
Instance: mCODEPrimaryCancerConditionExample01
InstanceOf: PrimaryCancerCondition
Description: "mCODE Example for Primary Cancer Condition"
Usage: #example
* id = "mCODEPrimaryCancerConditionExample01"
* clinicalStatus = $ClinStatus#active "Active"
* verificationStatus = $VerStatus#confirmed "Confirmed"
* code = $SCT#254637007 "Non-small cell lung cancer (disorder)"
* extension[HistologyMorphologyBehavior].valueCodeableConcept = $SCT#35917007 "Adenocarcinoma"
* bodySite = $SCT#39607008 "Lung structure (body structure)"
* bodySite.extension[Laterality].valueCodeableConcept = $SCT#7771000 "Left (qualifier value)"
* subject = Reference(mCODEPatientExample01)
* onsetDateTime = "2019-04-01"
* asserter = Reference(mCODEPractitionerExample01)
* stage.summary = $AJCC#3C "IIIC"
* stage.assessment = Reference(mCODETNMClinicalStageGroupExample01)
The FSH language is designed to support creation of StructureDefinitions for Profiles, Extensions, Resources, and Logicals; ValueSets; and CodeSystems. FSH implementations MAY additionally create an IG's ImplementationGuide resource based on project-specific configuration data and other information. There are other conformance resources involved with IG creation, however, that are not explicitly supported by specific FSH item types. These include CapabilityStatement, OperationDefinition, SearchParameter, and CompartmentDefinition.
These conformance resources MAY be created using FSH instance grammar. For example, to create a CapabilityStatement, use InstanceOf: CapabilityStatement
with Usage: #definition
. The CapabilityStatement is populated using assignment statements. Authors may choose to use parameterized rule sets to reduce repetition of common patterns in conformance resources.
Invariants are defined using the REQUIRED declaration Invariant
, RECOMMENDED keyword Description
1, and OPTIONAL keywords Severity
2, XPath
(FHIR R4 only) and Expression
. The keywords correspond directly to elements in ElementDefinition.constraint
, as shown in the table below. Invariants are incorporated into profiles, extensions, logical models, or resources via obeys rules.
Keyword | Usage | Corresponding element in ElementDefinition.constraint |
Data Type | Required |
---|---|---|---|---|
Invariant | Identifier for the invariant | key | id | yes |
Description | Human description of constraint | human | string | no1 |
Expression | FHIRPath expression of constraint | expression | FHIRPath string | no |
Severity | Either #error or #warning, as defined in ConstraintSeverity | severity | code | no2 |
XPath | XPath expression of constraint (Note: FHIR R5 no longer supports XPath) | xpath | XPath string | no |
TU
Rule types that apply to defining Invariants are: Assignment, Path, and Insert. Paths in Invariant assignment rules refer to elements within ElementDefinition.constraint
(e.g., severity
refers to ElementDefinition.constraint.severity
). Assignment rules are particularly useful for specifying constraint extensions such as the Best Practice extension.
1 If the Description
keyword is not specified, then the definition MUST contain an assignment rule for the human
element.
2 If the Severity
keyword is not specified, then the definition MUST contain an assignment rule for the severity
element.
Example:
Define a simplified version of an invariant found in US Core (for FHIR R4) using FSH Invariant keywords only:
Invariant: us-core-6
Description: "Patient.name.given or Patient.name.family or both SHALL be present"
Severity: #error
Expression: "family.exists() or given.exists()"
XPath: "f:given or f:family"
TU
Define a simplified version of an invariant found in US Core (for FHIR R4) using FSH Invariant keywords and rules:
Invariant: us-core-6
Description: "Patient.name.given or Patient.name.family or both SHALL be present"
* severity = #error
* expression = "family.exists() or given.exists()"
* xpath = "f:given or f:family"
Logical models allow authors to define new structures representing arbitrary content. While profiles can only add new properties as formal extensions, logical models add properties as standard elements with standard paths. Logical models have many uses, as described in the FHIR specification, but are often used to convey domain-specific concepts in a user-friendly manner. Authors often use logical models as a basis for defining formal profiles in FHIR.
Logical models are defined using the REQUIRED declaration Logical
, with RECOMMENDED keywords Id
, Title
, and Description
, and OPTIONAL keyword Parent
. If no Parent
is specified, the empty Base type SHALL be assumed as the default parent. Note that the Base type does not exist in FHIR R4, but both SUSHI and the FHIR IG Publisher have implemented special case logic to support Base in FHIR R4. Authors who wish to have top-level id
and extension
elements MAY use Element as the logical model's parent instead (when appropriate, based on the definition of Element). Alternately, authors MAY specify another logical model, a resource, or a complex datatype as a logical model's parent. Logical model metadata that does not have a dedicated keyword MAY be specified using assignment rules with caret paths (e.g., ^url
, ^status
, ^purpose
).
Rules defining the logical model follow immediately after the keyword section. Rule types that apply to Logicals are: Add Element, Assignment, Binding, Cardinality, Flag, Insert, Obeys, Path, and Type. Flag rules SHALL NOT include MS
flags.
In addition, authors SHOULD consult FHIR's interpretation of ElementDefinition for type definitions. Assignments MUST NOT set elements listed as prohibited in that table. For example, the table indicates that assigning maxLength
and mustSupport
is prohibited.
Note: Prior versions of FHIR Shorthand forbid logical model definitions from constraining inherited elements or using assignment rules to fix element values. These capabilities MAY now be used as TU features of FSH.
Example:
Define a logical model for a human and their family members:
Logical: Human
Id: human-being-logical-model
Title: "Human Being"
Description: "A member of the Homo sapiens species."
Characteristics: #can-be-target
// url, status, purpose, and other metadata could be defined here using caret syntax (omitted)
* name 0..* SU HumanName "Name(s) of the human" "The names by which the human is or has been known"
* birthDate 0..1 SU dateTime "The date of birth, if known"
"The date on which the person was born. Approximations may be used if exact date is unknown."
* deceased[x] 0..1 SU boolean or dateTime or Age "Indication if the human is deceased"
"An indication if the human has died. Boolean should not be used if date or age at death are known."
* family 0..1 BackboneElement "Family" "Members of the human's immediate family."
* mother 0..2 FamilyMember "Mother" "Biological mother, current adoptive mother, or both."
* father 0..2 FamilyMember "Father" "Biological father, current adoptive father, or both."
* sibling 0..* FamilyMember "Sibling" "Other children of the human's mother and/or father."
Logical: FamilyMember
Id: family-member
Title: "Family Member"
Description: "A reference to a family member (not necessarily biologically related)."
* human 1..1 SU Reference(Human) "Family member" "A reference to the human family member"
* biological 0..1 boolean "Biologically related?"
"A family member may not be biologically related due to adoption, blended families, etc."
Note: The use of the
Characteristics
keyword in the example above is TU.
TU
The keyword Characteristics
MAY be used to specify the type characteristics of the logical model being defined. FSH implementations SHOULD represent these characteristics on the logical model using the Structure Type Characteristics extension with a code value from the TypeCharacteristicCodes value set. Authors SHOULD use the Characteristics
keyword instead of directly assigning this extension using assignment rules.
When specifying characteristics using the Characteristics
keyword, authors MUST NOT include the code system, as it is implied. Multiple characteristics SHALL be specified by using a comma-separated list of codes. The following is an allowed list of formats for characteristics:
Specifying a single characteristic:
Characteristics: {code}
Specifying multiple characteristics as a comma-separated list:
Characteristics: {code 1}, {code 2}, {code 3}...
Examples:
Defining a logical model with a single type characteristic
Logical: MyLogical
Characteristics: #can-bind
Defining a logical model with multiple type characteristics
Logical: MyLogical
Characteristics: #has-range, #has-units, #is-continuous
Mappings are an OPTIONAL part of a StructureDefinition, intended to help implementers understand the StructureDefinition in relation to other standards. While it is possible to define mappings using escape (caret) syntax, FSH provides a more concise approach. These mappings are informative and are not to be confused with the computable mappings provided by FHIR Mapping Language and the StructureMap resource.
To create a mapping, the declaration Mapping
and the keywords Source
and Target
are REQUIRED, and Id
, Title
and Description
are RECOMMENDED.
Keyword | Usage | StructureDefinition element |
---|---|---|
Mapping | Appears first and provides a unique name for the mapping | n/a |
Source | The name or id of the profile the mapping applies to | n/a |
Target | The URL, URI, or OID for the specification being mapped to | mapping.uri |
Id | An internal identifier for the target specification | mapping.identity |
Title | A human-readable name for the target specification | mapping.name |
Description | Additional information such as version notes, issues, or scope limitations. | mapping.comment |
The mappings themselves are declared in rules with the following syntaxes:
* -> "{map string}" "{comment string}" #{mime-type code}
* <element> -> "{map string}" "{comment string}" #{mime-type code}
A rule starting with the characters ->
SHALL map the profile as a whole to a target. A rule starting with an element followed by the characters ->
SHALL map a specific element within the source to a target. The map
, comment
, and mime-type
are as defined in FHIR and correspond to elements in StructureDefinition.mapping and ElementDefinition.mapping (map
corresponds to mapping.map
, mime-type
to mapping.language
, and comment
to mapping.comment
). The mime type code MUST come from FHIR's MimeType value set. For further information, refer to the FHIR definitions of these elements.
Note: Unlike setting the
mapping.map
directly in the StructureDefinition, mapping rules within a Mapping item MUST NOT include the name of the resource in the path on the left hand side.
Rule types that apply to Mappings are: Insert, Mapping, and Path.
Examples:
Map the entire profile to a Patient item in another specification:
* -> "Patient" "This profile maps to Patient in Argonaut"
Map the identifier.value
element from one IG to another:
* identifier.value -> "Patient.identifier.value"
Define a map between USCorePatient and Argonaut:
Mapping: USCorePatientToArgonaut
Source: USCorePatient
Target: "http://unknown.org/Argonaut-DQ-DSTU2"
Id: argonaut-dq-dstu2
Title: "Argonaut DSTU2"
* -> "Patient"
* extension[USCoreRaceExtension] -> "Patient.extension[http://fhir.org/guides/argonaut/StructureDefinition/argo-race]"
* extension[USCoreEthnicityExtension] -> "Patient.extension[http://fhir.org/guides/argonaut/StructureDefinition/argo-ethnicity]"
* extension[USCoreBirthSexExtension] -> "Patient.extension[http://fhir.org/guides/argonaut/StructureDefinition/argo-birthsex]"
* identifier -> "Patient.identifier"
* identifier.system -> "Patient.identifier.system"
* identifier.value -> "Patient.identifier.value"
To define a profile, the declaration Profile
and keyword Parent
are REQUIRED, and Id
, Title
, and Description
are RECOMMENDED. Profile metadata that does not have a dedicated keyword MAY be specified using assignment rules with caret paths (e.g., ^url
, ^status
, ^purpose
). Rules defining the profile follow immediately after the keyword section.
Rules types that apply to Profiles are: Assignment, Binding, Cardinality, Contains (standalone extensions), Contains (slicing), Flag, Insert, Obeys, Path, and Type. Note that inline extensions are not permitted in profiles.
Example:
Define a profile for exposure to a pathogen:
Profile: KnownExposureSetting
Parent: Observation
Id: known-exposure-setting
Title: "Known Exposure Setting Profile"
Description: "The setting where an individual was exposed to a contagion."
// url, status, purpose, and other metadata could be defined here using caret syntax (omitted)
* code = $LNC#81267-7 // Setting of exposure to illness
* value[x] only CodeableConcept
* value[x] from https://loinc.org/vs/LL3991-8 (extensible)
Custom resources allow authors to define new structures representing arbitrary content. Resources are defined similar to logical models, but are intended to support data exchange using FHIR's RESTful API mechanisms. The capability to define resources may be used by HL7 to define core FHIR resources or by other organizations to define proprietary resources for their own internal use. Potentially, they also can be used to represent and maintain existing core FHIR resources.
Custom (non-HL7) resources SHOULD NOT be used for formal exchange between organizations; only standard FHIR resources and profiles SHOULD be used for inter-organizational exchange of health data. As such, the the FHIR IG publisher does not support including custom resources in implementation guides.
Resources are defined using the REQUIRED declaration Resource
. The keywords Id
, Title
, and Description
are RECOMMENDED. The use of Parent
is OPTIONAL. If no Parent
is specified, DomainResource SHALL be assumed as the default parent. Only DomainResource and Resource SHALL be allowed as parents of a resource. Resource metadata that does not have a dedicated keyword MAY be specified using assignment rules with caret paths (e.g., ^url
, ^status
, ^purpose
).
Rules defining the resource follow immediately after the keyword section. Rules types that apply to resources are: Add Element, Assignment, Binding, Cardinality, Flag, Insert, Obeys, Path, and Type. The following limitations apply:
MS
flags.The latter restrictions stem from FHIR's interpretation of ElementDefinition for type definitions. Assignments MUST NOT set elements that are prohibited in that table. For example, the table indicates that setting maxLength
or mustSupport
is prohibited.
Example:
Define a resource representing an emergency vehicle, using line spacing to make the definition easier to read:
Resource: EmergencyVehicle
Id: emergency-vehicle
Title: "Emergency Vehicle"
Description: "An emergency vehicle, such as an ambulance or fire truck."
// url, status, purpose, and other metadata could be defined here using caret syntax (omitted)
* identifier 0..* SU Identifier
"Identifier(s) of the vehicle"
"Vehicle identifiers may include VINs and serial numbers."
* make 0..1 SU Coding
"The vehicle make"
"The vehicle make, e.g., Chevrolet."
* make from EmergencyVehicleMake (extensible)
* model 0..1 SU Coding
"The vehicle model"
"The vehicle model, e.g., G4500."
* model from EmergencyVehicleModel (extensible)
* year 0..1 SU positiveInt
"Year of manufacture"
"The year the vehicle was manufactured"
* servicePeriod 0..1 Period
"When the vehicle was in service"
"Start date and end date (if applicable) when the vehicle operated."
* operator 0..* Reference(Organization or Practitioner or PractitionerRole)
"The operator"
"The organization or persons responsible for operating the vehicle"
* device 0..* Reference(Device)
"Devices on board"
"Devices on board the vehicle."
Rule sets provide the ability to define a group of rules as an independent entity. Through insert rules, they can be incorporated into a compatible target. FSH behaves as if the rules in a rule set are copied into the target. As such, the inserted rules MUST make sense where they are inserted. Once defined, a single rule set MAY be used in multiple places. The first rule in a rule set MUST NOT be indented. Rules after the first rule MAY be indented but do not affect any rules outside of the rule set (i.e., inserting a rule set SHALL NOT affect the rule paths after the insert
rule).
All types of rules SHALL be usable in rule sets, including insert rules, enabling the nesting of rule sets in other rule sets. However, circular dependencies SHALL NOT be allowed.
Simple rule sets are defined by using the declaration RuleSet
followed by a user-selected name:
RuleSet: {name}
{rule1}
{rule2}
// More rules
Example:
Define a rule set for metadata to be used in multiple profiles:
RuleSet: RuleSet1
* ^status = #draft
* ^experimental = true
* ^publisher = "Elbonian Medical Society"
Rule sets MAY also specify one or more parameters as part of their definition. Parameterized rule sets are defined by using the declaration RuleSet
followed by a user-selected name and then a comma-separated list of parameters enclosed in parentheses:
RuleSet: {name}(parameter1, parameter2, parameter3...)
{rule1}
{rule2}
// More rules
Each parameter represents a value that SHALL be substituted into the rules when the rule set is inserted. See the insert rules section for details on how to pass parameter values when inserting a rule set. In the rules, the places where substitutions should occur SHALL be indicated by enclosing a parameter name in curly braces {}
. Spaces MAY be used after the opening brace and before the closing brace: {parameter1}
and { parameter1 }
are both valid substitution sequences for a parameter named parameter1
. A parameter MAY occur more than once in the rule set definition.
Examples:
Define a rule set that contains the syntax for setting the context of an extension. This example also demonstrates the use of soft indexing. Note that the curly brackets in this example are literal, not syntax expressions:
RuleSet: SetContext(path)
* ^context[+].type = #element
* ^context[=].expression = "{path}"
This rule set can be applied to indicate an extension can only be applied to certain resources, for example:
* insert SetContext(Procedure)
* insert SetContext(MedicationRequest)
* insert SetContext(MedicationAdministration)
When the rule set is expanded, it translates to:
* ^context[+].type = #element
* ^context[=].expression = "Procedure"
* ^context[+].type = #element
* ^context[=].expression = "MedicationRequest"
* ^context[+].type = #element
* ^context[=].expression = "MedicationAdministration"
Interpreting the soft indices, this is equivalent to:
* ^context[0].type = #element
* ^context[0].expression = "Procedure"
* ^context[1].type = #element
* ^context[1].expression = "MedicationRequest"
* ^context[2].type = #element
* ^context[2].expression = "MedicationAdministration"
Define a parameterized rule set to define items in a Questionnaire:
RuleSet: Question(linkId, text, type, repeats)
* item[+].linkId = "{linkId}"
* item[=].text = "{text}"
* item[=].type = #{type}
* item[=].repeats = {repeats}
Apply the rule set to populate a Questionnaire:
Instance: TravelRecord
InstanceOf: Questionnaire
// skip some
* insert Question(tr1, When did you leave?, date, false)
* insert Question(tr2, When did you return?, date, false)
* insert Question(tr3, What countries did you visit?, code, true)
A value set is a group of coded values representing acceptable values for a FHIR element whose datatype is code, Coding, CodeableConcept, Quantity, string, or url.
Value sets are defined using the REQUIRED declaration ValueSet
, with RECOMMENDED keywords Id
, Title
and Description
. Value set metadata that does not have a dedicated keyword MAY be specified using assignment rules with caret paths (e.g., ^url
, ^status
, ^purpose
).
Codes MUST be taken from one or more terminology systems (also called code systems or vocabularies). Codes cannot be defined inside a value set. If necessary, you MAY define your own code system.
The contents of a value set SHALL be defined by "include" rules, which have the following syntax:
Note: In value set rules, the word
include
is OPTIONAL.
To include… | Syntax | Examples |
---|---|---|
A single code | * include {Coding} |
* include http://snomed.info/sct#22298006 "Myocardial infarction (disorder)" * $SCT#22298006 "Myocardial infarction (disorder)" * http://snomed.info/sct|http://snomed.info/sct/731000124108#22298006 "Myocardial infarction (disorder)" |
All codes from another value set | * include codes from valueset {ValueSet}|{version string} |
* include codes from valueset http://hl7.org/fhir/ValueSet/data-absent-reason * include codes from valueset http://hl7.org/fhir/ValueSet/data-absent-reason|5.0.0 |
All codes from a code system | * include codes from system {CodeSystem}|{version string} |
* include codes from system http://snomed.info/sct * include codes from system http://snomed.info/sct|http://snomed.info/sct/731000124108 |
Codes that lie in the intersection of value set(s) and (optionally) a code system | * include codes from system {CodeSystem}|{version string} and valueset {ValueSet1}|{version1 string} and {ValueSet2}|{version2 string}... |
* include codes from valueset http://hl7.org/fhir/ValueSet/units-of-time and http://hl7.org/fhir/ValueSet/age-units * include codes from valueset http://hl7.org/fhir/ValueSet/units-of-time|5.0.0 and http://hl7.org/fhir/ValueSet/age-units|5.0.0 |
Filtered codes from a code system | * include codes from system {CodeSystem}|{version string} where {filter1} and {filter2}... |
* include codes from system $SCT where concept descendant-of #254837009 * include codes from system http://snomed.info/sct where concept is-a #254837009 * include codes from system http://snomed.info/sct|http://snomed.info/sct/731000124108 where concept is-a #254837009 |
Notes:
include
rules.include
rule has both a system and more than one value set, the code system MUST be first or last.include
rule MUST not have more than one code system (the intersection of two code systems is the empty set).Examples:
Include codes in the intersection of time and age units:
* include codes from valueset http://hl7.org/fhir/ValueSet/units-of-time
and http://hl7.org/fhir/ValueSet/age-units
Include only the v2 codes in the name-assembly-order value set:
* include codes from system http://terminology.hl7.org/CodeSystem/v2-0444 and valueset http://hl7.org/fhir/ValueSet/name-assembly-order
Analogous rules MAY be used to leave out certain codes, with the word exclude
replacing the word include
:
To exclude… | Syntax | Examples |
---|---|---|
A single code | * exclude {Coding} |
* exclude $SCT#22298006 "Myocardial infarction (disorder)" * exclude http://snomed.info/sct#22298006 "Myocardial infarction (disorder)" * exclude http://snomed.info/sct|http://snomed.info/sct/731000124108#22298006 "Myocardial infarction (disorder)" |
All codes from another value set | * exclude codes from valueset {ValueSet}|{version string} |
* exclude codes from valueset http://hl7.org/fhir/ValueSet/data-absent-reason * exclude codes from valueset http://hl7.org/fhir/ValueSet/data-absent-reason|5.0.0 |
All codes from a code system | * exclude codes from system {CodeSystem}|{version string} |
* exclude codes from system http://snomed.info/sct * exclude codes from system http://snomed.info/sct|http://snomed.info/sct/731000124108 |
Codes that lie in the intersection of value set(s) and (optionally) a code system | * exclude codes from system {CodeSystem}|{version string} and valueset {ValueSet1}|{version1 string} and {ValueSet2}|{version2 string}... |
* exclude codes from valueset http://hl7.org/fhir/ValueSet/units-of-time and http://hl7.org/fhir/ValueSet/age-units * exclude codes from valueset http://hl7.org/fhir/ValueSet/units-of-time|5.0.0 and http://hl7.org/fhir/ValueSet/age-units|5.0.0 |
Filtered codes from a code system | * exclude codes from system {CodeSystem}|{version string} where {filter} |
* exclude codes from system $SCT where concept is-a #254837009 * exclude codes from system http://snomed.info/sct where concept is-a #254837009 * exclude codes from system http://snomed.info/sct|http://snomed.info/sct/731000124108 where concept is-a #254837009 |
Rule types that apply to ValueSets are: Assignment, Exclude, Include, and Insert. Assignment rules SHALL be applicable to value sets only in the context of caret paths.
For additional details about ValueSet composition, see the FHIR documentation on ValueSet composition rules.
A filter is a logical statement in the form {property} {operator} {value}
, where operator MUST be chosen from the FilterOperator value set. Not all operators in that value set are valid for all code systems. The property
and value
are dependent on the code system. Depending on the filter, the value
MAY be a code (e.g., #123-A
), boolean (e.g., true
), string (e.g., "inherited"
), or regular expression (e.g., /A\.[0-9]+/
). For choices for the most common code systems, see the FHIR documentation on filters.
Examples
Define a value set using extensional rules. This example demonstrates the optionality of the word include
:
ValueSet: BinetStageValueVS
Id: mcode-binet-stage-value-vs
Title: "Binet Stage Value Set"
Description: "Codes in the Binet staging system representing Chronic Lymphocytic Leukemia (CLL) stage."
// url, status, purpose, and other metadata could be defined here using caret syntax (omitted)
* $NCIT#C80134 "Binet Stage A"
* $NCIT#C80135 "Binet Stage B"
* $NCIT#C80136 "Binet Stage C"
Define a value set using intensional rules:
ValueSet: HistologyMorphologyBehaviorVS
Id: mcode-histology-morphology-behavior-vs
Title: "Histology Morphology Behavior Value Set"
Description: "Codes representing the structure, arrangement, and behavioral characteristics of malignant neoplasms, and cancer cells."
// url, status, purpose, and other metadata could be defined here using caret syntax (omitted)
* include codes from system $SCT where concept is-a #367651003 "Malignant neoplasm of primary, secondary, or uncertain origin (morphologic abnormality)"
* include codes from system $SCT where concept is-a #399919001 "Carcinoma in situ - category (morphologic abnormality)"
* include codes from system $SCT where concept is-a #399983006 "In situ adenomatous neoplasm - category (morphologic abnormality)"
* exclude codes from system $SCT where concept is-a #450893003 "Papillary neoplasm, pancreatobiliary-type, with high grade intraepithelial neoplasia (morphologic abnormality)"
* exclude codes from system $SCT where concept is-a #128640002 "Glandular intraepithelial neoplasia, grade III (morphologic abnormality)"
* exclude codes from system $SCT where concept is-a #450890000 "Glandular intraepithelial neoplasia, low grade (morphologic abnormality)"
* exclude codes from system $SCT where concept is-a #703548001 "Endometrioid intraepithelial neoplasia (morphologic abnormality)"
Note: Intensional and extensional forms MAY be used together in a single value set definition.
TU
Within a ValueSet definition, the caret syntax MAY be used to set metadata attributes for individual concepts (e.g., elements of ValueSet.compose.include.concept.designation
).
To assign metadata values for concepts that are included in the value set, authors SHOULD specify one or more indented caret path assignment rules below the rule that includes the concept:
* include {Coding}
* ^<element1 of corresponding concept> = {value1}
* ^<element2 of corresponding concept> = {value2}
To assign metadata values for concepts that are excluded in the value set, authors SHOULD specify one or more indented caret path assignment rules below the rule that excludes the concept:
* exclude {Coding}
* ^<element1 of corresponding concept> = {value1}
* ^<element2 of corresponding concept> = {value2}
Indented caret path assignment rules are RECOMMENDED for clarity, but authors MAY choose to repeat the code and follow it with a caret path assignment instead:
* {Coding} ^<element1 of corresponding concept> = {value1}
* {Coding} ^<element2 of corresponding concept> = {value2}
Note: A concept MUST be included or excluded before caret rule assignments can be used to set its metadata. When a single rule contains a concept followed by a caret path assignment, the assignment pertains to the concept wherever it is found in the composition (whether included or excluded).
Examples:
To specify a designation
for the fully specified name of the included concept $SCT#84162001
:
* $SCT#84162001 "Cold"
* ^designation[0].use = $SCT#900000000000003001 "Fully specified name"
* ^designation[0].value = "Cold sensation quality (qualifier value)"
To specify a designation
for the fully specified name of the included concept $LNC#55423-8
using the include
keyword:
* include $LNC#55423-8 "Number of steps"
* ^designation[0].use = $SCT#900000000000003001 "Fully specified name"
* ^designation[0].value = "Number of steps in Unspecified Time, Pedometer"
To specify a designation
for a synonym of the included concept $SCT#32849002
by repeating the code:
* $SCT#32849002 "Esophageal structure"
* $SCT#32849002 ^designation[0].use = $SCT#900000000000013009 "Synonym (core metadata concept)"
* $SCT#32849002 ^designation[0].language = urn:ietf:bcp:47#en-GB
* $SCT#32849002 ^designation[0].value = "Oesophageal structure"
To specify a designation
for a synonym of the excluded concept $SCT#22298006
:
* exclude $SCT#22298006 "Myocardial infarction (disorder)"
* ^designation[0].use = $SCT#900000000000013009 "Synonym (core metadata concept)"
* ^designation[0].language = urn:ietf:bcp:47#en-US
* ^designation[0].value = "Heart attack"
To specify a designation
for the fully specified name of the excluded concept $SCT#54987000
by repeating the code:
* exclude $SCT#54987000 "Choledochoplasty"
* $SCT#54987000 ^designation[0].use = $SCT#900000000000003001 "Fully specified name"
* $SCT#54987000 ^designation[0].value = "Repair of common bile duct (procedure)"
Rules are the mechanism in FSH for populating and constraining items by setting cardinality, applying flags, binding value sets, defining extensions, and more. Rules in FSH are distinguished by a leading asterisk (*
) symbol:
* {rule statement}
The following restrictions apply to rules:
The following table is a summary of the rule syntax.
Rule Type | Syntax |
---|---|
Add Element | * <element> {card} {flag(s)} {datatype(s)} "{short}" "{definition}" * <element> {card} {flag(s)} contentReference {contentUrl} "{short}" "{definition}" |
Assignment | * <element> = {value} (exactly) |
Binding | * <bindable> from {ValueSet} ({strength}) |
Cardinality | * <element> {min}..{max} // min, max, or both MUST be present |
Contains (standalone extensions) | * <extension> contains {Extension1} named {name1} {card} {flag(s)} |
Contains (inline extensions) | * <extension> contains {name1} {card} {flag(s)} |
Contains (slicing) | * <array> contains {name} {card} {flag(s)} |
Exclude | * exclude {Coding} * exclude codes from valueset {ValueSet}|{version} * exclude codes from system {CodeSystem}|{version} * exclude codes from system {CodeSystem}|{version} where {filter1} and {filter2}... * exclude codes from system {CodeSystem}|{version} |
Flag | * <element(s)> {flag(s)} |
Include | * include {Coding} * include codes from valueset {ValueSet}|{version} * include codes from system {CodeSystem}|{version} * include codes from system {CodeSystem}|{version} where {filter1} and {filter2}... * include codes from system {CodeSystem}|{version} |
Insert | * insert {RuleSet} * insert {RuleSet}({parameter1}, {parameter2}, ...) * <element> insert {RuleSet}({parameter1}, {parameter2}, ...) |
Local Code | * #{code} "{display string}" "{definition string}" * #{parentCode} #{childCode} "{display string}" "{definition string}" |
Mapping | * <element> -> "{map string}" "{comment string}" #{mime-type code} |
Obeys | * <element> obeys {Invariant} and {Invariant2} and {Invariant3}... |
Path | * <element> |
Type | * <element> only {datatype(s)} |
Rules SHALL be interpreted logically in a top-down manner. In many cases, the order of rules is flexible. However, there are some situations where FSH requires rules to appear in a certain order. For example, slicing rules require that a slice MUST first be defined by a contains
rule before the slice is referenced. Implementations MUST enforce rule-order requirements where they are specified in FSH.
Logical order dependencies can also arise. For example, in setting properties of a choice element (an element involving FHIR's [x]
syntax), this order is problematic:
* value[x].unit 0..0
* value[x] only Quantity
but this order is acceptable:
* value[x] only Quantity
* value[x].unit 0..0
In the first approach, value[x]
is not yet known to be restricted to a Quantity, so value[x].unit
is ambiguous. In the second approach, value[x]
is known to be a Quantity, so value[x].unit
is unambiguous.
In cases with no explicit or logical restrictions on rule ordering, users MAY list rules in any order, bearing in mind that insert rules expand into other rules that could have order constraints or logical ordering requirements.
It is possible for a user to specify contradictory rules, for example, two rules constraining the cardinality of an element to different values, or constraining an element to different datatypes. Implementations SHOULD detect such contradictions and issue appropriate warning or error messages.
Indentation before a rule MAY be used to set a context for the path on that rule. When one rule is indented below another, the full path of the indented rule or rules SHALL be obtained by prepending the path from the previous less-indented rule or rules. The level of indentation MAY be reduced to indicate that a rule should not use the context of the preceding rule. The full path of all rules SHALL be resolved from the context specified by indentation before any rules are applied.
Two spaces SHALL represent one level of indentation. Rules SHALL only be indented in increments of two spaces and un-indented by any multiple of two spaces.
Path rules are rules containing only a path. They are primarily used to set a path as context for subsequent rules, without any other effect. TU In FSH Instances, path rules sometimes have other effects as well. See path rules for more information.
Some types of rules, for example flag rules, MAY involve multiple paths. If multiple paths are specified in a rule that sets context for subsequent rules (such as a flag rule with multiple targets), the last path SHALL be used as context. When multiple paths are specified in an indented rule, context SHALL be applied to all paths. See examples below for details.
There are some limitations on where indented rules can be used. Indented rules MUST NOT appear below rules that do not specify a path. Rules that may omit an element path include top-level obeys rules, top-level caret paths, mapping rules, and insert rules.
When indented rules are combined with soft indexing and a rule containing the increment operator [+]
sets the path context for multiple subsequent rules, the index SHALL be incremented only once. On subsequent rules, the [+]
is effectively replaced with [=]
. See examples below for details.
Examples:
Use indented rules to set cardinalities on name.family
and name.given
in a Patient resource:
* name 1..1
* family 1..1
* given 1..1
is equivalent to:
* name 1..1
* name.family 1..1
* name.given 1..1
Use a path rule to set context for subsequent rules:
* name
* family 1..1
* given 1..1
is equivalent to:
* name.family 1..1
* name.given 1..1
Example of multi-level indented rules:
* name MS
* family MS
* id MS
is equivalent to:
* name MS
* name.family MS
* name.family.id MS
Example of multiple paths in an indented rule, with the context applied to all paths:
* name
* family and given MS
is equivalent to:
* name.family and name.given MS
Example of multiple paths in a rule that sets context for subsequent rules, where the last path sets the context:
* birthDate and name MS
* family 1..1
is equivalent to:
* birthDate and name MS
* name.family 1..1
Example of reducing the level of indentation to remove the context of a preceding rule:
* item[0]
* linkId = "title"
* type = #display
* item[0]
* linkId = "uniquearv_number"
* type = #string
* item[1]
* linkId = "personal_info"
* type = #group
* status = #active
is equivalent to:
* item[0].linkId = "title"
* item[0].type = #display
* item[0].item[0].linkId = "uniquearv_number"
* item[0].item[0].type = #string
* item[0].item[1].linkId = "personal_info"
* item[0].item[1].type = #group
* status = #active
Example of combining soft indexing with indented rules, where a rule with the increment operator [+]
is used to set the context:
* item[+]
* linkId = "title"
* type = #display
is not equivalent to:
* item[+].linkId = "title"
* item[+].type = #display
but is instead equivalent to:
* item[+].linkId = "title"
* item[=].type = #display
Another example of soft indexing combined with indented paths, illustrating that when a rule containing [+]
is used to set the context of multiple subsequent rules, the index is incremented only once:
* rest.resource[+]
* type = #Organization
* interaction[+].code = #create
* interaction[+].code = #update
* interaction[+].code = #delete
* rest.resource[+]
* type = #Condition
* interaction[+].code = #create
* interaction[+].code = #update
is equivalent to:
* rest.resource[+].type = #Organization
* rest.resource[=].interaction[+].code = #create
* rest.resource[=].interaction[+].code = #update
* rest.resource[=].interaction[+].code = #delete
* rest.resource[+].type = #Condition
* rest.resource[=].interaction[+].code = #create
* rest.resource[=].interaction[+].code = #update
is equivalent to:
* rest.resource[0].type = #Organization
* rest.resource[0].interaction[0].code = #create
* rest.resource[0].interaction[1].code = #update
* rest.resource[0].interaction[2].code = #delete
* rest.resource[1].type = #Condition
* rest.resource[1].interaction[0].code = #create
* rest.resource[1].interaction[1].code = #update
An error, attempting to use a rule without a path as context for an indented rule, since obeys
does not imply a path:
* obeys inv-1
* family 1..1
Authors define logical models and resources by adding new elements to their definitions. The add element rule is only applicable for logical models and resources. It SHALL NOT be used when defining profiles or extensions.
The syntax of the rules to add a new element is as follows:
* <element> {min}..{max} {flag(s)} {datatype(s)} "{short}" "{definition}"
where {datatype(s)}
MAY be one of the following:
or
,Reference({Resource/Profile1} or {Resource/Profile2} or {Resource/Profile3}...)
Canonical({Resource/Profile1} or {Resource/Profile2} or {Resource/Profile3}...)
CodeableReference({Resource/Profile1} or {Resource/Profile2} or {Resource/Profile3}...)
TU
To add an element that uses a contentReference to refer to another element, use the following syntax:
* <element> {min}..{max} {flag(s)} contentReference {contentUrl} "{short}" "{definition}"
where {contentUrl}
is a URI referencing the element whose properties will be used to define this element. This type of element definition is typically used with recursively nested elements, such as Questionnaire.item.item, which is defined by reference to #Questionnaire.item
. Another example is Observation.component.referenceRange, which is defined by reference to #Observation.referenceRange
. Refer to the ElementDefinition documentation for more information.
Note the following:
contentReference
keyword, a content reference URI, and short description.[x]
unless all types are References, all types are Canonicals, or TU all types are CodeableReferences.Examples:
Add a string-typed element:
* email 0..* string "The person's email addresses"
Add a string-typed element with a summary flag and longer definition:
* email 0..* SU string "The person's email addresses" "Email addresses by which the person may be contacted."
TU
Add an element defined by a contentReference
, which receives the content rules of the referenced element:
* email 0..* contentReference http://example.org/StructureDefinition/AnotherResource#AnotherResource.email "The person's email addresses"
Add a reference-typed element with a longer definition:
* primaryClinicians 0..* Reference(Organization or Practitioner or PractitionerRole) "Primary clinicians"
"The person's primary clinical organizations and practitioners"
Add a choice element with a multi-line description using markdown syntax:
* preferredName[x] 0..1 string or HumanName "The person's preferred name" """
Sometimes patients prefer to be called by a name other than their _formal_ name. This may be:
* their nickname
* their middle name
* their maiden name
* etc.
"""
Add a BackboneElement element to provide a structured set of elements in a logical model:
* serviceAnimal 0..* BackboneElement "Service animals" "Animals trained to assist the person by performing certain tasks."
* serviceAnimal.name 0..1 string "Name of service animal" "The name by which the service animal responds."
* serviceAnimal.breed 1..* CodeableConcept "Breed of service animal" "The dominant breed or breeds of the service animal."
* serviceAnimal.startDate 0..1 date "Date the service animal began work" "The date on which the service animal began working for the person."
or the same set of rules using indentation to maintain the path context:
* serviceAnimal 0..* BackboneElement "Service animals" "Animals trained to assist the person by performing certain tasks."
* name 0..1 string "Name of service animal" "The name by which the service animal responds."
* breed 1..* CodeableConcept "Breed of service animal" "The dominant breed or breeds of the service animal."
* startDate 0..1 date "Date the service animal began work" "The date on which the service animal began working for the person."
Assignment rules follow this syntax:
* <element> = {value}
The left side of this expression SHALL follow the FSH path grammar and MAY optionally include a caret path in definitions for profiles, extensions, logicals, resources, code systems, and value sets. The datatype on the right side MUST align with the datatype of the final element in the path. Except in specific cases noted below, an assignment replaces any existing value assigned to the element.
Assignment rules have two very different interpretations, depending on context:
This is best illustrated by example. Consider the following assignment (assuming code
is a CodeableConcept):
* code = https://loinc.org#69548-6
If this statement appears in an instance of an Observation, then the values of code.coding[0].system
and code.coding[0].code
will be set to https://loinc.org and 69548-6, respectively, in that Observation.
If the identical statement appears in a profile on Observation, it signals that the StructureDefinition is configured such that the code
element of a conformant instance MUST have a Coding with the system http://loinc.org and the code 69548-6. (In fact, the StructureDefinition does not even have its own code
element to populate.)
Note: In the profiling context, typically only the system and code are important conformance criteria for a Coding or CodeableConcept property. If a display text is included, it will be part of the conformance criteria.
In the latter case of establishing a constraint in a profile, the constraint pattern is considered "open" by default, in the sense that the element in question might have content in addition to the prescribed value, such as alternative codes in a CodeableConcept. If conformance to a profile requires a precise match to the pattern (which is rare), then the following syntax can be used:
* <element> = {value} (exactly)
Adding (exactly)
indicates that an exact match is REQUIRED. When the right-hand side of an assignment is a primitive value (e.g., a string), (exactly)
indicates that the exact value is REQUIRED and MUST NOT have an id or extensions. When the right-hand side of an assignment is a complex value (e.g., a Quantity), (exactly)
indicates that all specified components of the complex value are REQUIRED and additional sub-elements SHALL NOT be allowed. In general, using (exactly)
is not the best option for interoperability because it creates conformance criteria that could be too tight, risking the rejection of valid, useful data. FSH offers this option primarily because exact value matching is used in some current IGs and profiles. For example, in a profile,
* code = $LNC#69548-6 (exactly)
means that a conforming instance MUST have the system http://loinc.org, the code 69548-6, and MUST NOT have a display text, additional codes, or extensions on the code element.
Note: Assigning values in a profile populates the underlying ElementDefinition's
pattern[x]
orfixed[x]
property (pattern[x]
in the default case;fixed[x]
when(exactly)
is used). As such, assigned values SHALL be restricted to the types allowed for open type elements.
When assigning values to an instance, the (exactly)
modifier has no meaning and SHOULD NOT be used. Implementations MAY ignore the modifier or signal an error.
Examples:
Assignment of a code datatype:
* status = #arrived
Assignment of a boolean:
* active = true
Assignment of a date:
* onsetDateTime = "2019-04-02"
Assignment of a dateTime:
* recordedDate = "2013-06-08T09:57:34.2112Z"
TU
Assignment of an integer64 (note: this datatype was introduced in FHIR R5):
* extension[my-extension].valueInteger64 = 1234567890
A FHIR Coding has five attributes (system
, version
, code
, display
, and userSelected
). The first four of these MAY be set with a single assignment statement. The syntax is:
<Coding> = {CodeSystem}|{version string}#{code} "{display string}"
The only REQUIRED part of this statement is the code (including the #
sign), although every Coding SHOULD have a code system. The version string MUST NOT appear without a code system.
Whenever this type of rule is applied, whatever is on the right side SHALL entirely replace the previous value of the Coding on the left side. For example, if a Coding has a value that includes a display string, and a subsequent assignment replaces the system and code but has no display string, the result is a Coding without a display string.
Examples:
Assign a Coding that includes only a code:
myCoding = #chol-mmol
Assign a Coding that includes an explicit code system version:
myCoding = http://hl7.org/fhir/CodeSystem/example-supplement|201801103#chol-mmol
As an alternative to the bar syntax for version, set the code system version only:
* myCoding.version = "201801103"
Set the userSelected
property of a Coding (one of the lesser-used attributes of Codings):
* myCoding.userSelected = true
In an instance of a Signature, set Signature.type
(a Coding datatype):
* type = urn:iso-astm:E1762-95:2013#1.2.840.10065.1.12.1.2 "Coauthor's Signature"
Example of what happens when a second assignment replaces an existing value:
* myCoding = $SCT#363346000 "Malignant neoplastic disease (disorder)"
* myCoding = $ICD#C80.1
Because the second assignment clears the previous value of myCoding
, the result is:
myCoding.system
is http://hl7.org/fhir/sid/icd-10-cm (assuming the $ICD
alias maps to this URL)myCoding.code
is "C80.1"myCoding.display
has no valuemyCoding.version
has no valueExample of how incorrectly ordered rules can lead to loss of a previously-assigned value, because myCoding
is cleared as part of the second assignment:
* myCoding.userSelected = true
* myCoding = $SCT#363346000 "Malignant neoplastic disease (disorder)"
The result is:
system
is http://snomed.info/sctcode
is "363346000"display
is "Malignant neoplastic disease (disorder)"userSelected
has no valueThe correct way to approach the previous example is to reverse the order of the assignments:
* myCoding = $SCT#363346000 "Malignant neoplastic disease (disorder)"
* myCoding.userSelected = true
A CodeableConcept consists of an array of Codings and a text. To populate the array in an instance, array indices, denoted by brackets, are used. The shorthand is:
* <CodeableConcept>.coding[{index}] = {CodeSystem}|{version string}#{code} "{display string}"
The syntax on the right side is precisely like setting a Coding, as discussed directly above.
To set the first Coding in a CodeableConcept, FSH offers the following shortcut:
* <CodeableConcept> = {CodeSystem}|{version string}#{code} "{display string}"
Whenever the shortcut rule is applied, the value on the right side SHALL entirely replace any previous value of the CodeableConcept on the left side. Any previous value(s) in the CodeableConcept are cleared.
Assignment rules MAY be used to set any part of a CodeableConcept. For example, to set the top-level text
attribute of a CodeableConcept, the FSH expression is:
* <CodeableConcept>.text = "{string}"
Examples:
Set the first Coding in myCodeableConcept
:
* myCodeableConcept = $SCT#363346000 "Malignant neoplastic disease (disorder)"
An equivalent representation, using an explicit array index on the coding
array:
* myCodeableConcept.coding[0] = $SCT#363346000 "Malignant neoplastic disease (disorder)"
Another equivalent representation, using the shorthand that allows dropping the [0]
index:
* myCodeableConcept.coding = $SCT#363346000 "Malignant neoplastic disease (disorder)"
Add a second value to the array of Codings:
* myCodeableConcept.coding[1] = $ICD#C80.1 "Malignant (primary) neoplasm, unspecified"
Set the top-level text
attribute:
* myCodeableConcept.text = "Diagnosis of malignant neoplasm left breast."
Example of incorrect ordering rules that lead to loss of a previously-assigned value, because the last assignment clears the existing value of myCodeableConcept
before it applies new values:
* myCodeableConcept.coding[0].userSelected = true
* myCodeableConcept.text = "Metastatic Cancer"
* myCodeableConcept = $SCT#363346000 "Malignant neoplastic disease (disorder)"
The result is:
coding[0].system
is http://snomed.info/sctcoding[0].code
is "363346000"display
is "Malignant neoplastic disease (disorder)"coding[0].userSelected
has no valuetext
has no valueThe correct way to approach the previous example is to set the values of userSelected
and text
after setting the coding
, since those assignments only change the specific subelements on the left side of those assignments:
* myCodeableConcept = $SCT#363346000 "Malignant neoplastic disease (disorder)"
* myCodeableConcept.coding[0].userSelected = true
* myCodeableConcept.text = "Metastatic Cancer"
FSH provides a shorthand that allows quantities, units of measure, and display string for the units of measure to be specified simultaneously, provided the units of measure are Unified Code for Units of Measure (UCUM) codes:
* <Quantity> = {decimal} '{UCUM code}' "{units display string}"
A similar shorthand MAY be used for other code systems by specifying the unit using the standard FSH code syntax:
* <Quantity> = {decimal} {CodeSystem}|{version string}#{code} "{units display string}"
Alternatively, the value and units MAY also be set independently. To assign a value, use the Quantity.value
property:
* <Quantity>.value = {decimal}
The units of measure MAY be set independently by assigning a UCUM unit without the value:
* <Quantity> = '{UCUM code}' "{units display string}"
For non-UCUM units, the units of measure MAY be set independently by assigning a coded value to a Quantity:
* <Quantity> = {CodeSystem}|{version string}#{code} "{units display string}"
Examples:
Set the valueQuantity
of an Observation to 55 millimeters using UCUM units:
* valueQuantity = 55.0 'mm'
Set the valueQuantity
of an Observation to 55 millimeters using UCUM units and a display string:
* valueQuantity = 55.0 'mm' "millimeter"
Set the numerical value of Observation.valueQuantity
to 55.0 without setting the units:
* valueQuantity.value = 55.0
Set the units of Observation.valueQuantity
to millimeters, using UCUM units and a display string, without setting the value:
* valueQuantity = 'mm' "millimeter"
Express a weight in pounds, using the UMLS code for units (not recommended), and displaying "pounds":
* valueQuantity = 155.0 http://terminology.hl7.org/CodeSystem/umls#C0439219 "pounds"
Set the units of Observation.valueQuantity
to pounds, using the UMLS unit code (not recommended) and a display string, without setting the value (assuming $UMLS
has been defined as an alias for http://terminology.hl7.org/CodeSystem/umls):
* valueQuantity = $UMLS#C0439219 "pounds"
Example of how incorrect ordering of rules can result in the loss of a previously assigned value:
* valueQuantity.unit = "millimeter"
* valueQuantity = 55.0 'mm'
Note that the second rule clears valueQuantity
in its entirety before applying the specified values, so the result is:
value
is 55.0system
is http://unitsofmeasure.orgcode
is "mm"unit
has no valueThe correct way to approach the previous example, so unit has the desired value, is simply to reverse the order of rules:
* valueQuantity = 55.0 'mm'
* valueQuantity.unit = "millimeter"
Another way to approach this example (with the correct result) is:
* valueQuantity = $UCUM#mm "millimeter"
* valueQuantity.value = 55.0
Resource instances MAY refer to other resource instances. The referred resources can either exist independently or be contained inline in the DomainResource.contained
array. Less commonly, the value of an element can be a resource, rather than a reference to a resource.
A resource reference is assigned using this syntax:
* <Reference> = Reference({Resource})
For assignment of a resource to the value of an element directly:
* <Resource> = {Resource}
As advised in FHIR, the URL is the preferred way to reference an instance for the resource types on which it is defined. One advantage is that the URL MAY include a version. For an internal FSH-defined instance, referring to an instance by its id (as defined in the Instance
declaration) is more typical (see examples).
Examples:
Assignment of a reference to an example of a Patient resource to Observation.subject
:
* subject = Reference(EveAnyperson)
where, for example:
Instance: EveAnyperson // this is the id of the example instance
InstanceOf: Patient
Description: "Eve Anyperson"
Usage: #example
* name.given = "Eve"
* name.family = "Anyperson"
Assignment of the same instance in Bundle.entry.resource
, whose datatype is Resource (not Reference(Resource)):
* entry[0].resource = EveAnyperson
TU
The CodeableReference datatype was introduced as part of FHIR R5 release sequence. This type allows for a concept, a reference, or both. FSH supports applying bindings directly to CodeableReferences and directly constraining types on CodeableReferences. When applying a type rule (e.g., code only CodeableReference(Medication)
), the element's reference
property SHALL be constrained to the given type, but its concept
property SHALL remain available for use (unless otherwise constrained by another rule).
To assign values to a CodeableReference, authors MAY assign a FSH Coding or reference directly to the CodeableReference element. Assigning a Coding to a CodeableReference element SHALL assign the Coding to the element's concept
property. Assigning a reference to a CodeableReference element SHALL assign the reference to the element's reference
property. Assigning a Coding SHALL NOT affect the CodeableReference's reference
property. Similarly, assigning a reference SHALL NOT affect the CodeableReference's concept
property. If preferred, authors MAY assign a CodeableConcept's concept
and reference
properties directly.
Examples:
Constrain Substance.code
, which is datatype CodeableReference(SubstanceDefinition)
in FHIR R5:
Profile: LatexSubstance
Parent: Substance
Id: latex-substance
Description: "A substance consisting of or containing latex"
// restrict the CodeableConcept aspect to a code in the LatexCodeVS value set:
* code from LatexCodeVS (required)
// restrict Reference aspect to an instance of SubstanceDefinition conforming to the LatexSubstanceDefinition profile:
* code only CodeableReference(LatexSubstanceDefinition)
Assign the concept
and reference
properties of a CodeableReference by assigning values directly to the CodeableReference element:
Instance: LatexSubstanceExample
InstanceOf: LatexSubstance
Title: "Natural Rubber"
Description: "Natural rubber latex substance"
* code = $SCT#1003754000 "Natural rubber latex (substance)"
* code = Reference(NaturalLatexSubstanceDefinitionExample)
Assign the concept
and reference
properties of a CodeableReference by assigning values directly to each property. This has the same result as the example above:
Instance: LatexSubstanceExample
InstanceOf: LatexSubstance
Title: "Natural Rubber"
Description: "Natural rubber latex substance"
* code.concept = $SCT#1003754000 "Natural rubber latex (substance)"
* code.reference = Reference(NaturalLatexSubstanceDefinitionExample)
When the left side of an assignment rule contains a caret path, the value SHALL be assigned to the corresponding path within the underlying definitional instance of the FSH item. For more information about caret paths, see Caret Paths.
Examples
Assign the experimental
flag in a profile's StructureDefinition to true
:
* ^experimental = true
Override the auto-generated url in an extension's StructureDefinition with a custom url:
* ^url = "http://example.org/custom/myextension"
Assign the short description and definition for the Observation.value[x]
ElementDefinition in an Observation profile:
* value[x] ^short = "Measurement in cm"
* value[x] ^definition = "The measurement in centimeters. Values in other units must be converted to centimeters in order to conform with this profile."
Assign the short description and definition for the Observation.value[x]
ElementDefinition in an Observation profile using indented rules:
* value[x]
* ^short = "Measurement in cm"
* ^definition = "The measurement in centimeters. Values in other units must be converted to centimeters in order to conform with this profile."
Assign code metadata designation.use
for the #active
code within a CodeSystem:
* #active ^designation[0].use = $SCT#900000000000003001 "Fully specified name"
Assign concept metadata for a concept within a ValueSet using indented rules:
* include $SCT#84162001 "Cold"
* ^designation[0].use = $SCT#900000000000003001 "Fully specified name"
* ^designation[0].value = "Cold sensation quality (qualifier value)"
Binding is the process of associating a coded element with a set of possible values. The syntax to bind a value set, or alter an inherited binding, uses the reserved word from
:
* <bindable> from {ValueSet} ({strength})
The bindable types SHALL be the same as the bindable types in FHIR: code, Coding, CodeableConcept, Quantity, string, and uri. In FHIR R5, TU CodeableReference SHALL also be bindable.
The strengths SHALL be the same as the binding strengths defined in FHIR, namely: example
, preferred
, extensible
, and required
. If strength is not specified, a required binding SHALL be assumed.
The binding rules defined in FHIR SHALL be applicable to FSH. In particular:
Examples:
Bind to an externally-defined value set using its canonical URL:
* category from http://hl7.org/fhir/ValueSet/observation-category (required)
Bind to an externally-defined value set with required binding by default:
* gender from http://hl7.org/fhir/ValueSet/administrative-gender
Bind to a value set using an alias name, assuming $AdGen
is an alias for http://hl7.org/fhir/ValueSet/administrative-gender:
* gender from $AdGen
Bind to a value set by its name when it is defined in the same FSH project:
* code from CancerConditionVS (extensible)
Cardinality rules constrain (narrow) the number of repetitions of an element. Every element has a cardinality inherited from its parent resource or profile. If the inheriting profile does not alter the cardinality, no cardinality rule is required.
To change the cardinality, the syntax is:
* <element> {min}..{max}
* <element> {min}.. // leave max as-is
* <element> ..{max} // leave min as-is
As in FHIR, min
MUST be a non-negative integer and max
MUST be a non-negative integer or *, representing unbounded. Authors MAY include both the min
and max
, even if one of them remains the same as in the original cardinality. In this case, FSH implementations SHOULD only generate constraints for the changed values.
Cardinalities MUST follow rules of FHIR profiling, namely that the min
and max
cardinalities comply within the constraints of the parent.
For convenience and compactness, cardinality rules MAY be combined with flag rules via the following syntax:
* <element> {card} {flag}
* <element> {card} {flag1} {flag2} {flag3}...
Examples:
Set the cardinality of the subject
element to 1..1 (required, non-repeating):
* subject 1..1
Set the cardinality of the subject
element to 1..1 and declare it Must Support:
* subject 1..1 MS
Set the cardinality of a sub-element to 0..0 (not permitted):
* component.referenceRange 0..0
Require at least one category
without changing its upper bound:
* category 1..
Allow at most one category
without changing its lower bound:
* category ..1
Extensions are created by adding elements to extension arrays. Extension arrays are found at the root level of every resource, nested inside every element, and recursively inside each extension. The structure of extensions is defined by FHIR (see Extension element). Profiling extensions is discussed in Defining Extensions.
Extensions SHALL be specified using the contains
keyword. There are two types of extensions, standalone and inline:
The syntaxes to specify standalone extension(s) are:
* <extension> contains {Extension} named {name} {card} {flag(s)}
* <extension> contains
{Extension1} named {name1} {card} {flag(s)} and
{Extension2} named {name2} {card} {flag(s)} and
{Extension3} named {name3} {card} {flag(s)} ...
The syntaxes to define inline extension(s) are:
* <extension> contains {name} {card} {flag(s)}
* <extension> contains
{name1} {card} {flag(s)} and
{name2} {card} {flag(s)} and
{name3} {card} {flag(s)} ...
In these expressions, the names (name
, name1
, name2
, etc.) are new local names created by the rule author. They are used to refer to that extension in later rules. By convention, the local names SHOULD be lower camelCase. Implementers SHALL export these names as slice names in the generated StructureDefinition.
Note: Contains rules MAY also be applied to
modifierExtension
arrays by replacingextension
withmodifierExtension
in the above syntaxes.
Examples:
Add standalone FHIR extensions patient-disability and individual-genderIdentity to a profile of the Patient resource, using the canonical URLs for the extensions:
* extension contains http://hl7.org/fhir/StructureDefinition/patient-disability named disability 0..1 MS and http://hl7.org/fhir/StructureDefinition/individual-genderIdentity named genderIdentity 0..1 MS
The same statement, using aliases and whitespace flexibility for better readability:
Alias: $Disability = http://hl7.org/fhir/StructureDefinition/patient-disability
Alias: $GenderIdentity = http://hl7.org/fhir/StructureDefinition/individual-genderIdentity
// intervening lines not shown
* extension contains
$Disability named disability 0..1 MS and
$GenderIdentity named genderIdentity 0..1 MS
Add standalone FHIR modifier extension request-doNotPerform to a profile of the NutritionOrder resource, using an alias:
Alias: $DoNotPerform = http://hl7.org/fhir/StructureDefinition/request-doNotPerform
// intervening lines not shown
* modifierExtension contains $DoNotPerform named doNotPerform 0..1 MS
Add a standalone extension Laterality
, defined in the same FSH project, to a bodySite
attribute (second level extension):
* bodySite.extension contains Laterality named laterality 0..1
// intervening lines not shown
Extension: Laterality
Description: "Body side of a body location."
* value[x] only CodeableConcept
* value[x] from LateralityVS (required)
Show how the inline extensions defined in the US Core Race extension would be defined using FSH:
* extension contains
ombCategory 0..5 MS and
detailed 0..* and
text 1..1 MS
// rules defining the inline extensions would typically follow:
* extension[ombCategory].value[x] only Coding
* extension[ombCategory].value[x] from http://hl7.org/fhir/us/core/ValueSet/omb-race-category (required)
* extension[text].value[x] only string
// etc.
Slicing is an advanced, but necessary, feature of FHIR. It is helpful to have a basic understanding of slicing and discriminators before attempting slicing in FSH.
In FSH, slicing is addressed in three steps: (1) specify the slicing logic, (2) define the slices, and (3) constrain each slice's contents.
Note: The rules from each step MUST be sequentially ordered, i.e., step (1) slicing logic rules before step (2) slice definition rules before step (3) slice content rules.
To create slicings in FHIR, authors MUST specify a discriminator path, type, and rules. In addition, authors MAY optionally declare the slice as ordered or unordered (default: unordered), and/or provide a description. The meaning and allowable values SHALL be exactly as defined in FHIR.
The slicing logic parameters MUST be specified using caret paths on the element to be sliced, which is typically a multi-cardinality (array) element. The discriminator path SHALL identify the element used to distinguish each slice. The discriminator type SHALL determine how the slices are differentiated, e.g., by value, pattern, existence of the sliced element, datatype of sliced element, position of the sliced element (R5 and up), or profile conformance.
Example:
Provide slicing logic for slices on Observation.component
that are to be distinguished by their sub-element code
:
* component ^slicing.discriminator.type = #pattern
* component ^slicing.discriminator.path = "code"
* component ^slicing.rules = #open
* component ^slicing.ordered = false // can be omitted, since false is the default
* component ^slicing.description = "Slice based on the component.code pattern"
The second step in slicing is to populate the array that is to be sliced, using the contains
keyword. The syntaxes are very similar to contains rules for inline extensions:
* <array> contains {name} {card} {flag(s)}
* <array> contains
{name1} {card} {flag(s)} and
{name2} {card} {flag(s)} and
{name3} {card} {flag(s)} ...
In this pattern, <array>
is a path to the element that is to be sliced and MUST match the path on which the slicing rules were defined in step (1). The names (name
, name1
, etc.) are created by the rule author to describe the slice in the context of the profile. These names are used to refer to the slice in later rules. By convention, the slice names SHOULD be lower camelCase.
Each slice matches or constrains the datatype of the array it slices. In particular:
Observation.identifier
is sliced, each slice will have type Identifier or be constrained to a profile of the Identifier datatype.Observation.component
possess all the elements of Observation.component
(code
, value[x]
, dataAbsentReason
, etc.). Constraints MAY be applied to the slices.FSH implementations MUST add new slices to the StructureDefinition in the order in which they appear within the contains rule. When a FSH definition has multiple contains rules on the same path, these rules MUST be processed in the order in which they appear.
Examples:
Slice the Observation.component
array for blood pressure:
* component contains systolicBP 1..1 MS and diastolicBP 1..1 MS
Because FSH is white-space invariant, the previous example MAY be rewritten so the slices appear one-per-line for readability:
* component contains
systolicBP 1..1 MS and
diastolicBP 1..1 MS
Reslicing (slicing an existing slice) uses a similar syntax, but the left-hand side uses slice path syntax to refer to the slice that is being resliced:
* <array[{slice name}]> contains {name} {card} {flag(s)}
* <array[{slice name}]> contains
{name1} {card} {flag(s)} and
{name2} {card} {flag(s)} and
{name3} {card} {flag(s)} ...
Example:
In an Observation for Apgar score, reslice the Apgar respirationScore
component slice into one-, five-, and ten-minute scores:
* component contains
appearanceScore 0..3 and
pulseScore 0..3 and
grimaceScore 0..3 and
activityScore 0..3 and
respirationScore 0..3
* component[respirationScore] contains
oneMinuteScore 0..1 and
fiveMinuteScore 0..1 and
tenMinuteScore 0..1
The final step is to define the properties of each slice. FSH requires slice contents to be defined inline. The rule syntax is the same as constraining any other element, but the slice path syntax is used to specify the path:
* <array>[{slice name}].<element> {constraint}
The slice content rules MUST appear after the contains rule that creates the slices.
Example:
Constrain the content of the systolicBP
and diastolicBP
slices:
* component[systolicBP].code = $LNC#8480-6 // Systolic blood pressure
* component[systolicBP].value[x] only Quantity
* component[systolicBP].value[x] = $UCUM#mm[Hg] "mmHg"
* component[diastolicBP].code = $LNC#8462-4 // Diastolic blood pressure
* component[diastolicBP].value[x] only Quantity
* component[diastolicBP].value[x] = $UCUM#mm[Hg] "mmHg"
At minimum, each slice MUST be constrained such that it is uniquely identifiable via the discriminator (see Step 1). For example, if the discriminator path points to an element that is a CodeableConcept, and it discriminates by value or pattern, then each slice MUST constrain that CodeableConcept using an assignment rule or binding rule that uniquely distinguishes it from the other slices.
Complete Slicing Example:
Profile: TumorSize
Parent: Observation
Id: example-tumor-size
Title: "Tumor Size"
Description: "Records the one to three dimensions of a tumor"
* code = $LNC#21889-1 //"Size Tumor"
// other rules omitted
* component ^slicing.discriminator.type = #pattern
* component ^slicing.discriminator.path = "code"
* component ^slicing.rules = #open
* component ^slicing.description = "Slice based on the component.code pattern"
// Contains rule
* component contains tumorLongestDimension 1..1 and tumorOtherDimension 0..2
// Set properties of each slice
* component[tumorLongestDimension] ^short = "Longest tumor dimension"
* component[tumorLongestDimension] ^definition = "The longest tumor dimension in cm or mm."
* component[tumorLongestDimension].code = $LNC#33728-7 // "Size.maximum dimension in Tumor"
* component[tumorLongestDimension].value[x] only Quantity
* component[tumorLongestDimension].value[x] from TumorSizeUnitsVS (required) // value set defined elsewhere
* component[tumorOtherDimension] ^short = "Other tumor dimension(s)"
* component[tumorOtherDimension] ^definition = "The second or third tumor dimension in cm or mm."
* component[tumorOtherDimension] ^comment = "Additional tumor dimensions should be ordered from largest to smallest."
* component[tumorOtherDimension].code = $LNC#33729-5 // "Size additional dimension in Tumor"
* component[tumorOtherDimension].value[x] only Quantity
* component[tumorOtherDimension].value[x] from TumorSizeUnitsVS (required)
Exclude rules are used to remove codes from value sets. Exclude rules SHALL appear only in ValueSet items. For more details on exclude rules, see Defining Value Sets.
Flags are a set of information about the element that impacts how implementers handle them. The flags defined in FHIR, and the symbols used to describe them, are as follows:
FHIR Flag | FSH Flag | Meaning |
---|---|---|
S | MS |
Must Support |
Σ | SU |
Include in summary |
?! | ?! |
Modifier |
N | N |
Normative element |
TU | TU |
Trial use element |
D | D |
Draft element |
FHIR also defines the flags I and NE, representing elements affected by constraints, and elements that cannot have extensions, respectively. These flags are not supported in flag syntax, since the I flag is determined by the presence of invariants, and NE flags apply only to infrastructural elements in base resources.
The following syntaxes MAY be used to assign flags:
* <element> {flag}
* <element> {flag1} {flag2}...
* <element1> and <element2> and <element3> ... {flag}
* <element1> and <element2> and <element3> ... {flag1} {flag2}...
Note: When multiple flags are specified, they MUST be separated with whitespace(s). When multiple element paths are specified, they MUST be separated by
and
.
Examples:
Declare communication
to be a Must Support and Summary element:
* communication MS SU
Declare a list of elements and nested elements to be Must Support:
* identifier and identifier.system and identifier.value and name and name.family MS
Include rules are used to add codes to value sets. Include rules SHALL appear only in ValueSet items. For more details on include rules, see Defining Value Sets.
Rule sets are reusable groups of rules that are defined independently of other items. An insert rule is used to add the contents of a rule set to an item:
* insert {RuleSet}({parameters})
The rules in the named rule set are interpreted as if they were copied and pasted in the designated location (with parameter placeholders replaced as described below).
Each rule in the rule set MUST be compatible with the item where the rule set is inserted, in the sense that all the rules defined in the rule set apply to elements actually present in the target. Implementations SHOULD check the legality of a rule set at compile time. If a particular rule from a rule set does not match an element in the target, that rule MUST NOT be applied, and an error SHOULD be emitted. It is up to implementations if other valid rules from the rule set are applied.
Insert a simple rule set by using the name of the rule set:
* insert {RuleSet}
Examples:
Insert the rule set named RuleSet1 into a profile:
Profile: MyPatientProfile
Parent: Patient
Id: my-patient-profile
Title: "My Patient Profile"
Description: "An example patient profile."
* insert RuleSet1
* deceased[x] only boolean
// More profile rules
This is equivalent to the following:
Profile: MyPatientProfile
Parent: Patient
Id: my-patient-profile
Title: "My Patient Profile"
Description: "An example patient profile."
* ^status = #draft
* ^experimental = true
* ^publisher = "Elbonian Medical Society"
* deceased[x] only boolean
// More profile rules
Use rule sets to define two different national profiles, using a common clinical profile:
Profile: USBreastRadiologyObservationProfile
Parent: BreastRadiologyObservationProfile
Id: us-breast-radiology
Title: "US Breast Radiology Profile"
Description: "Breast Radiology Profile with US-specific constraints"
* insert USObservationRuleSet
Profile: FranceBreastRadiologyObservationProfile
Parent: BreastRadiologyObservationProfile
Id: france-breast-radiology
Title: "France Breast Radiology Profile"
Description: "Breast Radiology Profile with France-specific constraints"
* insert FranceObservationRuleSet
To insert a parameterized rule set, use the rule set name with a list of one or more parameter values:
* insert {RuleSet}(value1, value2, value3...)
As indicated, the list of values MUST be enclosed with parentheses ()
and separated by commas ,
. To put literal )
or ,
characters inside values, authors MUST escape them with a backslash: \)
and \,
, respectively. White space separating values is OPTIONAL, and SHALL be removed before the value is applied to the rule set definition.
TU
Alternatively, a parameter value MAY be surrounded by double square brackets [[
]]
. Literal )
and ,
characters within the double square brackets SHOULD NOT be escaped with a backslash*. Use of double brackets makes sense when a parameter requires multiple escape characters.
* The only exception to this is when the author wants to include ]],
or ]])
as part of the parameter value. In this case, the )
or ,
following the ]]
MUST be escaped with a backslash. For example, to include ]],
as part of a parameter value within double square brackets, use ]]\,
. This MUST be done even if there is whitespace between the ]]
and ,
or )
. For example, to include ]] )
as part of a parameter within double square brackets, use ]] \)
. Additionally, note that the full value MUST be surrounded with double square brackets in order for this type of processing to occur.
The values provided SHALL be substituted into the named rule set to create the rules that will be applied. The number of values provided MUST match the number of parameters specified in the rule set definition.
Any FSH syntax errors that arise as a result of the value substitution SHALL be handled the same way as FSH syntax errors in the declaration of a rule set without parameters. FSH implementers MAY perform the value substitution without checking the types of the values being substituted or the semantic validity of the resulting rules. Any invalid rules resulting from inserting a parameterized rule set SHOULD be detected at the same time as invalid rules resulting from inserting a simple rule set.
Examples:
Use the parameterized rule set, Name
, to populate an instance of Patient with multiple names (note that the curly brackets in this example are literal, not syntax expressions):
RuleSet: Name(first, last)
* name[+].given = "{first}"
* name[=].family = "{last}"
Instance: MrSmith
InstanceOf: Patient
Title: "Mr. Smith"
Description: "The patient Robert Smith"
// some rules
* insert Name(Robert, Smith)
* insert Name(Rob, Smith)
* insert Name(Bob, Smith)
// more rules
When the rule set is expanded and soft indices are resolved, this is equivalent to:
Instance: MrSmith
InstanceOf: Patient
Title: "Mr. Smith"
Description: "The patient Robert Smith"
// some rules
* name[0].given = "Robert"
* name[0].family = "Smith"
* name[1].given = "Rob"
* name[1].family = "Smith"
* name[2].given = "Bob"
* name[2].family = "Smith"
// more rules
Use the parameterized rule set, Phone
, to add a phone number to an instance of Organization (note the use of backslash to escape a closing parenthesis):
RuleSet: Phone(value)
* telecom[+].system = #phone
* telecom[=].value = "{value}"
Instance: AcmeOrganization
InstanceOf: Organization
Title: "Acme Organization"
Description: "The Acme Organization"
// some rules
* insert Phone( (800\)555-1234 )
// more rules
When the rule set is expanded and soft indices are resolved, this is equivalent to:
Instance: AcmeOrganization
InstanceOf: Organization
Title: "Acme Organization"
Description: "The Acme Organization"
// some rules
* telecom[0].system = #phone
* telecom[0].value = "(800)555-1234"
// more rules
TU
Use the parameterized rule set, AddVariableToTestScript
, to add variable definitions to an instance of TestScript (note the use of double brackets to avoid the need to escape closing parentheses and commas):
RuleSet: AddVariableToTestScript(name, expression)
* variable[+].name = "{name}"
* variable[=].expression = "{expression}"
Instance: MyTest
InstanceOf: TestScript
Title: "My Test Script"
Description: "A small test with a few FHIRPath expressions"
// some rules
* insert AddVariableToTestScript( firstObservation, [[component.all(valueSampledData.exists())]] )
* insert AddVariableToTestScript (testResponse, [[resource.repeat(item).answer.value.extension.value.aggregate($this+$total,0)]])
// more rules
When the rule set is expanded and soft indices are resolved, this is equivalent to:
Instance: MyTest
InstanceOf: TestScript
Title: "My Test Script"
Description: "A small test with a few FHIRPath expressions"
// some rules
* variable[0].name = "firstObservation"
* variable[0].expression = "component.all(valueSampledData.exists())"
* variable[1].name = "testResponse"
* variable[1].expression = "resource.repeat(item).answer.value.extension.value.aggregate($this+$total,0)"
// more rules
Rule sets MAY be inserted in the context of a path. The context MAY be specified by giving the path prior to the insert rule:
* <element> insert {RuleSet}(value1, value2, value3...)
Alternately, the context MAY be specified by indenting the insert rule under another rule that provides a path context (see indented rules). The path context from the rule which the insert rule is indented below SHALL be applied to all rules being inserted.
When the rule set is expanded, the path of the element SHALL be prepended to the path of all rules in the rule set.
When defining a Code System, rule sets MAY be inserted in the context of a concept. The context MAY be specified by giving the concept (or hierarchy of concepts, for child codes) prior to the insert rule or by indenting it below another concept:
* <concept> insert {RuleSet}(value1, value2, value3...)
Examples:
Insert a rule set into a profile specifying an element:
RuleSet: NameRules
* family MS
* given MS
Profile: MyPatientProfile
Parent: Patient
// skip some keywords and rules
* name insert NameRules
* deceased[x] only boolean
// More profile rules
An equivalent way to write the profile is:
Profile: MyPatientProfile
Parent: Patient
// skip some keywords and rules
* name
* insert NameRules
* deceased[x] only boolean
// More profile rules
Both of the above are equivalent to:
Profile: MyPatientProfile
Parent: Patient
// skip some keywords and rules
* name.family MS
* name.given MS
* deceased[x] only boolean
// More profile rules
Insert a rule set into a code system specifying a concept:
RuleSet: DesignationRules
* ^designation[0].use = $SCT#900000000000003001 "Fully specified name"
* ^designation[0].language = #en
CodeSystem: MyCodeSystem
// skip some keywords and rules
* #code-one "Code one"
* #code-one insert DesignationRules
* #code-one #child-code "Child code"
* #code-one #child-code insert DesignationRules
// more code system rules
An equivalent way to write the code system is:
CodeSystem: MyCodeSystem
// skip some keywords and rules
* #code-one "Code one"
* insert DesignationRules
* #child-code "Child code"
* insert DesignationRules
// more code system rules
Both of the above are equivalent to:
CodeSystem: MyCodeSystem
// skip some keywords and rules
* #code-one "Code one"
* #code-one ^designation[0].use = $SCT#900000000000003001 "Fully specified name"
* #code-one ^designation[0].language = #en
* #code-one #child-code "Child code"
* #code-one #child-code ^designation[0].use = $SCT#900000000000003001 "Fully specified name"
* #code-one #child-code ^designation[0].language = #en
// more code system rules
Local codes rules are used to define codes in code systems. Local code rules SHALL appear only in CodeSystem items. For more details on local code rules, see Defining Code Systems.
Mapping rules are used to define relationships between different specifications. Mapping rules SHALL appear only in Mapping items. For more details on mapping rules, see Defining Mappings.
Invariants are constraints that apply to one or more values in instances, expressed as FHIRPath or XPath expressions. One or more invariants MAY be applied to an instance as a whole or a single element. The syntax for applying invariants in profiles is:
* obeys {Invariant}
* obeys {Invariant1} and {Invariant2}...
* <element> obeys {Invariant}
* <element> obeys {Invariant1} and {Invariant2}...
The first case applies the invariant to the profile as a whole. The second case applies multiple invariants to the profile as a whole. The third case applies the invariant to a single element, and the fourth case applies multiple invariants to a single element.
The referenced invariant and its properties MUST be declared somewhere within the same FSH project, using the Invariant
keyword. See Defining Invariants.
Examples:
Assign invariant to US Core Implantable Device (invariant applies to profile as a whole):
* obeys us-core-9
Assign invariant to Patient.name
in US Core Patient:
* name obeys us-core-8
Path rules are used to set the context for subsequent indented rules.
* <element>
TU
Path rules MAY also be used to indicate the order for slices to appear in an Instance and to include optional fixed values of a path in an Instance. Path rules have no impact on all other FSH entity types; the only purpose of the path rule on those entities is to set context.
Examples:
Set a context of name
for subsequent rules:
* name
* given MS
* family MS
TU
Indicate the order for slices to appear in an Instance:
Given a profile that has a required lab
slice on category
, such as:
* category contains lab 1..1
* category[lab] = $OBSCAT#laboratory
an Instance of that profile can specify that the lab
slice MUST come before other values on category
by including the following path rule before other rules:
* category[lab]
* category[+] = $EX#example
Include optional fixed values of a path in an Instance:
Given a profile where name.family
is optional and has a fixed value, such as:
* name.family = "Smith"
an Instance of that profile can include the fixed value "Smith" by including the following path rule:
* name.family
Given a profile with an optional element that has child elements with required fixed values, such as:
* name 0..*
* name.family 1..1
* name.family = "Smith"
an Instance of that profile can include a name with the fixed value "Smith" by including the following path rule:
* name
FSH rules MAY be used to restrict the datatype(s) of an element. The syntaxes are:
* <element> only {datatype}
* <element> only {datatype1} or {datatype2} or {datatype3}...
* <element> only Reference({Resource/Profile})
* <element> only Reference({Resource/Profile1} or {Resource/Profile2} or {Resource/Profile3}...)
* <element> only Canonical({Resource/Profile})
* <element> only Canonical({Resource/Profile1} or {Resource/Profile2} or {Resource/Profile3}...)
TU
FSH rules MAY also be used to restrict the target types of CodeableReference elements. The syntaxes are:
* <element> only CodeableReference({Resource/Profile})
* <element> only CodeableReference({Resource/Profile1} or {Resource/Profile2} or {Resource/Profile3}...)
Certain elements in FHIR offer a choice of datatypes using the [x]
syntax. Choices also frequently appear in references. For example, Condition.recorder
has the choice Reference(Practitioner or PractitionerRole or Patient or RelatedPerson). In both cases, choices MAY be restricted in two ways: reducing the number or choices, and/or substituting a more restrictive datatype or profile for one of the choices appearing in the parent profile or resource. In some cases, the right-hand side of a type rule MAY have a combination of datatype, Reference, Canonical, and TUCodeableReference targets.
Following standard profiling rules established in FHIR, the datatype(s) in a type rule MUST always be more restrictive than the original datatype. For example, if the parent datatype is Quantity, it MAY be replaced by SimpleQuantity, since SimpleQuantity is a profile on Quantity (hence more restrictive than Quantity itself), but MUST NOT be replaced with Ratio, because Ratio is not a type of Quantity. Similarly, Condition.subject
, defined as Reference(Patient or Group), MAY be constrained to Reference(Patient), Reference(Group), or Reference(us-core-patient), but MUST NOT be restricted to Reference(RelatedPerson), since that is neither a Patient nor a Group.
Examples:
Restrict a Quantity type to SimpleQuantity:
* valueQuantity only SimpleQuantity
Condition.onset[x]
is a choice of dateTime, Age, Period, Range or string. To restrict onset[x]
to dateTime:
* onset[x] only dateTime
Restrict onset[x]
to either Period or Range:
* onset[x] only Period or Range
Restrict onset[x]
to Age, AgeRange, or DateRange, assuming AgeRange and DateRange are profiles of FHIR's Range datatype (thus permissible restrictions on Range):
* onset[x] only Age or AgeRange or DateRange
TU
Restrict value[x]
to the integer64 type (note: this datatype was introduced in FHIR R5):
* value[x] only integer64
Restrict Observation.performer
(nominally Reference(Practitioner | PractitionerRole | Organization | CareTeam | Patient | RelatedPerson)) to allow only Practitioner:
* performer only Reference(Practitioner)
Restrict performer
to either a Practitioner or a PractitionerRole:
* performer only Reference(Practitioner or PractitionerRole)
Restrict performer
to PrimaryCarePhysician or EmergencyRoomPhysician (assuming these are profiles on Practitioner):
* performer only Reference(PrimaryCarePhysician or EmergencyRoomPhysician)
Restrict the Practitioner choice of performer
to a PrimaryCarePhysician, without restricting other choices. Because the path specifically calls out the Practitioner choice, the result is that performer
can reference a Practitioner resource that validates against the PrimaryCareProvider profile or any of the other choices (PractitionerRole, Organization, CareTeam, Patient, and RelatedPerson):
* performer[Practitioner] only Reference(PrimaryCareProvider)
Assuming that LiteralReference is a profile on Reference, restrict the performer
Reference datatype to this LiteralReference profile and its target types to Practitioner or PractitionerRole. Note that the first rule restricts the Reference datatype and the second rule restricts the types it MAY refer to:
* performer only LiteralReference
* performer only Reference(Practitioner or PractitionerRole)
Restrict PlanDefinition.action.definition[x]
, nominally a choice of uri or canonical(ActivityDefinition | PlanDefinition | Questionnaire), to allow only the canonical of an ActivityDefinition:
* action.definition[x] only Canonical(ActivityDefinition)
Restrict PlanDefinition.action.definition[x]
to a canonical of either an ActivityDefinition or a PlanDefinition:
* action.definition[x] only Canonical(ActivityDefinition or PlanDefinition)
TU
Restrict MedicationRequest.reason
, a choice of CodeableReference(Condition | Observation), to allow only a CodeableReference to an Observation
* reason only CodeableReference(Observation)
Restrict CarePlan.activity.performedActivity
to a CodeableReference of an Encounter or a Procedure:
* activity.performedActivity only CodeableReference(Encounter or Procedure)
Abbreviation | Description |
---|---|
ANTLR | ANother Tool for Language Recognition |
D | Flag denoting draft status |
FHIR | Fast Healthcare Interoperability Resources |
FSH | FHIR Shorthand |
IG | Implementation Guide |
JSON | JavaScript Object Notation |
$LNC | Common FSH alias for LOINC code system (http://loinc.org) |
LOINC | Logical Observation Identifiers Names and Codes |
NPI | National Provider Identifier (US) |
N | Flag denoting normative element |
MS | Flag denoting a Must Support element |
OID | Object Identifier |
$SCT | Common FSH alias for SNOMED Clinical Terms |
SU | Flag denoting "include in summary" |
TU | Flag denoting trial use element |
UCUM | Unified Code for Units of Measure |
$UCUM | Common FSH alias for Unified Code for Units of Measure |
URL | Uniform Resource Locator |
XML | Extensible Markup Language |
SUSHI provides an implementation of a FSH language parser described in ANTLR v4. It includes elements of the FSH language marked as TU. The entity names defined in the grammar may not correspond to those used in the language specification. If there is a conflict between the language specification and the grammar defined in this Appendix, the language specification SHALL take precedence. This grammar implementation is provided for informational purposes and is not normative.
The parser grammar corresponding to this version of the specification can be found here and here.
The lexer grammar corresponding to this version of the specification can be found here and here.