Code Lists
A code list is a named set of clinical or medicinal concept identifiers. Patient query variables never carry codes directly: they name a code list, and the query engine resolves that name to a flat list of concept identifiers at run time.
Every code list a query uses must be declared in the query's own <codeLists>
block. There is no inheritance from a parent query or from the report that
contains it.
<codeLists>
<codeList>
<name>DIABETES</name>
<codeListDefinition>
<rules>
<inclusion><< 73211009 |Diabetes mellitus|</inclusion>
</rules>
</codeListDefinition>
</codeList>
</codeLists>
<variables>
<codedEntryVariable name="DIABETES_DAT" code="DIABETES" .../>
</variables>
Declaring a code list
<codeLists> holds zero or more <codeList> elements. Each one has a <name>
followed by exactly one payload element.
| Payload | Codes come from | Re-resolved at query time |
|---|---|---|
<codeListDefinition> | Expressions evaluated against the terminology | Yes, on every run |
<fixedCodeList> | The literal identifiers you list | Not applicable |
<name> is a child element, not an attribute, and it must come first.
<codeList name="DIABETES"> is not valid, and neither is putting the payload
before the name.
The name is the identifier used by variable attributes. It is scoped to the query, so it is yours to choose. Names must be unique within a query: if two entries share a name, the last one silently wins.
Inline definition
Evaluates one or more expressions against the terminology to build the list.
Expressions are re-evaluated on every query run, so a list defined this way
follows the SNOMED CT release: a concept added under 73211009 in a later
release starts matching without the query changing.
<codeList>
<name>DIABETES</name>
<codeListDefinition>
<rules>
<inclusion><< 73211009 |Diabetes mellitus|</inclusion>
<exclusion><< 420825003 |Maturity-onset diabetes of the young|</exclusion>
</rules>
</codeListDefinition>
</codeList>
<rules> takes one or more <inclusion> and <exclusion> elements in any
order and any mix. Each element holds exactly one expression. See
Expression syntax below.
Note the XML escaping: < must be written <, so the descendant-or-self
operator << becomes <<.
Fixed code list
An explicit list of concept identifiers, with no terminology lookup at all. Nothing is expanded, so descendants of the concepts you list are not included.
<codeList>
<name>SPECIFIC_CODES</name>
<fixedCodeList>
<codes>
<code>73211009</code>
<code>44054006</code>
</codes>
</fixedCodeList>
</codeList>
At least one <code> is required. The values are not checked against the
terminology, either at publish time or at run time: an identifier that does not
exist simply matches nothing.
Expression syntax
<inclusion> and <exclusion> accept a single expression from the table below.
An optional |Display term| label may follow the identifier and is ignored.
| Expression | Resolves to |
|---|---|
123456789 | That one concept |
< 123456789 | All descendants of the concept |
<< 123456789 | The concept and all its descendants |
<! 123456789 | Immediate children of the concept |
<<! 123456789 | The concept and its immediate children |
> 123456789 | All ancestors of the concept |
>> 123456789 | The concept and all its ancestors |
>! 123456789 | Immediate parents of the concept |
>>! 123456789 | The concept and its immediate parents |
^ 123456789 | Members of the reference set with that identifier |
DMD 123456789 | dm+d products related to the given product concept |
DMD INGREDIENT 123456789 | dm+d products containing the given ingredient substance |
BNF CHAPTER 5.1 | dm+d products in the given BNF chapter or sub-chapter |
READ H33% | Concepts forward-mapped from the matching CTV3 codes, % is a trailing wildcard |
There is exactly one space between the operator and the identifier. An
expression that matches none of the forms above throws at run time with
Could not parse rule on DIABETES expression: ....
Despite the resemblance, this is not SNOMED CT Expression Constraint Language.
Each expression is matched against the fixed set of prefixes above, so ECL
constructs beyond that set are not supported: no MINUS, AND or OR, no
attribute or refinement constraints (:), no wildcards (*), no parentheses,
and no nesting or composition of any kind. Use separate <inclusion> and
<exclusion> elements instead of set operators, and a separate code list
instead of a compound expression.
<! and <<! are not ECL operators at all. ^ takes the numeric reference set
identifier only, not a PCD cluster name: write ^ 12463601000001108, not
^ ASTTRT_COD. The cluster name is conventionally carried in the display label
for readability.
Everything is resolved against the terminology tables directly, and the result is flattened into the query as a literal list of identifiers. There is no call out to an external terminology server, and no limit on how far a hierarchy expression expands.
How inclusions and exclusions combine
Elements are applied strictly in document order. Each <inclusion> adds its
concepts to the set, and each <exclusion> removes its concepts from whatever
the set holds at that point.
This is not set algebra, and the order matters. An <exclusion> placed before
the <inclusion> that would have added the code removes nothing, and the code
ends up in the list:
<rules>
<!-- Wrong: the exclusion runs first and removes nothing. -->
<exclusion><< 420825003</exclusion>
<inclusion><< 73211009</inclusion>
</rules>
Put every exclusion after the inclusions it is meant to narrow.
A bare concept identifier removes only that one concept, and leaves its descendants in the list. This definition resolves to diabetes mellitus and every subtype except the one named:
<rules>
<inclusion><< 73211009 |Diabetes mellitus|</inclusion>
<exclusion>420825003 |Maturity-onset diabetes of the young|</exclusion>
</rules>
Writing the exclusion as << 420825003 removes that concept and its
descendants, which for an exclusion is usually what you want.
Medications and other code systems
There is no separate medication code list. dm+d products live in ordinary code
lists, declared the same way and referenced by the same variable attributes,
using the DMD, DMD INGREDIENT and BNF CHAPTER expressions.
<codeList>
<name>SGLT2_INHIBITORS</name>
<codeListDefinition>
<rules>
<inclusion>DMD 28775211000001102 |Canagliflozin 100mg tablets|</inclusion>
</rules>
</codeListDefinition>
</codeList>
<codeList>
<name>CARDIAC_DRUGS</name>
<codeListDefinition>
<rules>
<inclusion>BNF CHAPTER 5.1</inclusion>
</rules>
</codeListDefinition>
</codeList>
Because a code list is just a set of identifiers, nothing stops a single list
mixing clinical concepts and dm+d products, and nothing checks that the codes in
a list belong to the code system a variable expects. Matching the list to the
variable is the author's responsibility: pass drug lists to productCode
attributes and clinical lists to code attributes.
READ expressions exist for content migrated from CTV3 and resolve through the
forward map to SNOMED CT concepts. Prefer native SNOMED CT expressions in new
content.
Where code lists are used
Every attribute below takes one or more declared code list names, and each is resolved through the same mechanism.
| Variable | Attribute | Restricts to |
|---|---|---|
<codedEntryVariable> | code | Entries with one of these codes |
<codedEntryVariable> | encounterTypeCode | Entries recorded in an encounter of one of these types |
<codedEntryVariable> | valueUnitCode | Entries whose value carries one of these units |
<codedEntryVariable> | bodySiteCode | Entries recorded against one of these body sites |
<codedEntryVariable> | routeCode | Entries recorded with one of these administration routes |
<prescriptionVariable> | productCode | Prescriptions for one of these products |
<prescriptionIssueVariable> | productCode | Issues of one of these products |
<prescriptionIssueVariable> | quantityUnitCode | Issues whose quantity carries one of these units |
Appointment variables do not take code lists.
Any of these attributes accepts a comma-separated list of names, and the union of those lists is used:
<codedEntryVariable name="VACCINATED_DAT" code="VACCINE_COD,VACCINE_DRUG_COD" .../>
Whitespace around each name is trimmed, so code="A_COD, B_COD" is fine. Each
name must still be declared in <codeLists>.
Validation
The Resource Publishing API does not validate the patient query inside published content beyond XML well-formedness. Code list problems therefore surface when the query runs, not when you publish, and there is no partial success: a query whose code list fails to resolve fails outright rather than returning a smaller cohort.
The checks that do exist, and where they run:
| Problem | Detected |
|---|---|
<name> missing or not first | Internal report authoring only, via the XSD |
No <rules> in an inline definition | Internal report authoring only |
Inline definition with no <inclusion> | Internal report authoring only |
| Unrecognised expression | At query run time |
| Variable naming an undeclared code list | At query run time |
Duplicate <name> in one query | Never, the last declaration wins |
| Code list declared but never used | Internal report authoring only, as a warning |
| Concept identifiers that do not exist | Never, they match nothing |
The internal report authoring path applies one further restriction that the
query engine itself does not: its expression check accepts only the hierarchy
operators, ^, DMD and bare identifiers. BNF CHAPTER, READ and
DMD INGREDIENT expressions run correctly but are rejected by that authoring
check, so a code list using them cannot currently be built or edited in the
report builder even though a published query may use it.