CDA-FHIR-Maps (R4)
0.3.0 - DSTU 1

This page is part of the CDA-FHIR-Maps (R4) (v0.3.0: DSTU 1) based on FHIR R4. . For a full list of available versions, see the Directory of published versions

StructureMap: Bundle to CDA

map "http://fhir.ch/ig/cda-fhir-maps/StructureMap/BundleToCda" = "BundleToCda"


// CDA document
// 2020-01-16 Oliver Egger, copyright ahdis ag, Apache License
// CDA:  http://build.fhir.org/ig/ahdis/cda-core-2.0/branches/master/index.html
// FHIR: http://hl7.org/fhir/r4/

uses "http://hl7.org/fhir/cda/StructureDefinition/ClinicalDocument" alias ClinicalDocument as target
uses "http://hl7.org/fhir/cda/StructureDefinition/Author" alias Author as target
uses "http://hl7.org/fhir/cda/StructureDefinition/RecordTarget" alias RecordTarget as target
uses "http://hl7.org/fhir/cda/StructureDefinition/Custodian" alias Custodian as target
uses "http://hl7.org/fhir/cda/StructureDefinition/Organization" alias CdaOrganization as target
uses "http://hl7.org/fhir/cda/StructureDefinition/LegalAuthenticator" alias LegalAuthenticator as target
uses "http://hl7.org/fhir/cda/StructureDefinition/Section" alias CdaSection as target
uses "http://hl7.org/fhir/StructureDefinition/Bundle" alias Bundle as source
uses "http://hl7.org/fhir/StructureDefinition/Composition" alias Composition as source
uses "http://hl7.org/fhir/StructureDefinition/Practitioner" alias Practitioner as source
uses "http://hl7.org/fhir/StructureDefinition/Patient" alias Patient as source
uses "http://hl7.org/fhir/StructureDefinition/Organization" alias Organization as source
uses "http://hl7.org/fhir/StructureDefinition/BackboneElement" alias BackboneElement as source

imports "http://fhir.ch/ig/cda-fhir-maps/StructureMap/FhirToCdaTypes"

group BundleToCda(source bundle : Bundle, target cda : ClinicalDocument) {
  bundle ->  cda.recordTarget as recordTarget,  cda.author as author then BundleToClinicalDocument(bundle, recordTarget, author, cda) "bundle";
}

group BundleToClinicalDocument(source bundle : Bundle, target recordTarget : RecordTarget, target author : Author, target cda : ClinicalDocument) {
  bundle -> cda.typeId as typeId then {
    bundle -> typeId.root = '2.16.840.1.113883.1.3' "root";
    bundle -> typeId.extension = 'POCD_HD000040' "extension";
  } "typeId";
  bundle.identifier as identifier -> cda.id as id then IdentifierII(identifier, id) "id";
  bundle.timestamp as timestamp -> cda.effectiveTime as effectiveTime then InstantTS(timestamp, effectiveTime) "effectiveTime";
  bundle.entry as entry then {
    entry.resource as resource where $this.ofType(FHIR.Composition) then CompositionClinicalDocument(bundle, resource, recordTarget, author, cda);
  };
}

// _________________________ Section Level Templates _________________________
group SectionCdaSection(source bundle : Bundle, source section : BackboneElement, target cdasection : CdaSection) {
  section.extension as extension where $this.url = 'http://fhir.ch/ig/ch-core/StructureDefinition/ch-ext-epr-sectionid' -> cdasection.id as id then {
    extension.valueIdentifier as valueIdentifier then IdentifierII(valueIdentifier, id) "IdentifierII";
  } "valueIdentifier";
  section as section where $this.extension.where(url = 'http://fhir.ch/ig/ch-core/StructureDefinition/ch-ext-epr-sectionid').exists() = false -> cdasection.id as id then {
    bundle.identifier as identifier -> cdasection.id as id then IdentifierII(identifier, id) "setId";
  } "sectionid";
  section.code as code then {
    code.coding as coding where $this.system = 'http://loinc.org' -> cdasection.code as cdacode then CodingCE(coding, cdacode) "codingsection";
  };
  section.title as title ->  cdasection.title as cdatitle,  cdatitle.data = title;
  section.text as text then {
    text.div as div -> cdasection.text = div;
  };
}

