Skip to content

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.

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"
}
]
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.

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.

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.

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.

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.