A Web Template is a processed-representation of an openEHR Operational Template that includes:
-
Simplified node identifiers
-
AQL paths for all elements
-
Input type definitions for data entry
-
Localized labels and descriptions
-
Multiplicity constraints
Web Template is used to generate and validate data instances. Specification of Web Template metadata is separate from the data serialization format described in this specification.
Example of a Web Template:
{
"templateId": "Blood_Pressure_Demo.v0",
"semVer": "0.2.0",
"version": "2.3",
"defaultLanguage": "en",
"languages": [ "en" ],
"tree": {
"id": "blood_pressure_demo.v0",
"name": "Blood_Pressure_Demo.v0",
"localizedName": "Blood_Pressure_Demo.v0",
"rmType": "COMPOSITION",
"nodeId": "openEHR-EHR-COMPOSITION.encounter.v1",
"min": 1,
"max": 1,
"localizedNames": {
"en": "Blood_Pressure_Demo.v0"
},
"localizedDescriptions": {
"en": "Interaction, contact or care event between a subject of care and healthcare provider(s)."
},
"aqlPath": "",
"children": [ {
"id": "context",
"rmType": "EVENT_CONTEXT",
"nodeId": "",
"min": 1,
"max": 1,
"aqlPath": "/context",
"children": [ {
"id": "start_time",
"name": "Start_time",
"rmType": "DV_DATE_TIME",
"min": 1,
"max": 1,
"aqlPath": "/context/start_time",
"inputs": [ {
"type": "DATETIME"
} ],
"inContext": true
}, {
"id": "setting",
"name": "Setting",
"rmType": "DV_CODED_TEXT",
"min": 1,
"max": 1,
"aqlPath": "/context/setting",
"inputs": [ {
"suffix": "code",
"type": "TEXT"
}, {
"suffix": "value",
"type": "TEXT"
} ],
"inContext": true
} ]
}, {
"id": "blood_pressure",
"name": "Blood pressure",
"localizedName": "Blood pressure",
"rmType": "OBSERVATION",
"nodeId": "openEHR-EHR-OBSERVATION.blood_pressure.v2",
"min": 0,
"max": 1,
"localizedNames": {
"en": "Blood pressure"
},
"localizedDescriptions": {
"en": "The local measurement of arterial blood pressure which is a surrogate for arterial pressure in the systemic circulation."
},
"annotations": {
"comment": "Most commonly, use of the term 'blood pressure' refers to measurement of brachial artery pressure in the upper arm."
},
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]",
"children": [ {
"id": "any_event",
"name": "Any event",
"localizedName": "Any event",
"rmType": "EVENT",
"nodeId": "at0006",
"min": 0,
"max": -1,
"localizedNames": {
"en": "Any event"
},
"localizedDescriptions": {
"en": "Default, unspecified point in time or interval event which may be explicitly defined in a template or at run-time."
},
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/data[at0001]/events[at0006]",
"children": [ {
"id": "systolic",
"name": "Systolic",
"localizedName": "Systolic",
"rmType": "DV_QUANTITY",
"nodeId": "at0004",
"min": 0,
"max": 1,
"localizedNames": {
"en": "Systolic"
},
"localizedDescriptions": {
"en": "Peak systemic arterial blood pressure - measured in systolic or contraction phase of the heart cycle."
},
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value",
"inputs": [ {
"suffix": "magnitude",
"type": "DECIMAL",
"validation": {
"range": {
"minOp": ">=",
"min": 0.0,
"maxOp": "<",
"max": 1000.0
},
"precision": {
"minOp": ">=",
"min": 0,
"maxOp": "<=",
"max": 0
}
}
}, {
"suffix": "unit",
"type": "CODED_TEXT",
"list": [ {
"value": "mm[Hg]",
"label": "mm[Hg]",
"localizedLabels": {
"en": "mmHg"
},
"validation": {
"range": {
"minOp": ">=",
"min": 0.0,
"maxOp": "<",
"max": 1000.0
},
"precision": {
"minOp": ">=",
"min": 0,
"maxOp": "<=",
"max": 0
}
}
} ]
} ],
"termBindings": {
"SNOMED-CT": {
"value": "[SNOMED-CT(2003)::271649006]",
"terminologyId": "SNOMED-CT"
}
}
}, {
"id": "diastolic",
"name": "Diastolic",
"localizedName": "Diastolic",
"rmType": "DV_QUANTITY",
"nodeId": "at0005",
"min": 0,
"max": 1,
"localizedNames": {
"en": "Diastolic"
},
"localizedDescriptions": {
"en": "Minimum systemic arterial blood pressure - measured in the diastolic or relaxation phase of the heart cycle."
},
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/data[at0001]/events[at0006]/data[at0003]/items[at0005]/value",
"inputs": [ {
"suffix": "magnitude",
"type": "DECIMAL",
"validation": {
"range": {
"minOp": ">=",
"min": 0.0,
"maxOp": "<",
"max": 1000.0
},
"precision": {
"minOp": ">=",
"min": 0,
"maxOp": "<=",
"max": 0
}
}
}, {
"suffix": "unit",
"type": "CODED_TEXT",
"list": [ {
"value": "mm[Hg]",
"label": "mm[Hg]",
"localizedLabels": {
"en": "mmHg"
},
"validation": {
"range": {
"minOp": ">=",
"min": 0.0,
"maxOp": "<",
"max": 1000.0
},
"precision": {
"minOp": ">=",
"min": 0,
"maxOp": "<=",
"max": 0
}
}
} ]
} ],
"termBindings": {
"SNOMED-CT": {
"value": "[SNOMED-CT(2003)::271650006]",
"terminologyId": "SNOMED-CT"
}
}
}, {
"id": "clinical_interpretation",
"name": "Clinical interpretation",
"localizedName": "Clinical interpretation",
"rmType": "DV_TEXT",
"nodeId": "at1059",
"min": 0,
"max": 1,
"localizedNames": {
"en": "Clinical interpretation"
},
"localizedDescriptions": {
"en": "Single word, phrase or brief description that represents the clinical meaning and significance of the blood pressure measurement."
},
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/data[at0001]/events[at0006]/data[at0003]/items[at1059]/value",
"inputs": [ {
"type": "TEXT"
} ]
}, {
"id": "position",
"name": "Position",
"localizedName": "Position",
"rmType": "DV_CODED_TEXT",
"nodeId": "at0008",
"min": 0,
"max": 1,
"dependsOn": [ "systolic", "diastolic", "clinical_interpretation" ],
"localizedNames": {
"en": "Position"
},
"localizedDescriptions": {
"en": "The position of the individual at the time of measurement."
},
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/data[at0001]/events[at0006]/state[at0007]/items[at0008]/value",
"inputs": [ {
"suffix": "code",
"type": "CODED_TEXT",
"list": [ {
"value": "at1000",
"label": "Standing",
"localizedLabels": {
"en": "Standing"
},
"localizedDescriptions": {
"en": "Standing at the time of blood pressure measurement."
}
}, {
"value": "at1001",
"label": "Sitting",
"localizedLabels": {
"en": "Sitting"
},
"localizedDescriptions": {
"en": "Sitting (for example on bed or chair) at the time of blood pressure measurement."
}
}, {
"value": "at1002",
"label": "Reclining",
"localizedLabels": {
"en": "Reclining"
},
"localizedDescriptions": {
"en": "Reclining at the time of blood pressure measurement."
}
}, {
"value": "at1003",
"label": "Lying",
"localizedLabels": {
"en": "Lying"
},
"localizedDescriptions": {
"en": "Lying flat at the time of blood pressure measurement."
}
}, {
"value": "at1014",
"label": "Lying with tilt to left",
"localizedLabels": {
"en": "Lying with tilt to left"
},
"localizedDescriptions": {
"en": "Lying flat with some lateral tilt, usually angled towards the left side. Commonly required in the last trimester of pregnancy to relieve aortocaval compression."
}
} ]
} ]
}, {
"id": "time",
"name": "Time",
"rmType": "DV_DATE_TIME",
"min": 1,
"max": 1,
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/data[at0001]/events[at0006]/time",
"inputs": [ {
"type": "DATETIME"
} ],
"inContext": true
} ]
}, {
"id": "method",
"name": "Method",
"localizedName": "Method",
"rmType": "DV_CODED_TEXT",
"nodeId": "at1035",
"min": 0,
"max": 1,
"dependsOn": [ "any_event" ],
"localizedNames": {
"en": "Method"
},
"localizedDescriptions": {
"en": "Method of measurement of blood pressure."
},
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/protocol[at0011]/items[at1035]/value",
"inputs": [ {
"suffix": "code",
"type": "CODED_TEXT",
"list": [ {
"value": "at1036",
"label": "Auscultation",
"localizedLabels": {
"en": "Auscultation"
},
"localizedDescriptions": {
"en": "Method of measuring blood pressure externally, using a stethoscope and Korotkoff sounds."
}
}, {
"value": "at1037",
"label": "Palpation",
"localizedLabels": {
"en": "Palpation"
},
"localizedDescriptions": {
"en": "Method of measuring blood pressure externally, using palpation (usually of the brachial or radial arteries)."
}
}, {
"value": "at1039",
"label": "Machine",
"localizedLabels": {
"en": "Machine"
},
"localizedDescriptions": {
"en": "Method of measuring blood pressure externally, using a blood pressure machine."
}
}, {
"value": "at1040",
"label": "Invasive",
"localizedLabels": {
"en": "Invasive"
},
"localizedDescriptions": {
"en": "Method of measuring blood pressure internally ie involving penetration of the skin and measuring inside blood vessels."
}
} ]
} ]
}, {
"id": "language",
"name": "Language",
"rmType": "CODE_PHRASE",
"min": 1,
"max": 1,
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/language",
"inContext": true
}, {
"id": "encoding",
"name": "Encoding",
"rmType": "CODE_PHRASE",
"min": 1,
"max": 1,
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/encoding",
"inContext": true
}, {
"id": "subject",
"name": "Subject",
"rmType": "PARTY_PROXY",
"min": 1,
"max": 1,
"aqlPath": "/content[openEHR-EHR-OBSERVATION.blood_pressure.v2]/subject",
"inputs": [ {
"suffix": "id",
"type": "TEXT"
}, {
"suffix": "id_scheme",
"type": "TEXT"
}, {
"suffix": "id_namespace",
"type": "TEXT"
}, {
"suffix": "name",
"type": "TEXT"
} ],
"inContext": true
} ],
"termBindings": {
"SNOMED-CT": {
"value": "[SNOMED-CT(2003)::364090009]",
"terminologyId": "SNOMED-CT"
}
}
}, {
"id": "category",
"rmType": "DV_CODED_TEXT",
"nodeId": "",
"min": 1,
"max": 1,
"aqlPath": "/category",
"inputs": [ {
"suffix": "code",
"type": "CODED_TEXT",
"list": [ {
"value": "433",
"label": "event",
"localizedLabels": {
"en": "event"
}
} ],
"terminology": "openehr"
} ],
"inContext": true
}, {
"id": "language",
"name": "Language",
"rmType": "CODE_PHRASE",
"min": 1,
"max": 1,
"aqlPath": "/language",
"inContext": true
}, {
"id": "territory",
"name": "Territory",
"rmType": "CODE_PHRASE",
"min": 1,
"max": 1,
"aqlPath": "/territory",
"inContext": true
}, {
"id": "composer",
"name": "Composer",
"rmType": "PARTY_PROXY",
"min": 1,
"max": 1,
"aqlPath": "/composer",
"inputs": [ {
"suffix": "id",
"type": "TEXT"
}, {
"suffix": "id_scheme",
"type": "TEXT"
}, {
"suffix": "id_namespace",
"type": "TEXT"
}, {
"suffix": "name",
"type": "TEXT"
} ],
"inContext": true
} ]
}
}The Simplified Formats use hierarchical field identifiers composed of:
-
Node IDs: Generated from archetype node names
-
Path separators: Forward slash (
/) between hierarchy levels -
Instance indicators: Colon notation (
:0,:1, etc.) for repeating elements -
Attribute suffixes: Pipe notation (
|magnitude,|unit, etc.) for RM attributes -
RM attribute prefix: Underscore (
_) for optional RM attributes not in template -
Raw canonical JSON: Use of
|rawattribute to embed openEHR canonical JSON
Example identifier structure:
vital_signs/body_temperature:0/any_event:0/temperature|magnitude vital_signs/body_temperature:0/any_event:0/temperature/_normal_range/lower|magnitude
Node IDs are generated from archetype node names using the following algorithm:
-
Character normalisation: Replace any character that is not:
-
A Unicode alphabetic character (
\p{IsAlphabetic}) -
A digit (
0-9) -
An underscore (
_) -
A dot (
.) -
A dash (
-)with an underscore (
_)
-
-
Underscore consolidation: Replace multiple consecutive underscores with a single underscore
-
Case normalisation: Convert to lowercase
-
Trim underscores: Remove leading and trailing underscores
-
Empty ID handling: If result is empty, use "id" as the identifier
-
Numeric prefix handling: If result starts with a digit, prepend "a"
-
Uniqueness: Append a numeric suffix if needed to ensure uniqueness among siblings
Examples:
| Original Name | Generated ID |
|---|---|
Body temperature |
body_temperature |
Problem/diagnosis |
problem_diagnosis |
Tests (1, 2, 3) |
tests_1_2_3 |
1st visit |
a1st_visit |
Blood Pressure |
blood_pressure |
Blood Pressure (duplicate) |
blood_pressure_1 |
Full paths are constructed by concatenating parent node IDs with forward slashes:
composition_id/section_id/observation_id/element_id
When a node can occur multiple times (max > 1 or max = -1), instances are indexed using colon notation:
node_id:0 # First instance node_id:1 # Second instance node_id:2 # Third instance
The index is appended after the node ID and before the next path separator.
Indexing examples:
Multiple events in an observation:
vital_signs/body_temperature:0/any_event:0/temperature|magnitude vital_signs/body_temperature:0/any_event:1/temperature|magnitude
Multiple observations in a composition:
vital_signs/body_temperature:0/any_event:0/temperature|magnitude vital_signs/body_temperature:1/any_event:0/temperature|magnitude
RM attributes are indicated by pipe-separated suffixes.
Example of such attributes:
| RM Type | Suffix | Description |
|---|---|---|
|
Numeric value |
|
|
Unit of measure |
|
|
Terminology code |
|
|
Display term |
|
|
Terminology identifier |
|
|
The ID value |
|
|
The namespace of the ID value |
Some attributes are defined by the openEHR Reference Model but are optional and may not be explicitly constrained in the template.
To access these RM attributes, an underscore prefix (i.e. '_') is used in the path: _attributeName.
This convention allows applications to populate optional RM attributes that provide additional metadata, audit information, or structural details beyond what is defined in the template.
Examples:
{
"conformance/observation:0/_uid": "9fcc1c70-9349-444d-b9cb-8fa817697f5e"
}{
"path/observation:0/_link:0|type": "problem",
"path/observation:0/_link:0|target": "ehr://problem-123",
"path/observation:0/_link:0|meaning|code": "related_to",
"path/observation:0/_link:0|meaning|value": "Related to"
}{
"vital_signs/temperature:0/value|magnitude": 37.5,
"vital_signs/temperature:0/value|unit": "°C",
"vital_signs/temperature:0/value/_normal_range/lower|magnitude": 36.0,
"vital_signs/temperature:0/value/_normal_range/lower|unit": "°C",
"vital_signs/temperature:0/value/_normal_range/upper|magnitude": 37.8,
"vital_signs/temperature:0/value/_normal_range/upper|unit": "°C"
}The |raw attribute is a special bypass mechanism that enables direct embedding of pre-serialized openEHR canonical JSON into flat or structured format inputs.
This feature allows incorporating fully-formed openEHR Reference Model (RM) objects without decomposing them into individual attributes.
{
"ctx/language": "en",
"ctx/territory": "US",
"ctx/composer_name": "Dr. Smith",
"ctx/time": "2024-01-15T10:30:00Z",
"vital_signs/blood_pressure:0/any_event:0/systolic|raw": {
"_type": "DV_QUANTITY",
"magnitude": 120,
"unit": "mm[Hg]"
}
}This feature proves particularly valuable when:
-
Working with pre-existing openEHR canonical JSON data
-
Handling complex RM structures that are cumbersome to express in simplified formats
-
Integrating data from systems that natively produce canonical JSON
The raw JSON value must include the _type property indicating the openEHR type, and should conform to the openEHR Reference Model.
Context information represents composition-level metadata and is prefixed with ctx/.
This includes:
-
Mandatory: language, territory
-
Optional: composer, time, setting, participations, facility information, workflow identifiers
Context data is typically not entered by users but provided by the application.
The ctx/time field, if not explicitly set, defaults to the current server time (now()).
See below [_context_information] for more details.
In the Flat format, all data elements are represented as key-value pairs at a single level in JSON where:
-
Keys are full WT paths (with instance indices and attribute suffixes)
-
Values are primitive types (string, number, boolean), or simple objects
-
There is no distinction between ELEMENT and its value - elements ARE their values
Syntax Rules:
-
All paths MUST be fully qualified from the data instance root
-
Context fields MUST use
ctx/prefix -
Instance indices MUST be zero-based
-
Attribute suffixes MUST be separated by pipe (
|) -
RM attribute paths MUST use underscore prefix (
_) -
Path segments MUST be separated by forward slash (
/)
Example:
{
"ctx/language": "en",
"ctx/territory": "US",
"ctx/composer_name": "Dr. Smith",
"ctx/time": "2024-01-15T10:30:00Z",
"vital_signs/body_temperature:0/any_event:0/temperature|magnitude": 37.5,
"vital_signs/body_temperature:0/any_event:0/temperature|unit": "°C",
"vital_signs/body_temperature:0/any_event:0/temperature/_normal_range/lower|magnitude": 36.0,
"vital_signs/body_temperature:0/any_event:0/temperature/_normal_range/lower|unit": "°C",
"vital_signs/body_temperature:0/any_event:0/temperature/_normal_range/upper|magnitude": 37.8,
"vital_signs/body_temperature:0/any_event:0/temperature/_normal_range/upper|unit": "°C",
"vital_signs/body_temperature:0/any_event:0/time": "2024-01-15T10:30:00Z",
"vital_signs/blood_pressure:0/any_event:0/systolic|magnitude": 120,
"vital_signs/blood_pressure:0/any_event:0/systolic|unit": "mm[Hg]",
"vital_signs/blood_pressure:0/any_event:0/diastolic|magnitude": 80,
"vital_signs/blood_pressure:0/any_event:0/diastolic|unit": "mm[Hg]",
"vital_signs/blood_pressure:0/any_event:0/time": "2024-01-15T10:30:00Z"
}In the Structured format, the hierarchy is preserved as nested JSON objects where:
-
Each path segment becomes a property in a nested object
-
Instance indices remain in property names (e.g.,
body_temperature) -
Attribute suffixes become properties prefixed with pipe (e.g.,
|magnitude) -
Context data is grouped under
ctxobject -
Arrays are used throughout, even for single-cardinality elements
Syntax Rules:
-
Hierarchy MUST be represented by nested objects
-
Instance indices MUST remain in property names
-
Attribute suffixes MUST use pipe prefix
-
Context data MUST be grouped under
ctxproperty -
Arrays MUST be used for data values, even when cardinality is
0..1or1..1 -
Empty objects SHOULD be omitted
{
"ctx": {
"language": "en",
"territory": "US",
"composer_name": "Dr. Smith",
"time": "2024-01-15T10:30:00Z"
},
"vital_signs": {
"body_temperature": [
{
"any_event": [
{
"temperature": [
{
"|magnitude": 37.5,
"|unit": "°C"
}
],
"time": [
"2024-01-15T10:30:00Z"
]
}
]
}
],
"blood_pressure": [
{
"any_event": [
{
"systolic": [
{
"|magnitude": 120,
"|unit": "mm[Hg]"
}
],
"diastolic": [
{
"|magnitude": 80,
"|unit": "mm[Hg]"
}
],
"time": [
"2024-01-15T10:30:00Z"
]
}
]
}
]
}
}Algorithm for converting flat format to structured:
-
Parse each flat key into path segments
-
Separate context fields (
ctx/) from composition fields -
For each path:
-
Split on forward slash (
/) -
Create nested objects for each segment
-
For the final segment, check for attribute suffix (|)
-
If attribute suffix exists, create an array containing an object with suffix as property
-
Handle RM attributes (underscore prefix) appropriately
-
-
Merge all nested structures
-
Add context object
Algorithm for converting structured format to flat:
-
Recursively traverse the nested object structure
-
Build path by concatenating property names with forward slash
-
For properties with a pipe prefix, append to a parent path with pipe
-
Unwrap arrays (Structured uses arrays throughout)
-
Flatten context object with
ctx/prefix -
Preserve instance indices in property names
-
Preserve RM attribute underscore prefixes
Paths in Flat and Structured formats omit two distinct kinds of segments relative to the canonical RM path:
-
Container attribute names of
LOCATABLE-to-LOCATABLErelationships are never present as path segments — the parent connects directly to the child via the child’s archetype node-id alias. -
In addition, certain wrapper node types are themselves collapsed — their archetype node-id is also dropped — because they act only as structural slots and carry no clinically meaningful identity at that level.
The following RM attribute names are universally absent from paths:
-
COMPOSITION.content -
SECTION.items -
OBSERVATION.data,OBSERVATION.state,OBSERVATION.protocol -
EVALUATION.data,EVALUATION.protocol -
INSTRUCTION.activities,INSTRUCTION.protocol -
ACTION.description,ACTION.protocol -
ADMIN_ENTRY.data -
ACTIVITY.description -
HISTORY.events -
EVENT.data,EVENT.state -
ITEM_TREE.items,ITEM_LIST.items,ITEM_SINGLE.item,ITEM_TABLE.rows -
CLUSTER.items
In addition to the attribute elision above, the following wrapper node types are themselves collapsed — their archetype node-id is also dropped, so the parent connects directly to the wrapper’s contents:
-
ITEM_STRUCTURE(abstract) and its concrete subtypes:-
ITEM_TREE -
ITEM_LIST -
ITEM_SINGLE -
ITEM_TABLE
-
-
HISTORY
These types act as fixed structural slots in their parent (ENTRY for the ITEM_STRUCTURE family; OBSERVATION for HISTORY) and have no archetype node-id distinct from that slot.
An EVENT node is collapsed when both of the following hold:
-
Its maximum occurrence is 1 (i.e.,
max = 1), AND -
No sibling
EVENTnodes (of any concrete event type) exist in the same parentHISTORY.
EVENT nodes are retained when:
-
Multiple
EVENTtypes exist in the same parentHISTORY(e.g., aPOINT_EVENTalongside anINTERVAL_EVENT), or -
The
EVENTcan occur multiple times (max > 1).
Take a single measurement magnitude inside a laboratory result panel. The canonical RM path is:
/content[openEHR-EHR-OBSERVATION.laboratory_test_result.v1]
/data[at0001]
/events[at0002]
/data[at0003]
/items[openEHR-EHR-CLUSTER.laboratory_test_panel.v1]
/items[openEHR-EHR-CLUSTER.laboratory_test_analyte.v1]
/items[at0001]
/valueThe same field in Flat form:
laboratory_test_report/laboratory_test/laboratory_test_panel/laboratory_result:0/result_value|magnitudeDifferences:
-
Container attribute names (
content,data,events,items,value) are elided wherever they appear. -
The
HISTORY(at0001) andITEM_TREE(at0003) wrapper nodes are collapsed; theEVENT(at0002) is conditionally collapsed (heremax=1, single event type). -
The
OBSERVATIONand the twoCLUSTERnodes are retained under their archetype-id aliases (laboratory_test,laboratory_test_panel,laboratory_result); the innerCLUSTERrepeats, hence the:0instance index. -
ELEMENT.valueis replaced by the|magnitudeattribute suffix.
When an archetype constrains a leaf to DV_CODED_TEXT with an open value-set — the bound terminology lists recommended codes but the constraint also accepts values outside the list (listOpen: true in the web template; non-limit-to-list in ADL) — the same leaf may at runtime carry either a DV_CODED_TEXT (chosen from the list) or a DV_TEXT (free-text value).
Many archetypes deliberately combine a recommended coded list with free-text fallback (e.g. state_of_dress, confounding_factors, overall_test_status). Without a dedicated FLAT-level discriminator the DV_CODED_TEXT vs DV_TEXT branch would have to be inferred from value patterns, which is fragile and ambiguous. The |other suffix makes the branch explicit at the FLAT level and removes the need for receivers to reason about it.
-
On write: clients supply the free-text value via
<path>|other: "<text>". The server persists the leaf as aDV_TEXTin the canonical RM (not as aDV_CODED_TEXTwith emptydefining_code). -
On read: when the leaf carries a
DV_TEXTwhose archetype constraint isDV_CODED_TEXTwithlistOpen: true, the server SHOULD emit it via<path>|other: "<text>"so that round-trip equality holds at the FLAT level. -
|otheris mutually exclusive with|code,|valueand|terminologyon the same leaf path; servers MUST reject combinations. -
|otherMUST be rejected when the constraint is closed (listOpen: false).
The per-suffix table is in the [DV_CODED_TEXT] class section.
Implementations SHOULD validate:
-
Get the WT for the target template and map input fields to the identifiers
-
Check the final segment for the pipe to identify attribute suffix
-
Mandatory context fields (language, territory) are present
-
Field identifiers match WT metadata structure
-
Data types match expected types from the Operational Template
-
Cardinality constraints are satisfied
-
Terminology bindings are valid
-
RM attribute paths (underscore-prefixed) are valid