Mappings
Alignment happens in two places. A resource declares what it corresponds to
with mapsTo, and the transformation that performs the conversion lives in a
separate document that mapsTo points at.
The split is deliberate. Declaring an alignment is cheap and immediately useful to a consumer deciding whether integration is possible at all. Writing the transformation is work, and holding the declaration hostage to it would mean publishing nothing until everything was done.
mapsTo
Section titled “mapsTo”Both Model and Vocabulary carry an optional array of these.
| Field | Type | |
|---|---|---|
system |
URL, required | The external system, for example http://hl7.org/fhir or https://schema.org. |
schema |
URL, required | The external schema or class, for example https://schema.org/Person. |
type |
string, required | How closely the alignment holds. See below. |
mapping |
URL, optional | A StructureMap or ConceptMap performing the conversion, where one exists. |
comment |
string, optional | How the alignment should be read, where that is not obvious. |
"mapsTo": [ { "system": "https://schema.org", "schema": "https://schema.org/Person", "mapping": "https://ours.example.org/mappings/user-to-schemaorg-person.json", "type": "one-to-one" }]Alignment types
Section titled “Alignment types”type |
What it tells a consumer |
|---|---|
one-to-one |
One instance here becomes one instance there, and back, without loss. |
one-to-many |
One instance here becomes several there. |
many-to-one |
Several instances here collapse into one there. |
partial |
The correspondence holds for some of the content and not all of it. Expect loss. |
This is the field a consumer reads before the data. Somebody about to transform
across a partial alignment learns that the result will be lossy here, rather
than from the gaps in the output, and one-to-one on a mapping that quietly
drops fields costs them more than an honest partial ever would. Use comment
to say what is lost.
Mapping documents
Section titled “Mapping documents”The document at mapping is a FHIR
StructureMap or
ConceptMap, written in
FHIR Mapping Language. OURS
does not define these and does not extend them. It points at them, so a FHIR
mapping engine can execute them without being told anything about OURS.
StructureMap
Section titled “StructureMap”A StructureMap converts between structures. It names the source and target schemas and gives the rules, element by element.
{ "resourceType": "StructureMap", "id": "user-to-schemaorg-person", "url": "https://ours.example.org/mappings/user-to-schemaorg-person.json", "version": "1.0.0", "name": "UserToSchemaOrgPerson", "title": "User to Schema.org Person mapping", "status": "active", "structure": [ { "url": "https://api.example.org/schemas/User.schema.json", "mode": "source" }, { "url": "https://schema.org/Person", "mode": "target" } ], "group": [ { "name": "UserToSchemaOrgPerson", "input": [ { "name": "src", "type": "User", "mode": "source" }, { "name": "tgt", "type": "Person", "mode": "target" } ], "rule": [ { "name": "mapFirstName", "source": [{ "context": "src", "element": "firstName" }], "target": [{ "context": "tgt", "element": "name.given", "transform": "copy" }] }, { "name": "mapLastName", "source": [{ "context": "src", "element": "lastName" }], "target": [{ "context": "tgt", "element": "name.family", "transform": "copy" }] } ] } ]}The structure URLs should be the ones the resources already use. A
StructureMap whose source is a schema no model points at is unreachable from
the ontology, whatever else is right about it.
ConceptMap
Section titled “ConceptMap”A ConceptMap converts between code lists, code by code.
{ "resourceType": "ConceptMap", "id": "invoice-status-to-fhir-value-set", "url": "https://ours.example.org/mappings/invoice-status-to-fhir-value-set.json", "version": "1.0.0", "name": "InvoiceStatusToFhirValueSet", "title": "Invoice Status to FHIR Value Set", "status": "active", "group": [ { "source": "https://api.example.org/codes/invoice-status", "target": "http://hl7.org/fhir/ValueSet/invoice-status", "element": [ { "code": "OPEN", "display": "Open", "target": [{ "code": "issued", "display": "Issued", "relationship": "equivalent" }] }, { "code": "PAID", "display": "Paid", "target": [{ "code": "balanced", "display": "Balanced", "relationship": "equivalent" }] }, { "code": "VOID", "display": "Void", "target": [{ "code": "cancelled", "display": "Cancelled", "relationship": "equivalent" }] } ], "unmapped": { "mode": "fixed", "code": "UNKNOWN", "display": "Unknown", "relationship": "not-related-to" } } ]}unmapped is worth filling in. It says what a consumer should do with a code
the map does not cover, which is otherwise the first thing to go wrong when you
add a code and forget to extend the map.
Where they are published
Section titled “Where they are published”Every mapping document a mapsTo references belongs in the document the
ontology’s mappings pointer resolves to, so a consumer can enumerate the
available transformations without walking every model first. If you have
written none yet, serve
an empty bundle there.