FHIRPath (Continuous Build)
FHIRPath is a path based navigation and extraction language, somewhat like XPath. Operations are expressed in terms of the logical content of hierarchical data models, and support traversal, selection and filtering of data. Its design was influenced by the needs for path navigation, selection and formulation of invariants in both HL7 Fast Healthcare Interoperability Resources (FHIR) and HL7 Clinical Quality Language (CQL).
Looking for implementations? See FHIRPath Implementations on the HL7 confluence{:target="_blank"}
Note: The following sections of this specification have not received significant implementation experience and are marked for Standard for Trial Use (STU):
- Aggregates
- Literals - Long
- Conversions - toLong
- Functions - repeatAll
- Functions - sort
- Functions - coalesce
- Functions - String (lastIndexOf)
- Functions - String (matchesFull)
- Functions - String (trim, split, join)
- Functions - String (encode, decode, escape, unescape)
- Functions - Math
- Functions - Utility (defineVariable, lowBoundary, highBoundary)
- Functions - Utility (precision)
- Functions - Extract Date/DateTime/Time components
- Functions - Date and Time Interval Functions (duration, difference)
- Operations - Comparison (comparable)
- Instance Selector/Object Creation
- Types - Reflection
This section has undergone extensive clarification:
In addition, the appendices are included as additional documentation and are informative content. {: .stu-note }
Background
In Information Systems in general, and Healthcare Information Systems in particular, the need for formal representation of logic is both pervasive and critical. From low-level technical specifications, through intermediate logical architectures, up to the high-level conceptual descriptions of requirements and behavior, the ability to formally represent knowledge in terms of expressions and information models is essential to the specification and implementation of these systems.
Requirements
Of particular importance is the ability to easily and precisely express conditions of basic logic, such as those found in requirements constraints (e.g. Patients must have a name), decision support (e.g. if the patient has diabetes and has not had a recent comprehensive foot exam), cohort definitions (e.g. All male patients aged 60-75), protocol descriptions (e.g. if the specimen has tested positive for the presence of sodium), and numerous other environments.
Precisely because the need for such expressions is so pervasive, there is no shortage of existing languages for representing them. However, these languages tend to be tightly coupled to the data structures, and even the information models on which they operate, XPath being a typical example. To ensure that the knowledge captured by the representation of these expressions can survive technological drift, a representation that can be used independent of any underlying physical implementation is required.
Languages meeting these additional requirements also exist, such as Object Constraint Language (OCL), Java, JavaScript, C#, and others. However, these languages are both tightly coupled to the platforms in which they operate, and, because they are general-purpose development languages, come with much heavier tooling and technology dependencies than is warranted or desirable. Even constraining one of these grammars would be insufficient, resulting in the need to extend, defeating the purpose of basing it on an existing language in the first place.
Given these constraints, and the lack of a specific language that meets all of these requirements, there is a need for a simple, lightweight, platform- and structure-independent graph traversal language. FHIRPath meets these requirements, and can be used within various environments to provide for simple but effective formal representation of expressions.
Features
- Graph-traversal: FHIRPath is a graph-traversal language; authors can clearly and concisely express graph traversal on hierarchical information models (e.g. Health Level 7 - Version 3 (HL7 V3), Fast Healthcare Interoperability Resources (FHIR), virtual Medical Record (vMR), Clinical Information Modeling Initiative (CIMI), and Quality Data Model (QDM)).
- Fluent: FHIRPath has a syntax based on the Fluent Interface pattern
- Collection-centric: FHIRPath deals with all values as collections, allowing it to easily deal with information models with repeating elements.
- Platform-independent: FHIRPath is a conceptual and logical specification that can be implemented in any platform.
- Model-independent: FHIRPath deals with data as an abstract model, allowing it to be used with any information model.
Usage
In Fast Healthcare Interoperability Resources (FHIR), FHIRPath is used within the specification to provide formal definitions for conditions such as validation invariants, search parameter paths, etc. Within Clinical Quality Language (CQL), FHIRPath is used to simplify graph-traversal for hierarchical information models.
In both FHIR and CQL, the model independence of FHIRPath means that expressions can be written that deal with the contents of the resources and data types as described in the Logical views, or the UML diagrams, rather than against the physical representation of those resources. JSON and XML specific features are not visible to the FHIRPath language (such as comments and the split representation of primitives (i.e. value[x])).
The expressions can in theory be converted to equivalent expressions in XPath, OCL, or another similarly expressive language.
FHIRPath can be used against many other graphs as well. For example, Use of FHIRPath on HL7 Version 2 messages describes how FHIRPath is used in HL7 V2.
Conventions
Throughout this documentation, monospace font is used to delineate expressions of FHIRPath.
Optional parameters to functions are enclosed in square brackets in the definition of a function. Note that the brackets are only used to indicate optionality in the signature, they are not part of the actual syntax of FHIRPath.
All operations and functions return a collection, but if the operation or function will always produce a collection containing a single item of a predefined type, the description of the operation or function will specify its output type explicitly, instead of just stating collection, e.g. all(...) : Boolean
Throughout this specification, formatting patterns for Date, Time, and DateTime values are described using an informal description with the following markers:
yyyy{:.formatted} - A full four digit year (0001..9999), padded with leading zeroes if necessaryMM{:.formatted} - A full two digit month value (01..12), padded with leading zeroes if necessaryDD{:.formatted} - A full two digit day value (01..31), padded with leading zeroes if necessaryhh{:.formatted} - A full two digit hour value (00..24), padded with leading zeroes if necessarymm{:.formatted} - A full two digit minute value (00..59), padded with leading zeroes if necessaryss{:.formatted} - A full two digit second value (00..59), padded with leading zeroes if necessaryfff{:.formatted} - A fractional millisecond value (0..999)
and formatting patterns for numeric types are described using an informal description with these markers:
0{:.formatted} - Any digit MUST appear at this location in the format string#{:.formatted} - Any digits may appear at this location in the format string?{:.formatted} - The immediately preceding pattern is optional( ){:.formatted} - Used to group patterns« »{:.formatted} - Used indicate some specific named content is included. e.g'«unit»'{:.formatted} to indicate that a quantities unit would be surrounded by single quotes.|{:.formatted} - Used to combine choices of patterns (e.g.+|-{:.formatted} means a+or-will appear at this location)
Any other character in a format string indicates that the character must appear at that location (unless it has an optional indicator, or is part of an optional group), noting that named content inside « » isn't explicit text.
These formatting patterns are set in bold{:.formatted} to distinguish them typographically from literals or code and to make clear that they are not intended to be formally interpreted as regex patterns.
Conformance Language
This specification uses the conformance verbs SHALL, MUST, SHOULD, and MAY as defined in RFC 2119. Unlike RFC 2119, however, this specification allows that different applications might not be able to interoperate because of how they use optional features. In particular:
- SHALL/MUST: An absolute requirement for all implementations
- SHALL/MUST NOT: An absolute prohibition against inclusion for all implementations
- SHOULD/SHOULD NOT: A best practice or recommendation to be considered by implementers within the context of their particular implementation; there may be valid reasons to ignore an item, but the full implications must be understood and carefully weighed before choosing a different course
- MAY: This is truly optional language for an implementation; can be included or omitted as the implementer decides with no implications.
Credits
This implementation guide represents significant person-hours of discussion, development work, and testing. The following are some of the key participants in the work, but many more have assisted through connectathons testing, asking questions and participating in conference calls.
| Role | Contributors |
|---|---|
| Editors: | Bryn Rhodes (Smile Digital Health)<br/>Grahame Grieve (Health Intersections)<br/>Ewout Kramer (Firely)<br/>Brian Postlethwaite (Microsoft Research) |
| Key Contributors: | Paul Lynch (U.S. National Library of Medicine - NLM)<br/> Bas van den Heuvel (Philips Healthcare)<br/> Chris Moesel (MITRE)<br/> Nikolai Ryzhikov (Health Samurai)<br/> Brian Kaney (Vermonster)<br/> Yury Sedinkin (US NLM) |
This list inevitably fails to mention many of the individuals who contributed their time and energy to developing this specification and making it better. Thanks to all of you!
Navigation model
FHIRPath navigates and selects nodes from a tree that abstracts away and is independent of the actual underlying implementation of the source against which the FHIRPath query is run. This way, FHIRPath can be used on in-memory Plain Old Java Objects (POJOs), XML data or any other physical representation, so long as that representation can be viewed as classes that have properties. In somewhat more formal terms, FHIRPath operates on a directed acyclic graph of classes as defined by a Meta Object Facility (MOF)-equivalent [MOF] type system. In this specification, the structures on which FHIRPath operates are referred to as the Object Model.
Data are represented as a tree of labelled nodes, where each node may optionally carry a primitive value and have child nodes. Nodes need not have a unique label, and leaf nodes must carry a primitive value. For example, a (partial) representation of a FHIR Patient resource in this model looks like this:
{: height="375px" width="500px" style="float: unset; margin-bottom:0;" }
The diagram shows a tree with a repeating name node, representing repeating elements of the FHIR Object Model. Leaf nodes such as use and family carry a (string) value. It is also possible for internal nodes to carry a value, as is the case for the node labelled active: this allows the tree to represent FHIR "primitives", which may still have child extension data.
FHIRPath expressions are then evaluated with respect to a specific instance, such as the Patient one described above. This instance is referred to as the context (also called the root) and paths within the expression are evaluated in terms of this instance.
Path selection
FHIRPath allows navigation through the tree by composing a path of concatenated labels, e.g.
name.given
This would result in a collection of nodes, one with the value 'Wouter' and one with the value 'Gert'. In fact, each step in such a path results in a collection of nodes by selecting nodes with the given label from the step before it. The input collection at the beginning of the evaluation contained all elements from Patient, and the path name selected just those named name. Since the name element repeats, the next step given along the path, will contain all nodes labeled given from all nodes name in the preceding step.
The path may start with the type of the root node (which otherwise does not have a name), but this is optional. To illustrate this point, the path name.given above can be evaluated as an expression on a set of data of any type. However the expression may be prefixed with the name of the type of the root:
Patient.name.given
The two expressions have the same outcome, but when evaluating the second, the evaluation will only produce results when used on data of type Patient.
When resolving an identifier that is also the root of a FHIRPath expression, it is resolved as a type name first. If it resolves to a type and that type is the type of the context (or a supertype), then the evaluation proceeds with the context unchanged, i.e. in the example above proceeds to evaluate the name element.
Otherwise the identifier is resolved as a path on the context, which if not found returns an empty collection.
This could also be written using ofType(), which would have the same behaviour:
ofType(Patient).name.given
Syntactically, FHIRPath defines identifiers as any sequence of characters consisting only of letters, digits, and underscores, beginning with a letter or underscore. Paths may use other characters by using delimited identifiers - surrounding with backticks and using FHIRPath escaping as needed. This approach can also be used to encode nodes with names that are keywords. e.g.:
Message.`PID-1` // subtraction operator as a part of an element name
`as` as string // an element name that is also a fhirpath keyword
Collections
Collections are fundamental to FHIRPath, in that the result of every expression is a collection, even if that expression only results in a single item. This approach allows paths to be specified without having to care about the cardinality of any particular element, and is therefore ideally suited to graph traversal.
Within FHIRPath, a collection is:
- Ordered - The order of items in the collection is important and is preserved through operations as much as possible. Operators and functions that do not preserve order will note that in their documentation.
- Non-Unique - Duplicate values are allowed within a collection. Some operations and functions, such as
distinct()and the union operator|produce collections of unique values, but in general, duplicate values are allowed. - Indexed - Each item in a collection can be addressed by its index, i.e. ordinal position within the collection (e.g.
a[2]). - Unless specified otherwise by the underlying Object Model, the first item in a collection has index 0. Note that if the underlying model specifies that a collection is 1-based (the only reasonable alternative to 0-based collections), any collections generated from operations on the 1-based list are 0-based.
- Countable - The number of items in a given collection can always be determined using the
count()function
Note that the outcome of functions like children() and descendants() cannot be assumed to be in any meaningful order, and first(), last(), tail(), skip() and take() should not be used on collections derived from these paths. Note that some implementations may follow the logical order implied by the object model, and some may not, and some may be different depending on the underlying source. Implementations may decide to return an error if an attempt is made to perform an order-dependent operation on a list whose order is undefined.
Paths and polymorphic items
In the underlying representation of data, nodes may be typed and represent polymorphic items. Paths may either ignore the type of a node, and continue along the path or may be explicit about the expected node and filter the set of nodes by type before navigating down child nodes:
Observation.value.unit // all kinds of value
Observation.value.ofType(Quantity).unit // only values that are of type Quantity
The is operator can be used to determine whether or not a given value is of a given type:
Observation.value is Quantity // returns true if the value is of type Quantity
The as operator can be used to treat a value as a specific type:
Observation.value as Quantity // returns value as a Quantity if it is of type Quantity, and an empty result otherwise
The list of available types that can be passed as an argument to the ofType() function and is and as operators is determined by the underlying object model. Within FHIRPath, they are just identifiers, either delimited or simple.
Expressions
FHIRPath expressions can consist of paths, literals, operators, and function invocations. These can be chained together, so that the output of one operation or function is the input to the next. This is the core of the fluent [Fluent] syntactic style and allows complex paths and expressions to be built up from simpler components.
Literals
In addition to paths, FHIRPath expressions may contain literals, operators, and function invocations.
Examples of the supported FHIRPath literals:
Boolean: true, false
String: 'test string', 'urn:oid:3.4.5.6.7.8'
Integer: 0, 45
Long: 0L, 45L // Long is defined as STU
Decimal: 0.0, 3.14159265
Date: @2015-02-04 (@ followed by ISO8601 compliant date)
DateTime: @2015-02-04T14:34:28+09:00 (@ followed by ISO8601 compliant date/time)
Time: @T14:34:28 (@ followed by ISO8601 compliant time beginning with T, no timezone offset)
Quantity: 10 'mg', 4 days
For each type of literal, FHIRPath defines a named system type to allow operations and functions to be defined, as well as an ultimate root type, System.Any. For example, the multiplication operator (*) is defined for the numeric types Integer and Decimal, as well as the Quantity type. See the discussion on Models for a more detailed discussion of how these types are used within evaluation contexts.
Boolean
The Boolean type represents the logical Boolean values true and false. These values are used as the result of comparisons, and can be combined using logical operators such as and and or.
true
false
String
The String type represents string values up to 2<sup>31</sup>-1 characters in length and is UTF-8 encoded. String literals are surrounded by single-quotes and may use \-escapes to escape quotes and represent Unicode characters:
| Escape | Character |
|---|---|
\' | Single-quote |
\" | Double-quote |
\` | Backtick |
\r | Carriage Return |
\n | Line Feed |
\t | Tab |
\f | Form Feed |
\\ | Backslash |
\uXXXX | Unicode character, where XXXX is the hexadecimal representation of the character |
| {: .grid} |
No other escape sequences besides those listed above are recognized.
Note that Unicode is supported in both string literals and delimited Identifiers.
Note: The UTF-8 encoding is consistent with XML and JSON specifications, as well as the base FHIR specification.
'test string'
'urn:oid:3.4.5.6.7.8'
If a \ is used at the beginning of a non-escape sequence, it will be ignored and will not appear in the sequence.
define TestEscape1: '\p' // 'p'
define TestEscape2: '\\p' // '\p'
define TestEscape3: '\3' // '3'
define TestEscape4: '\u005' // 'u005'
define TestEscape5: '\' // ''
Integer
The Integer type represents whole numbers in the range -2<sup>31</sup> to 2<sup>31</sup>-1.
0
45
-5
Note that the minus sign (
-) in the representation of a negative integer is not part of the literal, it is the unary negation operator defined as part of FHIRPath syntax.
Long
{:.stu}
Note: The contents of this section are Standard for Trial Use (STU) {: .stu-note }
The Long type represents whole numbers in the range -2<sup>63</sup> to 2<sup>63</sup>-1.
{:.stu}
0L
45L
-5L
{:.stu}
Decimal
The Decimal type represents real values in the range (-10<sup>28</sup>+1)/10<sup>8</sup> to (10<sup>28</sup>-1)/10<sup>8</sup> with a step size of 10<sup>-8</sup>. This range is defined based on a survey of decimal-value implementations and is based on the most useful lowest common denominator. Implementations can provide support for larger decimals and higher precision, but must provide at least the range and precision defined here. In addition, implementations should use fixed-precision decimal formats to ensure that decimal values are accurately represented.
0.0
3.14159265
Decimal literals cannot use exponential notation. There is enough additional complexity associated with enabling exponential notation that this is outside the scope of what FHIRPath is intended to support (namely graph traversal).
Date
The Date type represents date and partial date values in the range @0001-01-01 to @9999-12-31 with a 1 day step size.
The Date literal is a subset of [ISO8601]:
- A date literal begins with an
@ - It uses the
yyyy-MM-DD{:.formatted} format, though month and day parts are optional, and a separator is required between provided components - Week dates and ordinal dates are not allowed
- Years must be present (e.g.
@-10-20is not a valid Date in FHIRPath) - Months must be present if a day is present
- To specify a date and time together, see the description of
DateTimebelow
The following examples illustrate the use of the Date literal:
@2014-01-25
@2014-01
@2014
Consult the formal grammar for more details.
Time
The Time type represents time-of-day and partial time-of-day values in the range @T00:00:00.000 to @T23:59:59.999 with a step size of 1 millisecond. This range is defined based on a survey of time implementations and is based on the most useful lowest common denominator. Implementations can provide support for higher precision, but must provide at least the range and precision defined here. Time values in FHIRPath do not have a timezone or timezone offset.
The Time literal uses a subset of [ISO8601]:
- A time begins with a
@T - It uses the
Thh:mm:ss.fff{:.formatted} format
The following examples illustrate the use of the Time literal:
@T12:00
@T14:30:14.559
Consult the formal grammar for more details.
DateTime
The DateTime type represents date/time and partial date/time values in the range @0001-01-01T00:00:00.000 to @9999-12-31T23:59:59.999 with a 1 millisecond step size. This range is defined based on a survey of datetime implementations and is based on the most useful lowest common denominator. Implementations can provide support for larger ranges and higher precision, but must provide at least the range and precision defined here.
The DateTime literal combines the Date and Time literals and is a subset of [ISO8601]:
- A datetime literal begins with an
@ - It uses the
yyyy-MM-DDThh:mm:ss.fff(+\|-)hh:mm{:.formatted} format - Timezone offset is optional, but if present the notation
(+\|-)hh:mm{:.formatted} is used (so must include both minutes and hours) - Z is allowed as a synonym for the zero (+00:00) UTC offset.
- A
Tcan be used at the end of any date (year, year-month, or year-month-day) to indicate a partial DateTime.
The following example illustrates the use of the DateTime literal:
@2014-01-25T14:30:14.559
@2014-01-25T14:30:14.559Z // A date time with UTC timezone offset
@2014-01-25T14:30 // A partial DateTime with year, month, day, hour, and minute
@2014-03-25T // A partial DateTime with year, month, and day
@2014-01T // A partial DateTime with year and month
@2014T // A partial DateTime with only the year
The suffix T is allowed after a year, year-month, or year-month-day literal because without it, there would be no way to specify a partial DateTime with only a year, month, or day; the literal would always result in a Date value.
Consult the formal grammar for more details.
Quantity
The Quantity type represents quantities with a specified unit, where the value component is defined as a Decimal, and the unit is represented as a String that is required to be either a valid Unified Code for Units of Measure [UCUM] unit or one of the calendar duration keywords, singular or plural.
The Quantity literal is a number (integer or decimal), followed by a (single-quoted) string representing a valid Unified Code for Units of Measure [UCUM] unit or calendar duration keyword. If the value literal is an Integer, it will be implicitly converted to a Decimal in the resulting Quantity value:
4.5 'mg'
100 '[degF]'
Implementations must respect UCUM units, meaning that they must not ignore UCUM units in calculations involving quantities, including comparison, conversion, and arithmetic operations. For implementations that do not support unit conversion, this means that the calculation need only be supported if the units are the same value, case-sensitively.
When using [UCUM] units within FHIRPath, implementations shall use case-sensitive comparisons.
Implementations shall support comparison and arithmetic operations on quantities with units where the units are the same.
Implementations should support other unit functionality as specified by UCUM, including unit conversion.
Implementations that do NOT support complete UCUM functionality may return empty (
{ }) for calculations involving quantities with units where the units are different.For Implementations that DO support UCUM conversion, if an operation is performed with conflicting units (for example, adding meters and grams), the evaluation will end and signal an error to the calling environment.
Time-valued Quantities
For time-valued quantities, in addition to the definite duration UCUM units, FHIRPath defines calendar duration keywords for calendar duration units:
| Calendar Duration | Unit Representation | Relationship to Definite Duration UCUM Unit |
|---|---|---|
year/years | 'year' | ~ 1 'a' |
month/months | 'month' | ~ 1 'mo' |
week/weeks | 'week' | = 1 'wk' |
day/days | 'day' | = 1 'd' |
hour/hours | 'hour' | = 1 'h' |
minute/minutes | 'minute' | = 1 'min' |
second/seconds | 'second' | = 1 's' |
millisecond/milliseconds | 'millisecond' | = 1 'ms' |
| {: .grid} |
For example, the following quantities are calendar duration quantities:
1 year
4 days
Whereas the following quantities are definite duration quantities:
1 'a'
4 'd'
The table above defines the equality/equivalence relationship between calendar and definite duration quantities. For example, 1 year is not equal to 1 'a', but it is equivalent to 1 'a'. See Date/Time Arithmetic for more information on using time-valued quantities in FHIRPath.
Operators
Expressions can also contain operators, like those for mathematical operations and boolean logic:
Appointment.minutesDuration / 60 > 5
MedicationAdministration.wasNotGiven implies MedicationAdministration.reasonNotGiven.exists()
name.given | name.family // union of given and family names
'sir ' + name.given
Operators available in FHIRPath are covered in detail in the Operations section.
Function Invocations
Finally, FHIRPath supports the notion of functions, which operate on a collection of values (referred to as the input collection), optionally taking arguments, and return another collection (referred to as the output collection). For example:
name.given.substring(0,4)
identifier.where(use = 'official')
Since all functions work on input collections, constants will first be converted to a collection when functions are invoked on constants:
(4+5).count()
will return 1, since the input collection is implicitly a collection with one constant number 9.
In general, functions in FHIRPath operate on collections and return new collections. This property, combined with the syntactic style of dot invocation enables functions to be chained together, creating a fluent-style syntax:
Patient.telecom.where(use = 'official').union(Patient.contact.telecom.where(use = 'official')).exists().not()
However not all functions support multiple items in the input collection, some expect only a single item and will be explicitly documented. Further details are available in the "singleton evaluation of collections" section. {:.stu}
Singleton only functions can be run on collections by using the function inside a select(...) to evaluate the function for each item in the collection.
{:.stu}
For a complete listing of the functions defined in FHIRPath, refer to the Functions section.
Null and empty
There is no literal representation for null in FHIRPath. This means that when, in an underlying data object (i.e. they physical data on which the implementation is operating) an element is null or missing, there will simply be no corresponding node for that element in the tree, e.g. Patient.name{:.fhirpath} will return an empty collection (not null) if there are no name elements in the instance.
In expressions, the empty collection is represented as { }.
Propagation of empty results in expressions
FHIRPath functions and operators both propagate empty results, but the behavior is in general different when the argument to the function or operator expects a collection (e.g. select(), where() and | (union)) versus when the argument to the function or operator takes a single value as input (e.g. + and substring()).
For functions or operators that take a single values as input, this means in general if the input is empty, then the result will be empty as well. More specifically:
- If a single-input operator or function operates on an empty collection, the result is an empty collection
- If a single-input operator or function is passed an empty collection as an argument, the result is an empty collection
- If any operand to a single-input operator or function is an empty collection, the result is an empty collection.
For operator or function arguments that expect collections, in general the empty collection is treated as any other collection would be. For example, the union (|) of an empty collection with some non-empty collection is that non-empty collection.
When functions or operators behave differently from these general principles, (for example the count() and empty() functions), this is clearly documented in the next sections.
Singleton Evaluation of Collections
In general, when a collection is passed as an argument to a function or operator that expects a single item as input, the collection is implicitly converted to a singleton as follows:
IF the collection contains a single node AND the node's value can be implicitly converted to the expected input type THEN
The collection evaluates to the value of that single node
ELSE IF the collection contains a single node AND the expected input type is Boolean THEN
The collection evaluates to true
ELSE IF the collection is empty THEN
The collection evaluates to an empty collection
ELSE
The evaluation will end and signal an error to the calling environment
For example:
Patient.name.family + ', ' + Patient.name.given
If the Patient instance has a single name, and that name has a single given, then this will evaluate without any issues. However, if the Patient has multiple name elements, or the single name has multiple given elements, then it's ambiguous which of the elements should be used as the input to the + operator, and the result is an error.
As another example:
Patient.active and Patient.gender and Patient.telecom
Assuming the Patient instance has an active value of true, a gender of female and a single telecom element, this expression will result in true. However, consider a different instance of Patient that has an active value of true, a gender of male, and multiple telecom elements, then this expression will result in an error because of the multiple telecom elements.
Note that for repeating elements like telecom in the above example, the logic looks like an existence check. To avoid confusion and reduce unintended errors, authors should use the explicit form of these checks when appropriate. For example, a more explicit rendering of the same logic that more clearly indicates the actual intent and avoids the run-time error is:
Patient.active and Patient.gender and Patient.telecom.count() = 1