// _________________________ Entry Level Templates   ________________________
// _________________________ Header Level Templates _________________________
group CompositionClinicalDocument(source bundle : Bundle, source composition : Composition, target recordTarget : RecordTarget, target author : Author, target cda : ClinicalDocument) {
  composition.type as type then {
    type.coding as coding where $this.system = 'http://loinc.org' -> cda.code as code share docCode then CodingCE(coding, code) "code";
  };
  composition.title as title -> cda.title as t then {
    title -> t.data = title "titleInner";
  };
  composition.confidentiality as conf -> cda.confidentialityCode as cdaconf then {
    conf -> cdaconf.code = conf "conf";
    conf -> cdaconf.codeSystem = '2.16.840.1.113883.5.25' "codeSystem";
  } "confidentialityCode";
  composition.language as language ->  cda.languageCode as languageCode,  languageCode.code = language "languageCode";
  bundle.entry as entry then {
    entry.fullUrl where ($this in %composition.subject.reference) and $this.startsWith('urn:uuid') then {
      entry.resource : Patient as patient then PatientRecordTarget(patient, bundle, recordTarget) "patient";
    } "uuid";
    entry.resource as patient where ('Patient' + '/' + $this.id) in %composition.subject.reference then PatientRecordTarget(patient, bundle, recordTarget) "patient";
    entry.fullUrl where ($this in %composition.custodian.reference) and $this.startsWith('urn:uuid') then {
      entry.resource : Organization as organization -> cda.custodian as custodian then OrganizationCustodian(organization, custodian) "custodian";
    } "uuid";
    entry.resource as organization where ('Organization' + '/' + $this.id) in %composition.custodian.reference -> cda.custodian as custodian then OrganizationCustodian(organization, custodian) "custodian";
    entry.fullUrl where ($this in %composition.author.reference) and $this.startsWith('urn:uuid') then {
      entry.resource : Practitioner as practitioner then PractitionerAuthor(bundle, composition, practitioner, author) "author";
    } "uuid";
    entry.resource as practitioner where ('Practitioner' + '/' + $this.id) in %composition.author.reference then PractitionerAuthor(bundle, composition, practitioner, author) "author";
    entry.fullUrl where ($this in %composition.attester.party.reference) and $this.startsWith('urn:uuid') then {
      entry.resource : Practitioner as practitioner -> cda.legalAuthenticator as legalAuthenticator then PractitionerLegalAuthenticator(bundle, composition, practitioner, legalAuthenticator) "legalAuthenticator";
    } "uuid";
    entry.resource as practitioner where ('Practitioner' + '/' + $this.id) in %composition.attester.party.reference -> cda.legalAuthenticator as legalAuthenticator then PractitionerLegalAuthenticator(bundle, composition, practitioner, legalAuthenticator) "legalAuthenticator";
  } "patient";
  // source.date -> tgt.effectiveTime "effectiveTime";
  composition.section as section where $this.code.exists() = false -> cda.component as component then {
    section -> component.contextConductionInd = true "contextConductionInd";
    section ->  component.structuredBody as structuredBody,  structuredBody.component as component,  component.section as cdasection then SectionCdaSection(bundle, section, cdasection) "cdasection";
  };
}

group PatientRecordTarget(source src : Patient, source bundle : Bundle, target tgt : RecordTarget) {
  src -> tgt.patientRole as patientRole then {
    src.identifier as identifier -> patientRole.id as id then IdentifierII(identifier, id);
    src.address as address -> patientRole.addr as ad then AddressAD(address, ad);
    src -> patientRole.patient as patient then {
      src.name as humanname -> patient.name as en then HumanNameEN(humanname, en);
      src.birthDate as birthDate -> patient.birthTime as birthTime then DateTS(birthDate, birthTime);
      src.gender as v log $this -> patient.administrativeGenderCode as adminGender then {
        v -> adminGender.code = translate(v, 'http://hl7.org/fhir/ConceptMap/cm-administrative-gender-v3', 'code') "gender";
        v -> adminGender.codeSystem = '2.16.840.1.113883.5.1' "codeSytem";
        v -> adminGender.codeSystemName = 'HL7 AdministrativeGender' "codeSystemName";
        v as v where $this = 'male' -> adminGender.displayName = 'Male' "male";
        v as v where $this = 'female' -> adminGender.displayName = 'Female' "female";
        v as v where $this = 'other' -> adminGender.displayName = 'Undifferentiated' "other";
      };
    } "patient";
    src.telecom as telecom -> patientRole.telecom as tel then ContactPointTEL(telecom, tel);
    src.managingOrganization as managingOrganization then {
      bundle.entry as entry then {
        entry.fullUrl where ($this in %managingOrganization.reference) and $this.startsWith('urn:uuid') -> patientRole.providerOrganization as providerOrganization then Organization2CdaOrganization(managingOrganization, providerOrganization) "providerOrganization";
        entry.resource as organization where ('Organization' + '/' + $this.id) in %managingOrganization.reference -> patientRole.providerOrganization as providerOrganization then Organization2CdaOrganization(managingOrganization, providerOrganization) "providerOrganization";
      };
    };
  } "patientRole";
}

