cda2fhir is a Java library to transform HL7 CDA R2 instances to HL7 FHIR resources. More specifically, cda2fhir enables automatic transformation of Consolidated CDA (C-CDA) Release 2.1 compliant document instances to the corresponding FHIR DSTU2 resources, wherever possible implementing the U.S. Data Access Framework (DAF) FHIR Implementation Guide. For this purpose, cda2fhir provides extensible document transformers, resource transformers, data type transformers and value set transformers. The current implementation provides a document transformer for Continuity of Care Document (CCD), but further document transformers, e.g. for Discharge Summary or Referral Note, can be easily introduced by reusing the already existing section and entry transformers. Although the cda2fhir library expects C-CDA R2.1 compliant documents/entries, it has been tested as well with several older document instances compliant with earlier releases of C-CDA. The official HL7 FHIR Validator is also integrated for automated validation of the generated FHIR resources.
All the mappings implemented between CDA artifacts and FHIR resources, data types and value sets are documented in this sheet: C-CDA CCD to FHIR DAF Mapping
Model Driven Health Tools (MDHT) is used for CDA manipulation and HAPI is used for FHIR manipulation. The current implementation produces DSTU2 resources. We are planning to cover STU3 resources as well, after the specification becomes official.
Apache Maven is required to build cda2fhir. Please visit http://maven.apache.org/ in order to install Maven on your system.
Under the root directory of the cda2fhir project run the following:
$ cda2fhir> mvn install
In order to make a clean install run the following:
$ cda2fhir> mvn clean install
These will build the cda2fhir library and also run a number of test cases, which will transform some C-CDA Continuity of Care Document (CCD) instances, and some manually crafted CDA artifacts (e.g. entry class instances) and datatype instances to corresponding FHIR resources, wherever possible using the DAF profile.
// Load MDHT CDA packages. Otherwise ContinuityOfCareDocument and similar documents will not be recognised.
// This has to be called before loading the document; otherwise will have no effect.
CDAUtil.loadPackages();
// Read a Continuity of Care Document (CCD) instance, which is the official sample CCD instance
// distributed with C-CDA 2.1 specs, with a few extensions for having a more complete document
FileInputStream fis = new FileInputStream("src/test/resources/C-CDA_R2-1_CCD.xml");
ClinicalDocument cda = CDAUtil.load(fis);
// Init an object of CCDTransformerImpl class, which implements the generic ICDATransformer interface.
// FHIR resource id generator can be either an incremental counter, or a UUID generator.
// The default is UUID; here it is set as COUNTER.
ICDATransformer ccdTransformer = new CCDTransformerImpl(IdGeneratorEnum.COUNTER);
// By default, FHIR DSTU2 resources are generated by setting the appropriate DAF profile URLs
// in meta.profile attribute of resources. This is configurable through the statically (i.e. globally)
// managed Config class, and can be turned on or off.
Config.setGenerateDafProfileMetadata(true);
// By default, html formatted narratives are generated in text.div attributes of FHIR DSTU2 resources,
// thanks to the automated narrative generation capability of HAPI that is enabled via thymeleaf library.
// This is configurable through the statically managed Config class, and can be turned on or off.
Config.setGenerateNarrative(true);
// Finally, the CCD document instance is transformed to a FHIR Bundle, where the first entry is
// the Composition corresponding to the ClinicalDocument, and further entries are the ones referenced
// from the Composition.
Bundle bundle = ccdTransformer.transformDocument(cda);
// Through HAPI library, the Bundle can easily be printed in JSON or XML format.
FHIRUtil.printJSON(bundle, "src/test/resources/output/C-CDA_R2-1_CCD-w-daf.json");
Further code examples can be found in CCDTransformerTest class. The outcome of the above transformation operation for the CCD instance available in the C-CDA 2.1 specification is available here: https://github.com/srdc/cda2fhir/blob/master/src/test/resources/C-CDA_R2-1_CCD-w-daf.json
// Init an object of ResourceTransformerImpl class, which implements the IResourceTransformer
// interface. When instantiated separately from the CDATransformer context, FHIR resources are
// generated with UUID ids, and a default patient reference is added as "Patient/0"
IResourceTransformer resTransformer = new ResourceTransformerImpl();
// Configuration of DAF profile URL creation in meta.profile and narrative generation in text.div is
// again configurable through the statically managed Config class.
Config.setGenerateDafProfileMetadata(true);
Config.setGenerateNarrative(false);
// Assume we already have a CCD instance in the ccd object below (skipping CDA artifact creation from scratch)
// Traverse all the sections of the CCD instance
for(Section cdaSec: ccd.getSections()) {
// Transform a CDA section to a FHIR Composition.Section backbone resource
Composition.Section fhirSec = resTransformer.tSection2Section(cdaSec);
// if a CDA section is instance of a Family History Section (as identified through its templateId)
if(cdaSec instanceof FamilyHistorySection) {
// cast the section to FamilyHistorySection
FamilyHistorySection famSec = (FamilyHistorySection) cdaSec;
// traverse the Family History Organizers within the Family History Section
for(FamilyHistoryOrganizer fhOrganizer : famSec.getFamilyHistories()) {
// Transform each C-CDA FamilyHistoryOrganizer instance to FHIR (DAF) FamilyMemberHistory instance
FamilyMemberHistory fmh = resTransformer.tFamilyHistoryOrganizer2FamilyMemberHistory(fhOrganizer);
}
}
}
// Again, any FHIR resource can be printed through FHIRUtil methods.
FHIRUtil.printXML(fmh, "src/test/resources/output/family-member-history.xml");
It should be noted that most of the time, IResourceTransformer methods return a FHIR Bundle composed of a few FHIR resources, instead of a single FHIR resource as in the example above. For example, tProblemObservation2Condition method returns a Bundle that contains the corresponding Condition as the first entry, which can also include other referenced resources such as Encounter, Practitioner.
Further examples can be found in ResourceTransformerTest class and CCDTransformerImpl class.
We have also integrated the official HL7 FHIR Validator, although in a bit ugly way since this validator is not available in any Maven repo. We have implemented a wrapper interface and a class on top of this validator: IValidator and ValidatorImpl. A resource can be validated individually, or a Bundle containing several resources as in the case of CDA transformation outcome can be validated at once. When (DAF) profile metadata is provided within the resources' meta.profile attribute, validation takes into account this profile as well. Validation outcome is provided as HTML within an OutputStream.
// Init an object of ValidatorImpl class, which implements the IValidator interface.
IValidator validator = new ValidatorImpl();
// Assume we already have a Bundle object to be validated at hand. Call the validateBundle method
// of the validator and get the validation outcome as HTML in a ByteArrayOutputStream.
ByteArrayOutputStream valOutcomeOs = (ByteArrayOutputStream) validator.validateBundle(bundle);
// The HTML can be printed to a file.
FileOutputStream fos = new FileOutputStream(new File("src/test/resources/output/validation-result-w-profile-for-C-CDA_R2-1_CCD.html"));
valOutcomeOs.writeTo(fos);
// Close the streams
valOutcomeOs.close();
fos.close();
Further examples can be found in ValidatorTest class. Some of the tests in this class are ignored, as validating takes some time, especially due to external Terminology Server access dependency. But they do work, users can enable them.
Unfortunately it is not easy to find up and running DSTU2 terminology servers all the time, hence this test can fail when none of the terminology servers configured in Config is accessible. In this case, if you happen to know an accessible DSTU2 terminology server, you can either update Config or set via the setTerminologyServer method of the validator. If you cannot find a running terminology server, then you can just ignore the validator tests.
This research has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement No 689181, C3-Cloud Project (A Federated Collaborative Care Cure Cloud Architecture for Addressing the Needs of Multi-morbidity and Managing Poly-pharmacy).
This research has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement No 689444, POWER2DM Project (Predictive model-based decision support for diabetes patient empowerment).