openEHR to ISO 13606-1, ISO 21090 mapping
Introduction
This page provides information on which a technical solution to bidirectional openEHR / ISO 13606 conversion can be based. Since ISO 13606 uses the ISO 21090 pre-standard for data types, this mapping necessarily involves an openEHR datatype <-> ISO 21090 mapping as well. Key points to note:
- there is currently no profile of 21090 (data types) for use in 13606; this means that 13606 currently uses the 'vanilla' 21090 schema and semantics. However many of these don't apply, and guidance now needs to be developed for them in the 13606 context.
- the requirements for round-tripping faithfully between 13606 and openEHR have not yet been defined. This will essentially be up to users.
ISO 13606-1
ISO 13606-1 is the model of an EHR Extract, designed to enable data to be shared between EHR systems. Technically it resembles the openEHR reference model, but in a simplified way. In particular , the ENTRY types of openEHR are mapped to a single ENTRY type in 13606, but this is not the only difference. A mapping algorithm is being developed that shold allow a bidirectional transform between openEHR and 13606. The algorithm uses two types of mapping:
- pre-defined class and attribute conversions, such as for the 13606 AUDIT_INFO class and the openEHR AUDIT_DETAILS class
- a generic algorithm that can be applied between ENTRYs
Predefined conversion rules
Common IM structures
openEHR | attribute | type | 13606 | attribute | type | description | exceptions / ambiguities |
---|---|---|---|---|---|---|---|
PATHABLE |
|
| RECORD_COMPONENT |
|
|
|
|
| parent (not persisted) | PATHABLE |
| orig_parent_ref | II [0..1] | rule: generate openEHR URI | see mismatches below |
LOCATABLE |
|
| RECORD_COMPONENT |
|
|
|
|
| uid | UID_BASED_ID [0..1] |
| rc_id | II [1] | rule: generate openEHR URI | see mismatches below |
| archetype_node_id | String [1] |
| archetype_id | String [0..1] | rule: String id->II |
|
| name | DV_TEXT [1] |
| name | TEXT [1] | rule: DV_TEXT -> TEXT | what are possible name values? |
| archetype_details | ARCHETYPED [0..1] |
|
|
|
|
|
| feeder_audit | FEEDER_AUDIT [0..1] |
| feeder_audit | AUDIT_INFO [0..1] | rule: follow link & map |
|
| links | Set<LINK> [0..1] |
| links | Set<LINK> [0..1] | rule: 1:1 iteration |
|
| - |
|
| sensitivity | Integer [0..1] |
| MISSING IN OPENEHR - could either be on LOCATABLE or on COMPOSITION |
|
|
|
| policy_ids | SET<II> |
| In openEHR, these settings are in the ACCESS_CONTROL object |
|
|
|
|
|
|
|
|
AUDIT_DETAILS |
|
| AUDIT_INFO |
|
|
|
|
| system_id | String [1] |
| ehr_system | II [1] | rule: String id->II | which system id is being used here? |
| committer | PARTY_PROXY [1] |
| committer | II [1] |
| which user id is being used here? |
| time_committed | DV_DATE_TIME [1] |
| time_committed | TS [1] | rule: |
|
| change_type | DV_CODED_TEXT [1] |
| reason_for_revision | CV [0..1] | rule: DV_CODED_TEXT->CV |
|
| description | DV_TEXT [0..1] |
| - |
|
| LOST INFORMATION |
+VERSION | lifecycle_state | DV_CODED_TEXT [1] |
| version_status | CS [0..1] | rule: DV_CODED_TEXT->CS |
|
+VERSION | preceding_version_id | OBJECT_VERSION_ID[1] |
| previous_version | II [0..1] | rule: |
|
+VERSION | owner_id | HIER_OBJECT_ID [1] |
| version_set_id | II [0..1] | rule: |
|
PARTY_PROXY |
|
| RELATED_PARTY |
|
|
|
|
| external_ref | PARTY_REF [0..1] |
| party | II [0..1] | rule: | LOST INFORMATION: namespace, type? |
PARTY_IDENTIFIED |
|
|
|
|
|
|
|
| name | String [0..1] | Demographics_package | name | ENTITY_NAME[*] | rule: String -> ENTITY_NAME synthesis |
|
| identifiers | List<DV_IDENTIFIER> [0..1] | Demographics_package | role | HEALTHCARE_ | rule: for each identifier: DV_IDENTIFIER -> HEALTHCARE_ |
|
PARTY_RELATED |
|
| RELATED_PARTY |
|
|
|
|
| relationship | DV_CODED_TEXT [1] |
| relationship | TEXT | rule: DV_CODED_TEXT->TEXT |
|
PARTY_SELF |
|
| RELATED_PARTY |
|
| convert to RELATED_PARTY with relationship = self? |
|
PARTICIPATION |
|
| FUNCTIONAL_ROLE |
|
|
|
|
| function | DV_TEXT [1] |
| function | CV [0..1] | rule: DV_CODED_TEXT->CV | LOST INFORMATION |
| performer | PARTY_PROXY [1] |
| performer | II [1] | use rule for: PARTY_PROXY.external_ref | LOST INFORMATION |
| time | DV_INTERVAL [0..1] |
| - |
| (no mapping available) | LOST INFORMATION |
| mode | DV_CODED_TEXT [1] |
| mode | CS [0..1] | rule: DV_CODED_TEXT->CS |
|
( EVENT_CONTEXT) | health_care_facility | PARTY_IDENTIFIED [0..1] |
| healthcare_facility | II [0..1] | use rule for: PARTY_PROXY.external_ref | healthcare facility is in openEHR.EVENT_CONTEXT (since there cannot be 2 HCFs in one ENTRY) |
( EVENT_CONTEXT) | setting | DV_CODED_TEXT [1] |
| service_setting | CV [0..1] | rule: DV_CODED_TEXT->CV | service setting is in openEHR.EVENT_CONTEXT (since there cannot be 2 types of service setting in one ENTRY) |
Section & Entry structures
openEHR | attribute | type | 13606 | attribute | type | description | exceptions / ambiguities |
---|---|---|---|---|---|---|---|
SECTION |
|
| SECTION |
|
|
|
|
|
|
|
|
|
|
|
|
ENTRY |
|
| ENTRY |
|
|
|
|
| language | CODE_PHRASE [1] |
| (items) | ELEMENT | generic mapping rule: | Can ELEMENT.name be used in this way? |
| encoding | CODE_PHRASE [1] |
| (items) | ELEMENT | generic mapping rule: | Can ELEMENT.name be used in this way? |
| subject | PARTY_PROXY [1] |
| subject_of_information | RELATED_PARTY | rule: PARTY_PROXY->RELATED_PARTY |
|
|
|
|
| subject_of_information_category | CS [0..1] | proposed rule: |
|
| provider | PARTY_PROXY [0..1] |
| info_provider | FUNCTIONAL_ROLE | map EVENT_CONTEXT. | MISSING IN OPENEHR - ENTRY.mode |
| - |
|
| uncertainty_expressed | Boolean [1] | rule: | Hard to see how this attribute could be a) on all Entries, and b) be a Boolean |
CARE_ENTRY |
|
| ENTRY |
|
|
|
|
| protocol | ITEM_STRUCTURE |
| (items) | CLUSTER/ELEMENT | use algorithm 1 below. |
|
| guideline_id | OBJECT_REF |
| - |
|
| INFORMATION LOST (not likely to be present in source in most cases) |
ADMIN_ENTRY |
|
| ENTRY |
|
|
|
|
| data | ITEM_STRUCTURE |
| (items) | CLUSTER/ELEMENT | use algorithm 1 below. |
|
OBSERVATION |
|
| ENTRY |
|
|
|
|
| data |
|
| (items) | CLUSTER/ELEMENT | use algorithm 1 below. |
|
| state |
|
| (items) | CLUSTER/ELEMENT | use algorithm 1 below. |
|
EVALUATION |
|
| ENTRY |
|
|
|
|
| data | ITEM_STRUCTURE |
| (items) | CLUSTER/ELEMENT | use algorithm 1 below. |
|
INSTRUCTION |
|
| ENTRY |
|
|
|
|
| narrative | DV_TEXT |
| (items) | ELEMENT | use algorithm 1 below. |
|
| expiry_time | DV_DATE_TIME |
| (items) | ELEMENT | use algorithm 1 below. |
|
| wf_definition | DV_PARSABLE |
| (items) | ELEMENT | use algorithm 1 below. |
|
| activities | List<ACTIVITY> |
| (items) | CLUSTER/ELEMENT | use algorithm 1 below. |
|
ACTIVITY |
|
| CLUSTER |
|
|
|
|
| description | ITEM_STRUCTURE |
| (parts) |
| use algorithm 1 below. |
|
| timing | DV_PARSABLE |
| (parts) | ELEMENT | use algorithm 1 below. |
|
ACTION |
|
| ENTRY |
|
|
|
|
| time | DV_DATE_TIME |
| (items) | ELEMENT | use algorithm 1 below. |
|
| description | ITEM_STRUCTURE |
| (items) | CLUSTER/ELEMENT | use algorithm 1 below. |
|
| ism_transition | ISM_TRANSITION |
| (items) | CLUSTER | use algorithm 1 below. |
|
| instruction_details | INSTRUCTION_DETAILS |
| (items) | CLUSTER | use algorithm 1 below. |
|
ISM_TRANSITION |
|
| CLUSTER |
|
|
|
|
| current_state | DV_CODED_TEXT |
| (parts) | ELEMENT | use algorithm 1 below. |
|
| transition | DV_CODED_TEXT |
| (parts) | ELEMENT | use algorithm 1 below. |
|
| careflow_step | DV_CODED_TEXT |
| (parts) | ELEMENT | use algorithm 1 below. |
|
INSTRUCTION_DETAILS |
|
| CLUSTER |
|
|
|
|
| instruction_id | LOCATABLE_REF |
| (parts) | ELEMENT | use algorithm 1 below. |
|
| activity_id | String |
| (parts) | ELEMENT | use algorithm 1 below. |
|
| wf_details | ITEM_STRUCTURE |
| (parts) | CLUSTER/ELEMENT | use algorithm 1 below. |
|
|
|
|
|
|
|
|
|
Sub-ENTRY structures
openEHR | attribute | type | 13606 | attribute | type | description | exceptions / ambiguities |
---|---|---|---|---|---|---|---|
HISTORY |
|
| CLUSTER |
|
|
|
|
events | (parts) | ||||||
EVENT |
|
| CLUSTER |
|
|
|
|
data | (parts) | ||||||
| state |
|
| (parts) |
|
|
|
POINT_EVENT |
|
| CLUSTER |
|
|
|
|
|
|
|
|
|
|
|
|
INTERVAL_EVENT |
|
| CLUSTER |
|
|
|
|
|
|
|
|
|
|
|
|
ITEM_STRUCTURE |
|
| CLUSTER |
|
|
|
|
|
|
|
|
|
|
|
|
ITEM_TREE |
|
| CLUSTER |
|
|
|
|
| items |
|
| (parts) |
|
|
|
ITEM_TABLE |
|
| CLUSTER |
|
|
|
|
| rows |
|
| (parts) |
|
|
|
ITEM_LIST |
|
| CLUSTER |
|
|
|
|
| items |
|
| (parts) |
|
|
|
ITEM_SINGLE |
|
| CLUSTER |
|
|
|
|
| item |
|
| (parts) |
|
|
|
CLUSTER | items | List<ITEM | CLUSTER |
|
|
|
|
|
|
|
|
|
|
|
|
ELEMENT | value | DATA_VALUE [0..1] | ELEMENT |
|
|
|
|
| null_flavour | DV_CODED_TEXT [0..1] |
|
|
|
|
|
ENTRY Conversion Algorithm (algorithm #1)
To convert between any openEHR concrete ENTRY type, such as OBSERVATION, a generic approach is required. The principle problem is that to convert an instance of any openEHR ENTRY class like OBSERVATION, EVALUATION, etc, we only have ISO13606 ENTRY as a possible target. The same is true for instances of HISTORY, POINT_EVENT, ITEM_TREE etc - they only possible target is CLUSTER. In ISO13606, every RM class has a 'meaning' attribute to be used in this kind of transformations. The meaning codes are
Code | Original Type |
---|---|
OE-01 | Observation |
OE-02 | Protocol |
OE-03 | Guideline_id |
OE-04 | Data |
OE-05 | Period |
OE-06 | Duration |
OE-07 | Point_event |
OE-08 | Event_data |
OE-09 | Event_state |
OE-10 | Interval_event |
OE-11 | Width |
OE-12 | Sample_count |
OE-13 | Math_function |
OE-14 | State |
OE-15 | Instruction_narrative |
OE-16 | Instruction_expiry_time |
OE-17 | Instruction_wf_definition |
OE-18 | Activity |
OE-19 | Activity_timing |
OE-20 | Activity_description |
OE-21 | Action_description |
OE-22 | Current_state |
OE-23 | Transition |
OE-24 | Careflow_step |
OE-25 | Instruction_details |
OE-26 | Instruction_id |
OE-27 | Activity_id |
OE-28 | Workflow_details |
OE-30 | Evaluation |
OE-31 | Instruction |
OE-32 | Action |
OE-33 | Activity_action_archetype_id |
Not all openEHR classes are defined as codes, but most of them are. Most notable missing ones: ADMIN_ENTRY, HISTORY, EVENT_CONTEXT.
openEHR | ISO13606 |
COMPOSITION +-content +-SECTION +-items +-OBSERVATION +-data +-HISTORY<ITEM_TREE> +-origin | +-DATE_TIME +-events +-POINT_EVENT<ITEM_TREE> +-data +-ITEM_TREE | COMPOSITION +-content +-SECTION +-members +-ENTRY (meaning = 'OE-01') -- OBSERVATION +-items +-CLUSTER -- HISTORY +-obs_time | +IVL<TS> +-items +-CLUSTER {meaning = 'OE-07') -- POINT_EVENT +-items +-CLUSTER |
ISO 21090 - Data Types
The 21090 data types are largely derived from HL7v3 data types, and as such contain things not needed by EHR systems. Currently there is no profile for 13606's use of 21090; if it existed it would state which things would not be used in 13606, and for others, how they should be used. Once a profile is developed, it should be used to build a new, simpler XML schema for 13606.
The following table is a list of notes relating to some of the attributes from abstract classes including ANY that need to be dealt with somehow in 13606/openEHR - the QTY data type has been used as the example here. These come either from the standard or from Grahame Grieve, its principal author. These could be used to develop a 13606 profile.
21090 class | attribute | comments |
---|---|---|
HXIT |
| 21090 spec: Because of the way that the types are defined, a number of attributes of the data types have values with a type derived from HXIT. In these cases the HXIT attributes are constrained to null. The only case where the HXIT attributes are allowed within a data type is on items in a collection (DSET, LIST, BAG, HIST). |
| validTimeLow, | GG: Intended for when a receiver system assembles a structure, but one of the pieces of data comes from somewhere else and is subject to separate life-cycle management - a piece of foreign data. So your own version management/life cycle stuff doesn't apply, but it's state is of sufficient interest to know this. (it's somewhat unusual, therefore, because most data is either handled in system, or its state is not tracked at all) So yes, the normal cycle is not respected (in the local context), but the data is of sufficient interest to track that state from where is is respected (elsewhere) a little. |
| controlActRoot, | The idea is that GUIDs would be generated for specific events - like measuring a person's BP. Or the BP being a certain value at a certain time - by some systems, and then used to refer to those events later on. This is a referent-tracking idea See Ceusters et al. |
ANY |
|
|
| nullFlavor | Mostly maps to ELEMENT.nullflavour. Exceptions:
|
| updateMode | RECOMMENDATION: eleminate from 13606 profile |
| flavorId | RECOMMENDATION: should not be in model; eleminate from 13606 profile |
QTY |
|
|
| expression | Was designed for representing a prescription dose dependent on external factors (e.g. patient peak flow rate, for an asthma drug). Should not really be on QTY. |
| uncertainty, uncertaintyType | Appears also to relate only to specific uses of certain kinds of QTY. Could be mappable to openEHR precision and accuracy in some cases. In openEHR, 'uncertainty' is a concept associated with assessments, diagnoses etc. |
| originalText | TB: this is a contextual idea that assumes a data entry application situation. The problem is that all kinds of ways of entering data are possible: it could be chosen from a dropdown or tree widget, or be a dial widget, calendar picker, or any one of a myriad of modern GUI entry mechanisms. So I don't see how this field can be meaningfully populated in many source systems anyway; I also don't see what to do with the value of the field if it doesn't match teh stringified version of the data item, e.g. what if this field value is '11/10/2009' and the actual value string is '2009-10-11' - then it is purely duplicate information and of no use; what if the value string is '2009-11-10'? We assume then a US-style interface, but otherwise it is still a duplicate. |
The following table is a map of data types.
openEHR Class | attribute | type | 21090 Class | attribute | type | description | exceptions |
---|---|---|---|---|---|---|---|
DV_BOOLEAN | value | Boolean [1] | BL or BL.NONNULL |
|
|
|
|
DV_STATE | value | DV_CODED_TEXT [1] |
|
|
|
|
|
| is_terminal | Boolean [1] |
|
|
|
|
|
DV_IDENTIFIER | issuer | String [1] |
|
|
|
|
|
| id | String [1] |
|
|
|
|
|
| type | String [1] |
|
|
|
|
|
| assigner | String [1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
DV_TEXT | value | String [1] |
|
|
|
|
|
| hyperlink | DV_URI [0..1] |
|
|
|
|
|
| mappings | List<TERM_MAPPING> |
|
|
|
|
|
| encoding | CODE_PHRASE [0..1] |
|
|
|
|
|
| language | CODE_PHRASE [0..1] |
|
|
|
|
|
TERM_MAPPING | match | Character [1] |
|
|
|
|
|
| purpose | DV_CODED_TEXT [0..1] |
|
|
|
|
|
| target | CODE_PHRASE [1] |
|
|
|
|
|
CODE_PHRASE | terminology_id | TERMINOLOGY_ID [1] |
|
|
|
|
|
| code_string | String [1] |
|
|
|
|
|
DV_CODED_TEXT | defining_code | CODE_PHRASE [1] |
|
|
|
|
|
DV_PARAGRAPH | items | List<DV_TEXT> [1..*] |
|
|
|
|
|
|
|
|
|
|
|
|
|
DV_ORDERED |
|
|
|
|
|
|
|
| normal_status | CODE_PHRASE [0..1] |
|
|
|
|
|
| normal_range | DV_INTERVAL<T> [0..1] |
|
|
|
|
|
| other_reference_ranges | List<REFERENCE_RANGE<T>> [0..1] |
|
|
|
|
|
DV_INTERVAL<T> |
|
|
|
|
|
|
|
| lower | T->DV_ORDERED [0..1] |
|
|
|
|
|
| upper | T->DV_ORDERED [0..1] |
|
|
|
|
|
| lower_included | Boolean |
|
|
|
|
|
| upper_included | Boolean |
|
|
|
|
|
| lower_unbounded | Boolean |
|
|
|
|
|
| upper_unbounded | Boolean |
|
|
|
|
|
REFERENCE_RANGE<T> | meaning | DV_TEXT [1] |
|
|
|
|
|
| range | DV_INTERVAL <T> [1] |
|
|
|
|
|
DV_QUANTIFIED | magnitude_status | String [0..1] |
|
|
|
|
|
DV_ORDINAL | value | Integer [1] |
|
|
|
|
|
| symbol | DV_CODED_TEXT [1] |
|
|
|
|
|
DV_AMOUNT |
|
|
|
|
|
|
|
| accuracy | Real [0..1] |
|
|
|
|
|
| accuracy_is_percent | Boolean [0..1] |
|
|
|
|
|
DV_COUNT |
|
| INT? |
|
|
|
|
| magnitude | Integer [1] |
|
|
|
|
|
DV_QUANTITY |
|
| REAL? |
|
|
|
|
| magnitude | Double [1] |
|
|
|
|
|
| precision | Integer [0..1] |
|
|
|
|
|
| units | String [1] |
|
|
|
|
|
DV_PROPORTION |
|
| RATIO? |
|
|
|
|
| numerator | Real [1] |
|
|
|
|
|
| denominator | Real [1] |
|
|
|
|
|
| type | Integer [1] |
|
|
|
|
|
| precision | Integer [0..1] |
|
|
| openEHR values: |
|
DV_DURATION | value | String [1] |
|
|
| ISO 8601 |
|
DV_ABSOLUTE_QUANTITY | accuracy | DV_AMOUNT [0..1] |
|
|
|
|
|
DV_DATE | value | String [1] | TS.DATE |
|
| ISO 8601 |
|
DV_TIME | value | String [1] | TS |
|
| ISO 8601 |
|
DV_DATE_TIME | value | String [1] | TS.DATE_TIME |
|
| ISO 8601 |
|
|
|
|
|
|
|
|
|
DV_TIME_SPECIFICATION |
|
|
|
|
|
|
|
| value | DV_PARSABLE [1] |
|
|
|
|
|
DV_PERIODIC_ |
|
| EIVL or PIVL |
|
| HL7 PIVL or EIVL syntax string |
|
DV_GENERAL_ |
|
|
|
|
| HL7 GTS syntax string |
|
|
|
|
|
|
|
|
|
DV_ENCAPSULATED |
|
|
|
|
|
|
|
| charset | CODE_PHRASE [0..1] | ED or subtype | charset | CODE [0..1] | codes: openEHR character sets |
|
| language | CODE_PHRASE [0..1] |
| language | CODE [0..1] | codes: openEHR languages |
|
DV_MULTIMEDIA |
|
|
|
|
|
|
|
| alternate_text | String |
|
|
|
|
|
| uri | DV_URI [0..1] |
| reference | TEL.URL [0..1] |
|
|
| data | Array <Octet> [0..1] |
| data | Binary [0..1] |
|
|
| thumbnail | DV_MULTIMEDIA [0..1] |
| thumbnail | ED [0..1] |
|
|
| media_type | CODE_PHRASE [1] |
| mediaType | CODE [0..1] | codes: openEHR media types |
|
| compression_algorithm | CODE_PHRASE [0..1] |
| compression | Compression [0..1] | codes: openEHR compression algorithms |
|
| integrity_check | Array <Octet> [0..1] |
| integrityCheck | Binary [0..1] |
|
|
| integrity_check_algorithm | CODE_PHRASE [0..1] |
| integrityCheckAlgorithm | integrityCheckAlgorithm [0..1] | codes: openEHR integrity check algorithms |
|
| size | Integer [1] |
|
|
|
|
|
DV_PARSABLE |
|
|
|
|
|
|
|
| value | String [1] |
| xml | XML |
|
|
| formalism | String [1] |
|
|
|
|
|
DV_URI | value | String [1] |
|
|
| legal W3C URI |
|
DV_EHR_URI |
|
|
|
|
| openEHR constrained version |
|
|
|
|
|
|
|
|
|
Mismatches
Model mismatches
Some ISO 13606 data attributes do not currently exist in openEHR, and might be candidates for addition to the reference model. We should make two key points clear here. Firstly openEHR is designed as a high-quality health record architecture, rather than a one-size-fits-all interchange standard. Thus, design decisions in 13606 which are typically taken to accommodate data structures from the largest number of possible source systems do not necessarily make sense in openEHR, which is designed as a coherent EHR, and could be considered one possible 'source' system. Of course, its structures are also extremely useful for intersystem interchange. Accordingly, the relevant question to ask here is: can 13606 accommodate what is in openEHR, rather than the other way around. (ISO 13606 has sometimes been used as a design basis for some EHR systems, rather than for its intended purpose as an interchange format; in such circumstances, due to the above reasons, problems may be encountered in such projects).
Secondly, ISO13606 is an extract, which means its information instances are constructed by processing existing data (which might be relational, objects, XML, etc) and generating the output. Thus the normalisation (i.e. 'factoring') and structure of data items in the 13606 Extract makes sense (hopefully) for sharing data in a context-free manner (i.e. the receiver of the extract can use it as-is, without needing to refer to the source system), but may not be good design for the source system, and in fact may be quite different from the latter. We can thus think of some 13606 attributes as being 'refactored' attributes - they model data that is likely to be located elsewhere in the source system.
The following is a list of information attributes from ISO 13606 not currently supported in openEHR. Recommendations are made as to what to do about these attributes.
ISO 13606 RECORD_COMPONENT.policy_ids
This attribute is defined as follows in the ISO 13606-1 standard:
This attribute identifies one or more access control policies that specifically pertain to this RECORD_COMPONENT and which need to be communicated to the EHR Recipient to govern future access to it. The identifiers may refer to policy information included in this EHR_EXTRACT as defined in Part 4 of this standard, or to policies held in external policy servers to which the EHR Recipient has access.
From part 4:
In the 13606 Part 1 Reference Model every RECORD_COMPONENT within the EHR_EXTRACT includes an optional Policy_ID attribute to permit references to such policies to be made at any level of granularity within the EHR containment hierarchy. Every RECORD_COMPONENT may therefore reference any number of access policies or consent declarations that define the intended necessary privileges and profiles of principals (users, agents, software, devices, delegated actors etc) for future access to it.
It must be remembered that some policies may apply to particular RECORD_COMPONENTs within an EHR, whilst others may apply to the EHR as a whole.
This attribute is a good example of a refactored attribute. The intention in ISO 13606 is to mark each data node with the list of policies that apply to it. However, in an EHR system, the same information model is very unlikely to be used, for at least one very basic reason: if the policies relating to a given data item or document were to change, changes would be required to the document itself. Instead, source systems are much more likely to have a policy server that references data items using whatever internal identification system is available.
Recommendation
This is the case for openEHR systems. The 13606 policy_ids attribute would therefore by populated by extracting the list of policy identifiers (where this makes sense) from the openEHR source system EHR ACCESS_CONTROL object and/or policy service. For conversion in the 13606 -> openEHR direction, the policy_ids found in the 13606 data would have to be matched to policies either in a service in the receiving system, or in a shared policy service. This would rely at least on the presence of a widely standardised policy identification scheme.
ISO 13606 RECORD_COMPONENT.sensitivity
This attribute is defined as follows in ISO 13606-1
The sensitivity of this RECORD_COMPONENT, represented using the code set for this attribute defined in Part 4 of this standard.
Part 4 contains the following:
In addition to the generic representation of EHR access policy information (Annex A), this standard therefore also defines a specification for a minimum basis for communicating the sensitivity of EHR data within an EHR_EXTRACT, by specifying the sensitivity of the RECORD_COMPONENTs within it according to the classification defined in clause 6.1 of this part standard. This classification corresponds to the various sub-domains of EHR data illustrated in Figure 3.
In practice any given EHR system might have other mechanisms for indicating the sensitivity of EHR data or some equivalent concept. This standard does not require EHR systems to store data according to the sensitivity levels defined in clause 6.1, but to be able to map to this classification on generating an EHR_EXTRACT.
This data item, and access policies in general have been discussed by the openEHR ARB in 2006. At the time it was thought that there might not be a single 'sensitivity' for a given data item, such as a document added to the EHR by an obstetrician indicating a woman's pregnancy. The patient in question may be happy for the GP to see this information, but not want it seen at all by her employer (which might be possible for large employers with their own health plans).
Recommendation
xxx
ISO 13606 ENTRY.mode
This attribute does exist in openEHR where the PARTICIPATION class is used. However, in the ENTRY class, the attributes subject and provider are 'hard-modelled', and do not use the generic PARTICIPATION value, since the function and performer are implicit. This does however mean that the mode attribute is also not available for the two principal participants.
Recommendation
This attribute is a candidate for addition to openEHR.
Data mismatches
This category of differences is where the models do map more or less directly, but are used in different ways, resulting in data instances that may not be populated in the same way.
ISO 13606 RECORD_COMPONENT.rc_id, orig_parent_ref
This attribute is probably the biggest challenge of the ISO 13606 model. ISO 13606-1 says the following.
It is important that each RECORD_COMPONENT be uniquely and consistently identified across multiple EHR_EXTRACTS, so that references to or between them remain valid. Examples of such references are semantic links, revision and attestation. The rc_id attribute is of data type Instance Identifier (II), which incorporates an ISO OID; II is currently considered internationally to be the most appropriate data type for persistent identifiers that are required to be globally unique. It is unlikely that contemporary EHR systems will have existing primary keys or internal identifiers that correspond directly to globally-unique II instances. However, an EHR Provider system that has been issued with an organisational OID might use its internal references to construct unique local extensions to that OID and thereby construct globally-unique rc_id values.
Alternatively, it might create completely new rc_ids and retain a record of the mapping of these to each internal identifier, so that any future EHR_EXTRACTS it generates will use consistent rc_id values. It is also unlikely that an EHR Recipient system will be able to use received rc_id values as its internal primary keys for the data, since every database uses a slightly different approach to generating and using such keys. The EHR Recipient might therefore also need to keep a record of the mapping of imported rc_id values to its primary keys, so that future references to those RECORD_COMPONENTS can be appropriately matched, and it can create EHR_EXTRACTs that reapply those rc_id values to the exported data. An alternative approach is for EHR systems to explicitly store the rc_id values along with the clinical data, and treat this as part of the "payload" data and not attempt to use these also as primary keys. It should also be noted that the rc_id does not function as a primary key equivalent within an EHR_EXTRACT i.e. duplicate values of rc_id are permitted if each instance does indeed refer to the same piece of clinical data within the EHR Provider system. [emphasis added]
The key requirement here is:
- Extract nodes (i.e. RECORD_COMPONENT instances) must be uniquely and consistently identified across multiple EHR_EXTRACTs (rather than just within a given extract).
Two strategies for populating rc_id are proposed:
- use an organisation OID + locally constructed internal identifiers for the nodes in the Extract
- create rc_id values (probably GUIDs) on the fly and make both source and target systems keep a record of them.
The second approach implies a serious impost in data management overhead, since it requires an entirely new GUID-based indexing capability to be added to all systems sharing data using 13606, with concomitant costs, even though they have no use for such a capability within the system, or for other sharing methods, such as HL7v2. As a result, the only approach that can realistically be used in EHR systems, including those based on openEHR, is the first. It is assumed for both the rc_id and the orig_parent_ref attributes.
Recommendation
To implement the first approach above in openEHR, ids of the form used in openEHR URIs are used, i.e. COMPOSITION.uid + node path, since COMPOSITION.uid is globally unique (other approaches could be used involving a system identifier as well). COMPOSITION.uid is of type OBJECT_VERSION_ID, described as follows in the specification:
The string form of an OBJECT_VERSION_ID stored in its value attribute consists of three segments separated by double colons ("::"), i.e. (EBNF):
value: object_id '::' creating_system_id '::' version_tree_id
object_id: UID
creating_system_id: UID
version_tree_id: VERSION_TREE_ID
An example is as follows:
F7C5C7B7-75DB-4b39-9A1E-C0BA9BFDBDEC::87284370-2D4B-4e3d-A3F3-F303D2F4F34B::2
Note that the uid (first and second segments can also be of type ISO Oid, or a reverse internet domain name. This 3-part id globally identifies a versioned openEHR Composition in a distributed network where multiple institutions can create their own local updates from an initial common copy e.g. of medications list. To get to an interior node, a path will be required, of the typical form used in openEHR, from the root node down to the node in question. An example of such a path is:
/content[openEHR-EHR-SECTION.vital_signs.v1 and name/value='Vital signs']/items[openEHR-EHR-OBSERVATION.heart_rate-pulse.v1 and name/value='Pulse']/data/ events[at0003 and name/value='Any event']/data/items[at1005]
So the identifier to each node in a structure could be something like:
F7C5C7B7-75DB-4b39-9A1E-C0BA9BFDBDEC::87284370-2D4B-4e3d-A3F3-F303D2F4F34B::2/content[openEHR-EHR-SECTION.vital_signs.v1 and name/value='Vital signs']/ items[openEHR-EHR-OBSERVATION.heart_rate-pulse.v1 and name/value='Pulse']/data/events[at0003 and name/value='Any event']/data/items[at1005]
(Note that 'Pulse' and 'Vital signs' could also be represented by Snomed or other codes).