group PractitionerAuthor(source bundle : Bundle, source composition : Composition, source src : Practitioner, target tgt : Author) {
  composition.author as srcauthor then {
    srcauthor.extension as extensionTime where $this.url = 'http://fhir.ch/ig/ch-core/StructureDefinition/ch-ext-epr-time' then {
      extensionTime.valueDateTime as valueDateTime -> tgt.time as time then DateTimeTS(valueDateTime, time) "DateTime";
    } "extensionTime";
  } "srcAuthor";
  bundle.timestamp as valueDateTime where composition.author.extension.where(url = 'http://fhir.ch/ig/ch-core/StructureDefinition/ch-ext-epr-time').empty() -> tgt.time as time then DateTimeTS(valueDateTime, time) "DateTimeBundle";
  src -> tgt.assignedAuthor as assignedAuthor then {
    src.identifier as identifier -> assignedAuthor.id as id then IdentifierII(identifier, id) "id";
    src.telecom first as telecom -> assignedAuthor.telecom as tel then ContactPointTEL(telecom, tel);
    src.address as address -> assignedAuthor.addr as ad then AddressAD(address, ad);
    src.name as name ->  assignedAuthor.assignedPerson as assignedPerson,  assignedPerson.name as en then HumanNameEN(name, en);
    bundle.entry as entry then {
      entry.fullUrl where ($this in %composition.author.reference) and $this.startsWith('urn:uuid') then {
        entry.resource : Organization as organization -> assignedAuthor.representedOrganization as cdaorganization then Organization2CdaOrganization(organization, cdaorganization) "organization";
      } "uuid";
      entry.resource as organization where ('Organization' + '/' + $this.id) in %composition.author.reference -> assignedAuthor.representedOrganization as cdaorganization then Organization2CdaOrganization(organization, cdaorganization) "organization";
    } "patient";
  } "assignedAuthor";
}

group OrganizationCustodian(source src : Organization, target tgt : Custodian) {
  src -> tgt.assignedCustodian as assignedCustodian then {
    src -> assignedCustodian.representedCustodianOrganization as representedCustodianOrganization then Organization2CdaOrganizationCustodian(src, representedCustodianOrganization) "representedCustodianOrganization";
  } "assignedCustodian";
}

group Organization2CdaOrganizationCustodian(source src : Organization, target tgt : CdaOrganization) {
  src.identifier as identifier -> tgt.id as id then IdentifierII(identifier, id) "id";
  src.name as name ->  tgt.name as orgname,  orgname.other = name;
  src.address as address -> tgt.addr as ad then AddressAD(address, ad);
  // target telecom is 0..1
  src.telecom first as telecom -> tgt.telecom as tel then ContactPointTEL(telecom, tel);
}

group Organization2CdaOrganization(source src : Organization, target tgt : CdaOrganization) {
  src.identifier as identifier -> tgt.id as id then IdentifierII(identifier, id) "id";
  src.name as name ->  tgt.name as orgname,  orgname.other = name;
  src.address as address -> tgt.addr as ad then AddressAD(address, ad);
  src.telecom as telecom -> tgt.telecom as tel then ContactPointTEL(telecom, tel);
}

group PractitionerLegalAuthenticator(source bundle : Bundle, source composition : Composition, source src : Practitioner, target tgt : LegalAuthenticator) {
  src ->  tgt.templateId as templateId,  templateId.root = '2.16.756.5.30.1.1.10.2.5' "templateId";
  composition.attester as attester then {
    attester.time as srcTime -> tgt.time as time then InstantTS(srcTime, time) "timestamp";
  } "time";
  // src -> tgt.signatureCode = 'S' "S";
  src ->  tgt.signatureCode as signatureCode,  signatureCode.code = 'S' "signature";
  src -> tgt.assignedEntity as assignedEntity then {
    src.identifier as identifier -> assignedEntity.id as id then IdentifierII(identifier, id);
    src.name as name ->  assignedEntity.assignedPerson as assignedPerson,  assignedPerson.name as en then HumanNameEN(name, en);
  } "assignedEntity";
}